Problems with booleans and creating closed meshes using Rhinocommon

I’am struggling for days with some apparently simple boolean substractions.

i’am using brep.CreateBooleanSubstraction() under rhinocommon using ironpython in grasshopper.

the operation is being a substraction to a sphere of some closed solid, created revolving a curve.

9 or 10 substraction are being applied recursively to each sphere. Each time one brep vs brep. Tolerance used for the method is 1.

Finally a closed mesh object needs to be obtained. I’am using mesh.CreateFromBrep(brep,meshParam)

The process is working fine in 95% percent of the time. But in some cases, strange things happens.

When everything goes ok, the result looks like this:

but there are some cases that some little mosters appears, and rhino is considering them as “valid objects”

the resulting mesh appears like this:

Sometime the brep is closed, and apparently the geometry is visually ok and passed rhino check, but the resulting mesh using mesh.CreateFromBrep(brep,meshParam) with meshParam.JaggedSeam = False and meshParam.ClosedObjectPostProcess = True, gives as result an open mesh.

If I bake the brep and then manually convert to meshes, then all brep are converted to closed Meshes, except those brep that appear like the monster above.
Unfortunately, manual conversion is not a option. I could alternatively add brep objects to the document, use _Mesh command to convert them as long as this is the only secure manner to obtain closed meshes, and finally continue the operation in rhinocommon. But still the moster-like breps are misserably failling when converted to meshes, as shown in the image above.

All this is not making any sense to me. My nerves are almost done. Is this a bug? am I missing something?

Any help would be appreciated.

thanks

Hi @aitorleceta,

Can you post both your model and your source code?

Thanks,

– Dale

i’am not working over a model. All the data is taken from a sql database.

but I can share the model of the monster thing.
monster.3dm (391.9 KB)

     def createNodes(sefl,nodeId):

            #I omit the first part as is basically recolectin the mesh in list of meshes called boolOperatorList
            
            diam = float(node.diam) # custom component
            ptOrig = node.getPoint()
            sphere = rg.Sphere(ptOrig,diam/2)
            sphere = sphere.ToBrep()
            try:
                newList = copy.deepcopy(boolOperatorList)
                result = self.substractBrep(sphere,newList) 
            except:
                rotate = rg.Transform.Rotation(random.random(),rg.Vector3d.ZAxis,ptOrig)
                sphere.Transform(rotate) #The reason of this operation was becasuse sometimes the brep 
                                         #substraction miserably failed, so i discovered that when this happens, a little 
                                         #rotation of the sphere helps to give the method a new opportunity. It just works.
                result = self.substractBrep(sphere,newList)


            meshParam = rg.MeshingParameters.Coarse
            meshParam.JaggedSeams = False
            meshParam.ClosedObjectPostProcess = True
            meshArray = rg.Mesh.CreateFromBrep(result,meshParam)
            brepMesh = rg.Mesh()
            brepMesh.Append(meshArray)
            return brepMesh

    def substractBrep(self,brep1,brepList): #recursion function for brep substraction method
        brep2 = brepList.pop()
        brepArray = rg.Brep.CreateBooleanDifference(brep1,brep2,1)
        brep3 = rg.Brep()
        for brep in brepArray:
            brep3.Append(brep)
  
        if len(brepList)>0:
            return self.substractBrep(brep3,brepList)
        else:
            return brep3

The sphere is created on the fly on Rhinocommon.

The subsctractor geometry is readed externally from different files. I basically orient and position these geometries as needed on the fly, and group then in the mentioned boolOperatorList

in this file you will find the “substractor objects”
SubstractionGeometry.3dm (1.0 MB)

@dale , if you need more information, I will try to provide you whatever possible. I cant give you the whole think as it has a lot of non rhino dependencies. Anyway, I guess the issue if focalized in the substraction between freshly generated spheres and closed brep made from revolved surfaces.

My principal concerne is those geometries I called “monsters”, that rhino recognize as “valid geometry” but they obviously are not. Is there any rhinocommon method to detect them as invalid, even if rhino’s Check command cant detect them, something, so to say, more “incisive”…

I’have found the reason of those “degenerated”, closed, valid, succesfully checked geometry. It happens when the trimming curve happens to be tangent (what a casualty!) to the sphere seam. Untrimming this particular edge, the surface get healed.


exploding the brep and untrimming the tangent edge…

surface get “healed”

Now, the problem for me is how i can detect (programatically) that the corrupted geometry is so. If i could, then i could recursively rotate a random degree the sphere before the substraction process, until I can achieve a (really) correct geometry. I must remember that quality checking commands are not working in this case.

I would appreciate any suggestion on this.
thanks
aitor

Still, i’am surprised on how frequently this tangential relation between surface seam and edge is happening, given that the structure is very free formed globally, so there is no any logical/geometrical reason for this to happen, except “the casualty”. I can’t see ony other pattern that could explain that “phenomenom”. But again, casualty is being strangely recurrent here.

definitively, i’am missing something

could it be somehow rellated to the tolerance parameter in brep.CreateBooleanDifference method?
How is affecting this parameter the result of the boolean operation?

Hi @aitorleceta,

Rhino objects are valid if their data structures are valid and in order. So it’s possible for an object, that is geometrically invalid, to report as valid.

Also, keep in mind that Boolean Union in a operation designed for solids. Since you are trying to difference open Breps from a closed Brep, you’ve got to make sure the face normals are all pointing in an outward direction. Looking at your model, it appears the direction of the “lip” surface (for lack of better term) is pointed inward relative to the rest of the cylinder.

monster-fixed.3dm (193.6 KB)

– Dale

Hi Dale, thank for your comments.

But i must say that the operation are made between closed breps not opensurfaces.I double checked the operators geometry, and I found that only one of them has an issue, having a naked edge, so being open.

This is the geometry to be substracted from the sphere. Executing _SelClosedPolysrf command…

I found that one of them is incorrectly constructed…

But I have checked if this particular geometry has participated in the boolean operations applyed to the “monster”, and the answer is no. So, even if that open polysurface should give problems on a boolean, still we have a bad geometry, even when it was generated solely using closed polysurfaces.

By the other hand, exploding the bad polysurface, all normal direction seem to be correct. Aren’t they? (backfaces are colored emerald.) I dont quite get what part you refere with “lip”…

In conclusion, i’am still not sure why is this happening. What i have found is that when geometry is bad, rotating a little bit the sphere (avoiding the tangential rellation between surface seam and trimmed edge) then the boolean goes wright. Don’t you think this could be the main cause? I doesn’t make sense?

leceta

Hi @aitorleceta,

Your geometry is fairly far from the world origin. I’m wondering if this is a floating point rounding issue?

– Dale

oh! good point @dale !
The project is worked in milimeters for a really huge building.
I must try this. Thanks