Offset a curve with a direction point

I offset curves with direction points, but this method makes two different results as shown in the example.

    double tol = RhinoDoc.ActiveDoc.ModelAbsoluteTolerance;
    A = curve.Offset(point, Vector3d.ZAxis, distance, tol, CurveOffsetCornerStyle.Sharp);

Two rectangles are made with a script, so they’re exactly the same curves. The left rectangle works, but the right side rectangle offset doesn’t work.
If I use center points of these rectangles or make the offset distance value smaller, it offsets both rectangles correctly. However, I want to make the offset work with any direction point inside closed planar curves as part of different scripts. Is this a bug, or am I missing anything in this offset method to make the result correct?
I’m attaching the example file. Curves and points are internalised in Grasshopper, but the Rhino file unit should be in meters to see this issue. offset.gh (8.9 KB)

I usually check after the offset method if the offset curve contains the point.

if (offsetCurve.Contains(pointInside, plane, offset) != PointContainment.Outside)
 {
        // if the offset is successful then continue ....
 }
 else
 {
        //search for the new direction point 
 }

the trick is to find the point inside the curve!

Thank you, @torabiarchitect. I made sure the direction point is always inside the curve to offset. Are you saying that the direction point should be inside of the resulted offset curve? I thought that the direction point is inside of the original curve (rectangles colored in red in my example) versus its outside to decide the direction to offset.

Yes, after the offset it may happen that resulted curve does not contain the point . This is due to the fact that point is not distanced sufficiently larger than the offset amount from the original curve . So if you are selecting the direction point randomly inside the curve then it is better to check it the offset is created as you expected.

I’m not sure if it will resolve the issue. In my example posted here, the direction point used in the right side is actually inside of the resulted offset curve. If your suggested logic is applied, this wrong offset would pass the point containment test. The correct offset result, shown in the left side of my example, actually wouldn’t pass the point containment test, so the script will find the next direction point despite getting the correct offset curve. I kind of resolved the issue temporarily using the following logic:

  1. Check if the first offset curve direction is the same as the original curve, valid, not null, and its count is one.
  2. If the offset curve doesn’t pass the step 1, find the centroid of the curve and check if the centroid is inside of the original curve.
  3. Offset the curve one more time using the centroid as the direction point.

Because there’s always a chance the centroid is outside of the curve, there should be an iterative process to find the next direction point to offset. @DavidRutten Is this a bug or am I misunderstanding the concept of the direction point? I’m not clear why the offset with a direction point makes two different results with the same curve.

Your point is not considered inside the curve given the offset value, you need to pass the offset value to contain() method as threshold, this will assume a circle around the point with the radius of the offset value which must be entirely inside the curve
As for the method to find a point inside the curve I do have my own recursive method which I will post when I am back to work

Hi,
here the code for finding point inside curve which can lead to a proper offset (if possible)
I have also attached a grasshopper def. You probbaly need to rework this as per your needs, for example if you deal with very narrow shape maybe it is better to implement the while(){} loop instead of the recursion just to avoid stack over flow…
offset direction.gh (9.1 KB)

        /// <summary>
        /// search for a point inside the curve. return true if the point is found.
        /// </summary>
        /// <param name="curve"></param>
        /// <param name="box">The counding box of the curve</param>
        /// <param name="tolerance">the maximum distance of the point to the curve</param>
        /// <param name="pointInside"></param>
        /// <returns></returns>
        public static bool FindPointInside(this Curve curve, Box box, double tolerance, out Point3d pointInside, IEnumerable<Curve> constrains = null,IEnumerable<Point3d> points=null)
        {
            if (
                curve.Contains(box.Center, box.Plane, tolerance) == PointContainment.Inside
                &&
                (constrains == null || !constrains.Any() || constrains.All(c => c.Contains(box.Center, box.Plane, tolerance) == PointContainment.Outside))
                &&
                (points == null || !points.Any() || points.All(p => !box.Contains(p)))
                )
            {
                pointInside = box.Center;
                return true;
            }
            else
            {
                
               
                 
                double x = box.X.Length / 4.0;
                double y = box.Y.Length / 4.0;
                
                
                box.Inflate(-x, -y, 0);
                if (box.X.Length < tolerance/4.0 || box.Y.Length < tolerance/4.0)
                {
                    pointInside = Point3d.Unset;
                    return false;
                }
                //move to the corner
                box.Transform(
                    Transform.Translation(-box.Plane.XAxis * box.X.Length / 2 - box.Plane.YAxis * box.Y.Length / 2 )
                    );
                if (FindPointInside(curve, box, tolerance, out pointInside,constrains, points))
                    return true;
                // move to right
                box.Transform(Transform.Translation(box.Plane.XAxis * box.X.Length ));                
                if (FindPointInside(curve, box, tolerance, out pointInside,constrains, points))
                    return true;
                // move up
                box.Transform(Transform.Translation(box.Plane.YAxis * box.Y.Length));
                if (FindPointInside(curve, box, tolerance, out pointInside,constrains, points))
                    return true;
                // move left
                box.Transform(Transform.Translation(-box.Plane.XAxis * box.X.Length ));
                if (FindPointInside(curve, box, tolerance, out pointInside,constrains, points))
                    return true;
                pointInside = Point3d.Unset;
                return false;
            }

        }
1 Like

@torabiarchitect Thank you very much for sharing your code. I had no idea that the circle from the direction point with the offset value radius needs to be inside the curve.