Cleaning up messy BooleanUnions


(This is just an example, so I don’t need modelling tips. It’s just a question I always have when using BooleanUnion…)

When I have something like 1. and ArrayPolar and BooleanUnion it, I get 2. which is an ugly brep that gives 40 faces when exploded. But the same overall shape can also be created using 10 faces. (3.)

Is there a script that cleans up breps after BooleanUnions when things get to much out of hand?

(Pascal Golay) #2

Hi Marcus -MergeAllFaces should help.



Hi @pascal.

I have tested -MergeAllFaces (in WIP) now and for the polysurface below, which has 784 surfaces before and 304 after the command ran, -MergeAllFaces needs 60 seconds here.

I have also written something, and although using Python, it needs 600 ms. And both seem to give the same result. So, I wanted to show it to you:


looks like rhino should be rebuilt with grasshopper technology :smiley:


Is the slower cmd line version of MergeAllFaces related to repeated Viewport updates or something?

// Rolf


I don’t know how MergeAllFaces works, but this is not the reason. Because when I just duplicate the amount of surfaces in the Brep above, so that it has 1544 surfaces exploded, MergeAllFaces needs 4 minutes instead of 1 minute, while what I have written then needs 1.4 seconds.


Sounds like some “exponential problem” with lists, something happening for each element added to the list, perhaps with history involved?

// Rolf

(Willem Derks) #9


I think it’s @rajaa who can shed some light in this.
My suspicion is that the command version of mergeallfaces is a much more robust implementation, dealing with less obvious configurations.

Out of curiosity I scrutinized your code:

My conclusion ( correct me if I’m wrong) is:
In your code you only pair up the ‘absolute’ planar surfaces, There is no tolerance to find ‘planar enough’ faces, nor is there any tolerance in how parallel planes need to be. It’s even disregarding possible floating point errors.

Let me try to follow you code:
You test for Absolute planarity of the face
I see you create a line from the origin in the face normal direction.
Next you find where that line intersects the face plane
Next you duplicate the face edges ( this could be done via Brep.DuplicateNakedEdgeCurves as well right?) I believe there is no provision for faces with holes as that would return a list of curves.

As a final step you create a dictionary key entry unique for this plane direction and height.(does a tuple get parsed as a key? I did not know that to be possible)

In the last loop I wonder again how the BooleanUnion deals with holes in faces if they get this far at all.

In a controlled environment like grasshopper however where the possible input is well known, it’s better to use optimized code rather than generic solutions meant to catch all possible configurations.

Thanks for sharing!


Okay, not too many people seem to be interested in this one, nevertheless, here is also a version that works for all my test objects. A bit slower, but still, for polysurfaces with 3000 surfaces, that take Rhino’s MergeAllFaces 20 minutes to solve, it needs 4 seconds… (224.0 KB)

(Rajaa Issa) #15

Really appreciate you taking the time to discuss this topic, and for putting together the script. It is an important issue that we discussed at length few years back, and indeed needs clarification. I also apologize for a very late reply.

We attempted to optimize MergeAllFaces with a lightweight algorithm before releasing Rhino5, and it worked fast on many of the example similar to what you provided. It was along the lines of what you suggested. However, when released to users to try in the Beta, we quickly realized that it failed on some of the more settle cases when there is a tiny change in co-planar condition that is within tolerance creating bad objects. Small differences add up cross a number of faces, and start to exceed tolerance between the 2 ends. The merged faces end up with bad edge alignment. We had to revert to the more rigorous algorithm of merging one face at a time, which I agree it can be painfully slow when you have big number of faces.
I will try to dig out some of these example, and test with your script.

I will add a bug item to my list to devise a tight tolerance test of faces to merge, and if that passes, then we can use the faster merge, otherwise use the more rigorous. This might help expedite the more common cases.


Can you share examples that you use for testing your algorithm for MergeAllFaces?

(Rajaa Issa) #17

I tried to open your GH file, but got out of memory crash. What version of Rhino and GH do you use?
Can you email me the script by itself so I can test with it?


I am using the latest WIP, but it never crashed… But I have uploaded the definition and removed one large brep. If this still shouldn’t work it’s also here. (

(Rajaa Issa) #19

Got it to run.
Here is the example that failed, and is also failing with your script. Meshing issue MergeAllFaces.3dm (551.9 KB)


There are also a few other situations where my script fails… But I think I am missing data that exists at the end of a boolean operation that returns such an object I want to clean up. Curves where the objects intersect or so… Maybe it’s not even possible to solve this problem fast without that data. But thank you for the example…

(Rajaa Issa) #21

For a general tool, it has to be robust in all cases. Most of all, it has to fail when necessary, rather than produce bad results silently. This is what prompted us to revert to the slow version. I will however have a look at ways to speed it up, but I do not See it be available in the V6 timeframe.