Boolean Difference - failure for simple case

I came across a simple example for which Boolean difference completely fails. Changing the tolerance settings does not help. The solids are clean and simple. Obviously there are workarounds for this, but I decided to post this to help tracking down the problem in Boolean difference. Please find attached the example.

BoolenDifferenceFailure.3dm (118.0 KB)

It may look simple, but there are some edges with very high tolerances on the gray polysurface. This is probably the cause of the problem.

Use the List command to see this, for example

edge[36]: v0(21) v1(24) 3d_curve(36) tolerance(6.30033)
    domain(-400.048,-100.047) start(-15491.6,-1715.64,19130) end(-15743.3,-1878.9,19130)
    trims (+73,+72)
  edge[37]: v0(27) v1(22) 3d_curve(37) tolerance(5.73398)
    domain(-399.777,-99.7761) start(-15699.8,-1946.02,19130) end(-15448.1,-1782.76,19130)
    trims (+75,+74)
  edge[38]: v0(22) v1(13) 3d_curve(38) tolerance(5.73398)
    domain(-2993.49,-2575.34) start(-15448.1,-1782.76,19130) end(-15215.1,-2130.48,19130)
    trims (-76,+77)

Many thanks for the hint, I hadn’t known about the List command. Very strange to see such high tolerances being reported, given that the solid was created using a document tolerance of 0.000001.

Why are you working with such high file tolerances? That’s 1/1000 of a micron, very few manufacturing process can even hold one micron. For objects of that size, that tolerance setting basically only going to slow things down and may cause operations to fail.

http://wiki.mcneel.com/rhino/faqtolerances

Was this object created in Rhino or elsewhere? As Menno said, there are edges that have been pulled completely out of tolerance - by 5-6 mm in some cases, so it would be good to know how it was made in the first place.

–Mitch

The reason I am working with a very low value for the absolute tolerance was to achieve a model as clean as possible, because I knew I would have to do a lot of Boolean operations later on. All of the objects in my example where created inside Rhino, using the same absolute tolerance setting of 1e-6.

I uploaded another file containing the object before any Boolean operation. The tolerance shown by the List command is already quite high for some edges in my opinion, way to high given the absolute tolerance setting I am using. (On another note it would be interesting to know how the tolerances shown by the List command are defined exactly.) Doing the Boolean difference based on this object, the tolerance explodes after the Boolean operation. Subtracting both red objects parallel does not work, only if done serially in a specific order. In any case no further Boolean operations can be done afterwards.

BoolenDifferenceFailure.3dm (175.3 KB)

Again, how was the green object made (before boolean) ? If you explode, rebuild edges and re-join, it does not join up as closed, the edges are way out of tolerance. This does not appear to be a simple extrusion, so how did you create it to have edges that bad?

If I extract a border, and I extrude that, the boolean differences work fine…

–Mitch

The green solid consists of 4 planar surfaces (top and bottom, sides), and two curved surfaces (front and back). It was created by reciprocally trimming the initial (large) surfaces with each other, then joining them to a solid. All of these operations were carried out using an absolute tolerance of 1e-6. What I don’t get is how the edges can become that bad, because all of them are intersections created at this very low tolerance.

What’s odd here is that I am unable to change the file tolerance back to something reasonable such as 0.001. (that looks like a bug - not in your file though, wonder if anyone else sees that…)

Again, your very high tolerance value is probably the cause here, coupled with the fact that your objects are very far from the origin. The floating point math involved may not be able to arrive at a successful edge join under these conditions.

If I copy your object to a new file (as I can’t seem to change the tolerances in an open file here) with an absolute tolerance of 0.001, untrim, retrim and rejoin all using that tolerance, everything works fine including the BooleanDifference, even that far from the origin.

You are working under the misconception that setting the tolerance higher will result in a more accurate file. That is not necessarily the case and can actually cause problems later on, as the Wiki article suggests.

From the wiki page:

In general you should keep the absolute tolerance setting in the range
of 0.01 to 0.0001, and never set it below 1.0e-5. If you need tighter
tolerance, use smaller units instead.

1 Like

Many thanks for your feedback. I also worked on tracking down the problem, and found out the following:

The inaccuracy is introduced when trimming the planar top surface using one of the curved side surfaces. This is being done in a RhinoScript using Rhino.TrimBrep. The trimmed surface resulting from this operation already has a very high tolerance (>1mm) along one of its edges. Strangely the joining of surfaces, which follows after the trimming of all 6 faces making up the solid, does not care about this huge tolerance and just joins everything into a solid. I assume this happens because the edge curves are actually correct and match each other within tolerance.

I am sure now that there is a bug in Rhino.TrimBrep. It doesn’t occur very often because I am using this procedure on hundreds of these elements, and I had this problems only regarding two of them. Interestingly it only occurs when trimming planar surfaces. I am using the following workaround now: After calling Rhino.TrimBrep on the planar surface, I duplicate the boundary curve and recreated a planar surface from it using Rhino.AddPlanarSrf.

What tolerance are you using for TrimBrep() ? Does anything change if you loosen or tighten the tolerance?

Instead of trimming the planar surface, why not just call Rhino.Geometry.Brep.CapPlanarHoles() ?

–Mitch

I experimented with changing the tolerance, but the bad behavior of Rhino.TrimBrep won’t change.

That’s what I’m doing for the small planar side surfaces. You are right that this could be done for the top and bottom surface instead.

Well, I suppose it could be a bug in Rhino.TrimBrep()… However, I still don’t see why it works with the normal native Rhino commands (if you lower the file tolerance) and not with RhinoCommon. In principle, it is calling the same code behind the scenes… It is possible that TrimBrep() is not paying attention to the programmed tolerance as it is supposed to and is instead using the file tolerance, which might explain the failure.

–Mitch

This is not necessarily true for all commands, I recall multiple discussions in where a developer wants to “duplicate” the behavior of a command, and the response of RMA being that this is not possible because the native Rhino command has completely different code than the similar code in RhinoCommon (e.g. Using CreatePatch in RhinoCommon without a starting surface - #8 by dale)

I dunno… Somewhere it is still calling into calling some lower level geometric kernel function that actually does the trimming, no? --Mitch