Fastest way to check if two closed curves overlap?

Greetings,

I use rs.CurveBooleanUnion and check the areas, but this method is very slow. Is there a faster way?

Here’s my script. It takes first one curve, second a list of curves, and checks for overlaps between the first curve and the curves in the list. Returns those that overlap and the ones that don’t in separate lists.

def shape_filter_intersect(curve_bound,shapes):
    area1 = rs.Area(curve_bound)
    false_shapes = []
    true_shapes = []

    for shape in shapes:
        area2 = rs.Area(shape)
        areasum = area1 + area2
        areasum=float('%.3f'%(areasum)) #ROUND TO 3 DECIMALS

        crvbool = rs.CurveBooleanUnion([curve_bound,shape])

        if len(crvbool) != 1:
            rs.DeleteObjects(crvbool)
            false_shapes.append(shape)
            
    
        else:
            areabool = rs.Area(crvbool)
            areabool=float('%.3f'%(areabool)) #ROUND TO 3 DECIMALS

            if areabool != areasum: # if not equal
                rs.DeleteObjects(crvbool)
                false_shapes.append(shape)
                
            else:
                rs.DeleteObjects(crvbool)
                true_shapes.append(shape)
    return false_shapes, true_shapes

(1)
Rhinocommon has
https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.curve/planarclosedcurverelationship

https://developer.rhino3d.com/api/rhinocommon/rhino.geometry.curve/planarcurvecollision

(2)
skip the unneeded area calculation (put it in the else part of the condition).

(3)
there might be some performance tricks using polylines within tolerances or a rough version first … depends a bit on the context, amount of hits, complexity of curves and so on.

(4)
are you turning redraw off ?

give a feedback if above already helps. happy coding - kind regards -tom

Hi @Tom_P ,

From what I read in the documentation, PlanarClosedCurveRelationship and PlanarCurveCollision are used to check for intersections not for overlaping. So they don’t help.

i need to filter those two situations:

Here is an old script of mine that might help.

DetectOverlaps.py (1.2 KB)

It might be slow with large numbers of curves.

i’m thinking… check if intersect between curve1 and curv2 returns a curve, check if curve2 is inside of curve1…

Your definition of overlaps does not correspond to the curves themselves, but rather the regions they enclose. On the left, the curves themselves intersect with no overlap, and on the right they intersect with an overlap.

If you need to check for region overlaps, you will likely need to work with surfaces or volumes made from your curves. For example on the left, a BooleanIntersection between volumes extruded from the curves will have a non-zero volume. On the right the volume will either fail to calculate or be zero.

@Helvetosaur , you were right. my definition of overlap was not correct. Two curves overlap when they have a sub-segment overlapping. Here’s the new diagram.

Below, new code. I used Rhino.Geometry.Intersect.Intersection.CurveCurve() and Rhino.Geometry.PointContainment.Inside() to chek for overlap and inclusion.

def shape_filter_intersect2(curve_bound,shapes):
    tol = 1
    plane = Rhino.Geometry.Plane.WorldXY

    false_shapes = []
    true_shapes = []

    curve_bound = rs.coercecurve(curve_bound)

    for shape in shapes:
        shape = rs.coercecurve(shape)
        events = Rhino.Geometry.Intersect.Intersection.CurveCurve(curve_bound, shape, tol, tol)

        has_overlap = False

        if events:
            for event in events:
                if event.IsOverlap:
                    has_overlap = True
                    break

        if has_overlap:
            result = shape.TryGetPolyline()

            if result and result[0]:  # success
                polyline = result[1]
                has_strictly_inside_point = False

                for pt in polyline:
                    containment = curve_bound.Contains(pt, plane, tol)
                    if containment == Rhino.Geometry.PointContainment.Inside:
                        has_strictly_inside_point = True
                        break

                if has_strictly_inside_point:
                    #print("✅ At least one point strictly inside ")
                    false_shapes.append(shape)
                else:
                    #print("❌ All points outside or on edge")
                    true_shapes.append(shape)
            else:
                #print("⚠️ Shape is not a valid polyline")
                false_shapes.append(shape)

        else:
            #print("❌ No overlap")
            false_shapes.append(shape)

    # Convert shapes to Rhino object IDs for further action
    false_shapes_IDs = [sc.doc.Objects.AddCurve(shape) for shape in false_shapes]
    true_shapes_IDs = [sc.doc.Objects.AddCurve(shape) for shape in true_shapes]

    return false_shapes_IDs, true_shapes_IDs