Reliable Boolean Difference for Coplanar BReps

Hi all,

I’m struggling with a recurring Boolean Difference failure that I cannot seem to stabilize. These cutters often share overlapping vertical sides or coplanar faces with the base. I know this is a frequent topic on the forum—I’ve scanned through dozens of threads and tried the most common suggestions, but they are failing for my specific geometry.

The Setup:

  • Base Geometry: A closed Brep (a twisted, box-like geometry).

  • Cutters: Multiple closed Breps, slightly tapered.

The Issue: The results are highly inconsistent. In some cases, I get a clean Closed Brep. In others, I get an Invalid Brep, an Open Brep (due to a left-over part of cutter brep).

What hasn’t worked:

  1. Non-Uniform Scaling: I tried scaling the cutters from their centers by a small margin to eliminate coplanar overlaps. This still results in invalid geometry or the output is simply one of the cutter objects itself.

  2. Union Cutters First: Attempting to Solid Union the cutters first before I do the Difference doesn’t produce a better result.

  3. Spatial Orientation: Strangely, if I orient the geometry from its 3D spatial position back to the World XY plane, some “Invalid” cases resolve into “Closed Breps.” However, this isn’t a fix-all; the “Open Breps” stay open regardless of location.

I am attaching a file with three examples that illustrate this inconsistency. The file should be self-explanatory. Hope someone can drect me in a working solution. I my final file, there will be 200+ elements

boolean-difference-test-03.gh (10.1 MB)

I’ve found a workaround that sort of “works,” but it isn’t ideal. I tried increasing the Non-Uniform scaling domain from 1.001 to 1.01for the cutter objects

While the Boolean succeeds, it results in what is effectively a more “dirty” geometry. The faces that were intended to be perfectly coplanar/flush are now misaligned by a margin.

I use the MergeFaces node (that joins all adjacent co-planar faces) to clean up the resulting edges and faces, but it is computationally very slow and significantly bogs down the definition when processing multiple objects.

I’m still looking for a more elegant method (or a different logic altogether) that can handle these type of intersections without requiring the randomize “jitter” that effects the original alignment.

Beste Crz_06, Een bestand van 10 mB that is hugeeee!
It took 60 seconds to load + run.
Then I enabled a Solid Diff item. And now my grasshopper is dead.

You would help me (us) by scaling it dow to just a small set of breps.

Regards, Eef

The notoriety of this topic is well deserved. Unfortunately it’s not easy to resolve, due to fundamental limits of floating-point maths. You should either make your cutters with some excess length outside the main body, or look for alternative methods to construct your geometry. For example, you could cut the rectangular holes, copy/scale/move the boundaries and Ruled Surface between them, then Boundary Surface the caps.

Hi @Eef_Weenink

Sorry for that.
When I tried any subset of the brep cutters list (from the list of cutters that result in an invalid brep), will actually result in closed brep, when i try the SDifference.

at least no one can blame for not internalizing my data :wink:

ok, this is getting odd > reducing list with 1 gives valid geometry, even with different seeds

em, ok :hot_face:
@Japhy can you explain why shuffling a list of cutter object would results in a valid CLosedBrep, whereas before it would result in invalid or open brep

test_boolean_difference_03_combined.gh (3.3 MB)

(the invalid brep output)

(the open brep output)

edit:
when check with this C# node from this thread, it may give some more insights into why this works. Be causion, expect ~8min compute vs 1min compute for the vanilla node

@crz_06, nice unsolvable problem!

How’s this for another non-ideal+terrible workaround*?
*no scaling used, but I did unify colliding solids.

b.gh (5.2 MB)



SDiff takes ~13 s (left disabled)

Hi @cfee ,

I am far from being the right person to be answering this question but I found that boolean unioning the cutters, then merging their co-planar faces before solid differencing worked. I do not know if that is a reliable generality though.

Right—I tried dispatching (A) colliding vs (B) non-colliding, ‘unify’ (As), combine with (Bs), then bang bang big boss solid

I don’t know what this means, but I’ll like it anyway.

Haha—as you said: unioning the cutters, which I did, but only the ones that are colliding with others, because the rest don’t need to be unioned; then you bring them all together to subract from the big solid. I have found that doing this {sometimes} sort of ‘slaps’ Rhino/Gh after they give you solid boolean attitude.


After experimenting for a while, I found this way. To later discover, that i am not the first, and even not the second to answer you the same way. Well, at least my method works with multithreaded for branches, so it is 10 times faster than your current solution. It uses solid union and merge coplanar faces, and i did not see it give me something other than closed brep yet

boolean-difference-test-03.gh (5.2 MB)

If it can be a box, not a twisted box - the solution can be very fast and precise, without using solid operations. So maybe consider this.

this is what i get when i bake one set of geometry before the boolean difference.

i think you’re expecting to much magic from boolean difference.
fix each group - like the blue one - first, best as a 2d polyline approach…

issues with boolean operations are best diagnosed by
_intersectTwoSet
(closed curves are needed for booleans to work)

quick and dirty:
for each group do a boolean union with mergeCoplanarFaces first:

this will reduce the complexity significant - you know more about the algorithm then the computer…

good luck - cheers - tom

That’s what I’ve done: after finding clusters of colliding solids I take cross sections (2D polyline regions), and then thicken (solid extrude) them to approximate depths of original colliding volumes. One seemingly negligible discrepancy was minute mismatches of what I suppose must be coplanar faces

@cfee my method isn’t bulletproof, however keep in mind doing the boolean union + merge faces on any instances of your clashing solids will still output dirty breps even if they appear as ‘closed’, hence the workaround attempt

Wow, awesome and creative solutions to this evolving saga! Tried something similar using Clash and then Union those, but compute time went overboard.

I’ll test your proposed solution on the full data set of 200 different sets of these Sdiff operations that need. Keep you posted of something unforseen occurs

I think this is one is of the ways, but as you saw, it takes long; then your final SDiff will also take long. Solid extrusions might get you by and speed things up a bit for that part; otherwise gain a couple of seconds with a coded method as presented by @dfytz1

Cheers!

is that ‘TreeViz2’ yours? nice versatile tool!

Yes its mine. Thank you:) I use it all the time.

based on you original code i extended it a bit so it is even more generic (example file now light weight with simple input geo)

boolean-difference-test-05.gh (127.7 KB)

  • the Clash Node now works with Branches
  • and SUnion checks for case when join brep becomes open brep (happens when 2 breps share 1 edge)
  • added node for invalidBrep just incase
  • added a branch colorizer node of my own