BUG (?) ClosedPlanarCurve - Plane Direction - Extrusion


PlanarClosedCurve-Plane-Error.3dm (46.0 KB)

I’m generating some Curves in a c# / RhinoCommon Plug-in.
The curves are used for Extrusion.Create
I can t get the correct / expected side for the extrusion, and it seams it s the fault of the return Plane of the Curve…

I always thought, that a closed planar Curve is CCW orientated in it s (corresponding) Plane, the Plane returned by TryGetPlane.
Is this wrong ?
or is this a Bug.

If a planar Curve has a random Plane Orientation - then Extrusion.Create does not make sense - as it uses the Plane - and it will afford to correct the extruded direction / side.

Please:

  • should the Plane of a closed Planar Curve always be CCW ? yes / no ?
  • if No
    • please update the documentation of TryGetPlane
    • please add an overload to Extrusion.Create that allows a correct direction
  • if YES → this is a bug

thanks
kind regards - tom

Hi @Tom_P,

With the exception of an ArcCurve, which is comprised of a plane and other properties, the plane of a Curve is computed as needed.

When computing a curve’s plane, the starting point is used for the plane origin, and the tangent direction at the starting point is used for the the plane’s x-axis. The plane’s y-axis is computed by evaluating curve spans.

So to answer your question, yes, the plane of a closed planar curve is always counter-clockwise to it’s computed plane, being that the plane is computed from the curve itself.

Of course, what appears to be counter-clockwise in one view projection can be considered clockwise in another.

I’ve attached a simple Python script to extrude the curves in your model.

test_extrude.py (800 Bytes)

– Dale

thanks

many thanks for your fast answer and your effort.

… what does this mean in detail. (my pure english ? sorry)

look s like a bug

the result of script:

but that does not seam right with “my” curves.
they both have the same shape and orientation, only different starting point.
so the result is an extrusion in two different directions.

ok I added a few lines of code to your test-Scripts (thanks) and this shows my missunderstanding:

Extrusion_create_test_02_orientation.py (962 Bytes)

added

if curve:
        extrusion = Rhino.Geometry.Extrusion.Create(curve, 5.0, True)
        sc.doc.Objects.AddExtrusion(extrusion)
        success, plane = curve.TryGetPlane(0.001);
        if success:
            orientation = curve.ClosedCurveOrientation(plane)
            Rhino.RhinoApp.WriteLine(str(orientation))

add it will once print
clockwise
, and once pring
counterClockWise

:thinking: :cold_face:

thanks for having a second look at this issue.

kind regards -

workaround

my workaround in my c# plug-in

static public Brep CreateExtrusion(Curve crv, double zMin, double zMax, bool cap, double tolerance = 0.001)
        {
            ///
            double height = zMax - zMin;
            Plane pl;
            if (!crv.TryGetPlane(out pl, tolerance))
                return null;
            Extrusion extr = Extrusion.Create(crv, height, cap);
            Brep brep = extr.ToBrep();
            // check plane and Curve orientation
            CurveOrientation orientation = crv.ClosedCurveOrientation(pl);
            Vector3d move = new Vector3d();
            if (orientation == CurveOrientation.Clockwise)
            {
                pl = FlipPlane(pl);
                move += pl.Normal * height;
            }
            move += pl.Normal * zMin;
            Transform xform = Transform.Translation(move);
            brep.Transform(xform);
            return brep;
        }
        /// <summary>
        /// keep origin, keep x-axis, reverse normal and y-axis
        /// </summary>
        /// <param name="plane"></param>
        static public Plane FlipPlane(Plane plane)
        {
            Vector3d z = plane.Normal;
            z.Reverse();
            Vector3d y = Vector3d.CrossProduct(z, plane.XAxis);
            return new Plane(plane.Origin, plane.XAxis, y);
        }

general question about struct Plane

by the way - can i be sure that all constructors of
new Plane (...)
always ensure a proper unit-vector, right hand rule, 90-degree setting ?
(for a my_plane.IsValid == true )

@dale
may I ask to have a second look at this - thanks a lot.

can somebody please have a look at this ?
@Gijs - who can answer my concerns ?

