Tips on adjusting breps to get planar intersection working?

My C# application using RhinoCommon running inside Rhino.Compute needs to perform boolean intersection & difference operations on many pairs of coplanar single-face breps. Essentially for each pair I need to get the intersection regions, the regions only in the first input, and the regions only in the second input. A boolean full-outer-join, if you will.

I find that about 2-5% of the time, the planar boolean operations Brep.CreatePlanarIntersection & Brep.CreatePlanarDifference fail in one of the following ways:

  1. The operation returns null instead of an empty array (documentation says this is the fail state)
  2. The operations do return arrays, but the sum of the area of the intersections + differences for one or both surfaces does not equal the area of the original surface
  3. The operations return arrays which conserve area, but Intersect(a,b) != Intersect(b,a), i.e. the intersection returns a different result based on the order I pass in the breps.

Here is a link to another post I made with an example of a relatively simple scenario leading to a noticeably ungood result:

A very helpful support team member from McNeel (thanks Brian J!) found that a combination of ShrinkTrimmedSrf and Rebuild performed in Rhino caused the operations to succeed. I believe I found the equivalent operations in the RhinoCommon API, BrepFace.ShrinkFace and BrepFace.Rebuild. These things go deeper into the NURBS-guts than I have gone thus far, but I found that when I encounter one of the above error conditions, passing my input breps through the function below and trying again (in a loop with maxRetries=4) does in fact seem to resolve the cases I’ve seen thus far:

	private Brep RebuildBrepFace(Brep brep, double tolerance)
        {
            if (brep.Faces.Count > 1)
                throw new InvalidOperationException("Cannot rebuild brep with multiple faces");
            
            var face = brep.Faces[0];
            
            face.ShrinkFace(BrepFace.ShrinkDisableSide.ShrinkAllSides);
            
            var u = face.Degree(0);
            var v = face.Degree(1);
            var newSurface = face.Rebuild(u*2,v*2,u*4,v*4);
            var newBrep = Brep.CopyTrimCurves(face, newSurface, tolerance);
            return newBrep;
        }

So my questions are:

  1. Am I doing the above correctly? Does anyone who knows what they are doing see anything silly / dumb / unneccesary going on in that function?
  2. Is there a more effecient way of performing that refine/repair method?
  3. I’d love any deeper understanding anyone could share around what exactly the above code is doing, and why it would change the behavior of boolean operations.

Hi @Tai,

The the equivalent Rhino commands work on your planar surface?

Feel free to post a model containing geometry that is failing for you.

– Dale

Dale, the link to my previous post contained an example:

I do believe the equivalent command using the Rhino UI output the same result (if not for the one in that example, then for others.)

My issue is not so much getting specific examples to work, it’s that this is part of a larger pipeline which needs to be robust as possible against large numbers of arbitrary new situations. I’m trying to get a solution which just works as often as possible and can automatically attempt to resolve runtime issues.

I also run into (perhaps similar?) issues in the 3d volumetric boolean operations on closed solids, and am wondering if I need to adapt the RebuildBrepFace function I posted to perform a comparable upscaling (if that’s the term) to a multi-face brep.

I see that - I’ve logged the issue.

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

– Dale