Offset madness

We know the offset curve function in Rhino is weak, but the GH function seems to be much worse…

In the .gh below, which references 5 closed planar polylines in the .3dm file, I want to offset the curves to the outside. As you can never know which side a closed curve will offset (depending on the curve direction CW or CCW) I run both offsets and then choose the outside. The “outside” curve can be chosen by a variety of methods, I used closed curve containment on the offset curve start point in this example and used that to filter (that incidentally produced another problem, see below),

As the .gh is saved with an offset of 0.4, everything looks fine. Now, move the offset slider to 0.7 or above. Boom, the leftmost profile no longer offsets correctly to the outside (due to one area being too small) and everything goes pear-shaped. Try the native Offset command in Rhino with a value of 0.7 or above and it works fine however.

As for the secondary problem, set the offset slider at 0.5. The right most profile then gets two extrusions - because both the inside and outside offset curve start points are determined to be ‘outside’ (value=0) by the containment component. Don’t know why that is happening.

The Rhino file is a V6 file but I tested in V7 and it is the same.

What is disappointing is the most CAM programs know how to offset 2D profiles perfectly - this since the 90’s when I started using them - that is their essential function otherwise pocketing, profiling, cutter radius compensation and the like would be impossible. If they have been able to do it 30 years ago already, why can’t Rhino?

I can work around this all sorts of ways, but it’s sad to have to explain to people “Well, uhhh, yeah… this is just something that doesn’t work reliably in Rhino, sorry…”

OffsetProblem.3dm (341.9 KB)
BadOffset.gh (12.8 KB)

4 Likes

i have noticed that too when i tried to offset voronoi patterns and it behaved terribly in GH. i think i used then some other plugin which could handle this most trivial function. This is what is undermining rhino. I would go and persuade my whole company to switch from cad to rhino but these i would look like stupid if someone started asking why it cant make proper offsets. It doesnot look robust and reliable. The samee thing goes with offsetsrf. It fails even for simple kind of geometries.

If you compute polygon plane by average of each segment cross products it at least offset in one direction not whatever.

But the offset component fails after some value, because it cannot handle self intersections.
Probably the best option is Clipper if you do not mind numeric rounding.

Yup offset and mesh booleans something that was not solved for years…
I wish some of those computer graphics guys could make plugins for rhino:

Cross product of which two vectors? Segment tangent vector and…?

Yeah, I’m aware of Clipper. My basic complaint here is that this should just work in Rhino/GH without having to look for outside solutions or complex workarounds.

Actually they have for the most part as I understand, and quite awhile ago - notably by Claude Vuattoux, originator of Rhino Terrain. But it hasn’t made it into Rhino.

1 Like

The normal of plane is computed like this:

public static Vector3d AverageNormal(this Polyline p)
        {

            int len = p.Count - 1;
            Vector3d vector3d = new Vector3d();

            for (int i = 0; i <= len - 1; i++)
            {
                int num = ((i - 1) + len) % len;
                int item1 = (checked(i + 1) + len) % len;
                Point3d point3d = p[num];
                Point3d point3d1 = p[item1];
                Point3d item2 = p[i];
                vector3d = vector3d + Vector3d.CrossProduct(new Vector3d(item2 - point3d), new Vector3d(point3d1 - item2));
            }

            if (vector3d.X == 0 & vector3d.Y == 0 & vector3d.Z == 0)
                vector3d.Unitize();

            return vector3d;
        }

I totally agree, these issues should not be placed just to the issue tracker and forgotten, but someone should do it.
I am relatively young user, but nothing changed for 8 years I am using those offsets.

Yeah, I’m aware of Clipper. My basic complaint here is that this should just work in Rhino/GH without having to look for outside solutions or complex workarounds.

2 Likes

So if I understood correctly that is the average of the all the cross products of the tangent vector of each segment with the tangent vector of the next segment? I don’t really read C#.

Exactly.

I guess in my case as these are all closed planar curves I could just use Curve.ClosedCurveOrientation() and flip as necessary. This method isn’t in GH as a component, so I guess I could also just use the Planar component and check the normal direction/flip as necessary.