if it is a bug it is quite fundamental.
if I am doing something wrong I have to fix it before I send my current project to the customer.

thanks a lot. kind regards - tom

I don’t know what your exact issue is. You are showing curves with different orientation, so planes and extrusions will be different. How are you creating the curves that they are sometimes CW and sometimes CCW?

thanks @Gijs
which version of rhino did you use to test ?

my problem (Mac Version 7 (7.30.23130.11002, 2023-05-10))
one of the curves returns a Plane (Curve.TryGetPlane) but within this plane the curve is CW instead of CCW - and this results in wrong direction of Extrusion.
what results are you getting when running above .py script.
( I get clockwise / counterClockwise - but expected counterClockWise twice)

?

_Dir shows same orientation - or is my brain interpreting the arrows wrong ?
:eyeglasses: :nerd_face:

Sorry, I was not paying close enough attention, hold on, currently trying something out

Hi Tom, my best guess is that it is not so much a bug, but rather a limitation based on how the plane is being calculated. If I load it in GH, I see that the plane is flipping there as well. So I’d say, you need a workaround for this.

ok but the plane of a planar Curve is used for further steps - for example for the Extrusion.Create function. (not allowing a Dir / Plane parameter)

And Dale claimed above:

which seams not the case - and will result in quite unexpected Extrusion directions…

Especially as Curve orientations seams quite essential in nurbs-context

for my case i found a workarround - but I am sure other developers will stumble on this as well…
and it is quite a hidden special case i think

I’ve logged an issue for the seam issue.

https://mcneel.myjetbrains.com/youtrack/issue/RH-75060

– Dale

1 Like

Thanks

A planar curve does not determine the orientation of the plane.
image
orient.3dm (51.0 KB)
Only if the curve is closed and simple (no self intersections) does it uniquely determine an orientation. If it satisfies these conditions one can use curve.ClosedCurveOrientation(plane) to get the orientation with respect to the plane.

I don’t think all these steps should be included in curve.IsPlanar(plane) because they are going significantly beyond just determining if a curve is planar.

dear @GregArden
thanks for digging into this topic. It s clear that a self-intersecting curve is a special case…
What about the curves I posted at the beginning / top of this topic ?
My main concern is, that it looks like Extrusion.Create is using the orientation of the plane, given by the curve, to decide the extrusion direction - and it looks like there is some inconsistency (or bug).

kind regards - tom

Extrusion.Create takes a plane and a curve, each have their own orientation. According to the documentation of Extrusion.Create, I would expect the direction of the extrusion is relative to the plane orientation, i.e. it is independent of the curve orientation. Is this what happens? So the user must understand the plane orientation to get predictable results.

Geometry.Curve.TryGetPlane (which is basically ON_Curve::IsPlanar( ON_Plane*, double) in c++) does not guarantee an orientation of the plane. So you need to decide on the orientation before you make an extrusion. If you want to make that decision based on the orientation of the simple closed curve use Geometry.Curve.ClosedCurveOrientation(plane) to decide.

this is not exposed to rhinocommon in that way - only a Curve, height, cap

https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.extrusion/create

static Extrusion Create (
   Curve planarCurve, 
   Double height, 
   Boolean cap
)

see my workaround above.
I more or less do what you suggest.

thanks for your explanations. - kind regards -tom

https://mcneel.myjetbrains.com/youtrack/issue/RH-75208

Tom,
I see that you’re right the RhinoCommon method Extrusion.Create only takes a curve. So I changed ON_Curve::IsPlanar(plane, tol) to get the compatible orientation for a simple planar closed curve. Now you can get predictable behavior from Extrusion.Create in this case.

This is even more of a problem for open planar curves since there is no cannonical orientation of the plane and as you point out the interpretation of the height parameter depends on the orientation of the plane. In this case I think Dale’s youtrack https://mcneel.myjetbrains.com/youtrack/issue/RH-75208 is the right solution.

this is, what I would expect:

most cases where developers will use Extrusion.Create also the curve was created by code and therefor this would be most robust, it is not a big deal to code the correct orientation.

And Yes Dale 's youtrack is the right solution - maybe Extrusion.Create without a plane / direction parameter is “promising” to much.

thanks again. kind regards -tom