Help in debugging logic... 😱

I have been going around with this for an hour or two and I finally gave up…

The script below (part of something larger) prompts the user to select a boundary curve and then gets all the other brep objects in the scene. It then tests each object to see if all the eight bbox points are inside the curve, all outside, or some inside and some outside; it classifies the objects into 3 lists, inside, outside and inters based on the result.

What I’m getting is the inverse of what is should be for inside/outside - an object which should have all points inside is reporting as outside and vice versa.

In the file below as is, there is a circle plus two visible surfaces. All the BB points on the pink surface should clearly lie outside the circle, but it gets classified as inside. Inversely, the cyan surface which is entirely inside the circle tests as outside… There are some hidden surfaces in the file that test as intersect, those are OK.

I’m sure there is something fundamental that I’m missing here, but I can’t see what - I’ve been staring at it too long probably. If you hide the cyan object and run the script with a breakpoint set as in the image below, you will see that the 8 points from the pink surface which should all be outside are all reported as inside (True) by brep.IsPointInside()

import rhinoscriptsyntax as rs
import scriptcontext as sc
import Rhino

def CheckPointInclusionBase(pts,vol,strict,tol):
    """
    Checks for inclusion of all points inside volume(single point or pt list)
    Returns:
    1 if all points are inside volume
    -1 if all points outside volume
    0 if at least one point is inside and one is outside.
    Strict=True means points that are ON surface are considered outside
    """
    if isinstance(pts,Rhino.Geometry.Point3d): pts=[pts]
    inside=False
    outside=False
#    sc.doc.Objects.AddBrep(vol) #debug
#    sc.doc.Views.Redraw() #debug
    rs.AddPoints(pts) #debug
    for pt in pts:
        chk=vol.IsPointInside(pt,tol,True)
        pass
        if chk==True:
            inside=True
        elif chk==False:
            outside=True
        else:
            #something went wrong
            return
    if inside==True and outside==False:
        #all points have tested inside, none outside
        return 1
    elif outside==True and inside==False:
        #all points have tested outside, none inside
        return -1
    else:
        return 0


def TestPointInclusion():
    msg="Select closed curve for inclusion test"
    crv_id=rs.GetObject(msg,4,preselect=True)
    if not crv_id: return
    
    obj_ids=rs.ObjectsByType(8+16,state=1)
    if not obj_ids: return
    
    inside=[]
    outside=[]
    inters=[]
    tol=sc.doc.ModelAbsoluteTolerance
    strictly_in=False
    plane=Rhino.Geometry.Plane.WorldXY
    
    all_objs_bb=rs.BoundingBox(obj_ids)
    #set plane to bottom of all objects bounding box
    plane.Origin=all_objs_bb[0]
    #get extrusion vector
    ex_vec=all_objs_bb[4]-all_objs_bb[0]
    if ex_vec.IsTiny(tol): ex_vec=Rhino.Geometry.Vector3d.ZAxis
    
    #create inclusion extrusion (closed brep)
    sel_crv=rs.coercecurve(crv_id)
    sel_crv.Transform(rs.XformPlanarProjection(plane))
    sel_extru=Rhino.Geometry.Extrusion.CreateExtrusion(sel_crv,ex_vec)
    sel_extru_brep=sel_extru.ToBrep()
    sel_vol=sel_extru_brep.CapPlanarHoles(tol)
    
    for obj_id in obj_ids:
        bb=rs.BoundingBox(obj_id)
        pts=[rs.coerce3dpoint(pt_id) for pt_id in bb]
        test=CheckPointInclusionBase(pts,sel_vol,strictly_in,tol)
        if test==1:
            #all bb points of object are inside the sel volume
            inside.append(obj_id)
        elif test==-1:
            #all bb points of object are outside the sel volume
            outside.append(obj_id)
        elif test==0:
            #some points inside, some points outside
            inters.append(obj_id)
        else:
            #some error occurred
            print("Error!")
    rs.SelectObjects(inside)
TestPointInclusion()

SelScriptProblem.3dm (2.2 MB)

:exploding_head:

1 Like

Hi @Helvetosaur,

After capping your extruded Brep, make sure the orientation is BrepSolidOrientation.Outward.

– Dale

1 Like

Hi @dale,

Thanks… I suspected that, but didn’t check the orientation in the script… What I did to test was to add the brep to the document and check the normals there, but of course, something in the Add… process flips the normals, so it looked fine once added to the document. I didn’t look further.

Why in the world does a capped, solid brep get inverted normals? Especially when made from a circle with a CCW direction and extruded in the +Z direction?

OK, so now I added a check/flip operation to make sure the brep normals are oriented outwards. That solved one problem, but highlighted another…

It was still failing on some combinations of surfaces and not others. I suspected that the point inclusion was still not working correctly when the points were at exactly the same height as the bottom or top of the extrusion volume. So I expanded the volume up and down slightly and then everything started working correctly.

I think this is the known bug concerning when the points fall on an edge - in this case on one of the surfaces of the inclusion volume - and this despite the fact that if strict is set to false, then points that are on the volume should be considered as “in”… I will try to create a simpler example to test.

Anyway, thanks for your help!

1 Like