Yes, and someone could add this option to component itself, it is probably written ages ago. I wish that instead of creating those 3rd party plugins, somebody would let us correct existing components for very specific cases like this one.

Away from my computer right now but I uses a few different workflows in grasshopper for non-planar curve offsets that help in different circumstances.

  1. use a curves vertices + plane fit to create the plane input for the offset component.
  2. use minimal bounding bounding box (the fastest one from the thread you contributed to a while back) to create the plane input for the offset component.
  3. for curves on surfaces, project the curve to the plane created using minimal bounding box, and then offset, then project back.
  4. for all of the above, with multiple curves, use the Sasquatch “flip clockwise” component up front, or make a native cluster that does the same thing.

And yes, it is mindboggling and annoying that RhinoCAM, made by a tiny company in an office park, can do perfect cutter compensation offsets and Rhino can’t. Maybe McNeel and MecSoft can work out some kind of a fair trade of code? Please?

1 Like

Offset work fine in python Rhino.Geometry.Curve.Offset

Offset_new.gh (11.2 KB)

1 Like

Yep, Rhino native Offset works fine as well. That the Python script works is all the more surprising as GH is supposed to be based on RhinoCommon. So why does the Offset Curve component not behave correctly when the Python script does?

The main issue is probably this - Curve.Offset() has two overloads. One - the one used in @anon39580149 's script needs a point to determine the offset side.

https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_Curve_Offset_1.htm

The other does not, and uses a plane and probably the curve direction to determine the offset side. The GH component probably uses this version.

https://developer.rhino3d.com/api/RhinoCommon/html/M_Rhino_Geometry_Curve_Offset.htm

The disadvantage of having to provide a point to determine the offset side is that it too can be unreliable. The use of the curve area centroid as a direction for an inside offset may be OK for relatively regular, convex closed curves, but it is not guaranteed to really fall on the inside - it’s easy enough to imagine a curve shape where it doesn’t. For the outside direction point, again, normally a corner of a scaled bounding box should guarantee success, but in my experience depending on the curve, the position of the box and which corner is used as a reference, it can also fail.

The non-point method would ideally give you a good result - which might be either inside or outside depending on the curve direction. Inverting the offset value would then ideally give you the other side and from there the desired result could be chosen. But unfortunately neither is reliable.

1 Like

The script work for closed curves which need point inside or outside, opened curve need to change direction to negative or positive.
Point is not necessary but it’s better if we want for example offset voronoi cells

Can you give an example? why it fail if you scale the bounding box by 100 or 10000?
or you can simply scale the curve and choose a point from it

Hmm, what happened to the middle figure in your image?

I’ve had quite a number in the past which have been submitted, bit I don’t have anything specific on hand at the moment. The critical problem is the relationship of the point chosen and the curve seam and the arrangement of the segments. Sometimes it just fails. The typical cases are ‘pinch points’ where the self intersecting parts need to be removed, or where an inside offset might end up as two or more curves - in which case you often get only one of the two.

This happen when we don’t use the point to determine the direction.


I try to find a solution maybe with mesh interior edges?

My ‘point’ exactly.

I use center of extracted face mesh to find a point inside the closed curve, i think this work whatever the index of the face

Offset_new_2.gh (15.2 KB)

1 Like

OK, here’s a quick and very simple example that took me 2 minutes to create. Try it with either your Offset_new or Offset_new_2 definitions, any offset value of 2.5 or larger. Fun results…

OffsetFailExample.3dm (310.4 KB)

Obviously this is an ‘extreme’ case just to prove my point, but basically to show that the ‘point’ method of determining the offset direction isn’t 100% reliable either. The problem isn’t really in how the direction is determined, it is in the geometrical calculation of the offset function itself. This is not a new issue, it only took me two minutes to create the example because I have a lot of experience with its failures.

Unfortunately, I don’t have any more time on this, I have a class I need to start teaching on Tuesday and this is taking away from my prep time…

All available offset methods give different results, maybe the one used for Breps, they can used its code for curves