Solid Difference Failure

I ran into an issue using Solid Difference in Grasshopper. If the two objects are precisely on the same edge, it fails and produces an invalid Brep

Here is an example I made that demonstrates the issue:
Boolean Subtract Fail.gh (7.1 KB)

The center of the cylinder is 0.25" from the edge of the box. When I make the radius of the cylinder 0.25" the Solid difference fails.

If I make the radius 0.251" then it is fine

If I make it 0.2499" then it is also fine

Hello,

I think it is Non-manifold edges.

https://docs.mcneel.com/rhino/7/help/en-us/index.htm#popup_moreinformation/non-manifold_edges.htm

Boolean Subtract Fail.gh (21.4 KB)

If I understand the issue correctly, at that exact point the non-manifold condition results in some ambiguity that is causes the Boolean Subtract to fail… is there any way to make it work to get the desired result other than to make it slightly the wrong size?

If Non Manifold edges result in an invalid Brep, and effectively nothing is output, then isn’t that the same as when Cap Holes fails to produce any output? So, shouldn’t it turn red with an error the same way Cap Holes does?

Screenshot 2023-01-08 091506

@magicteddy put together a C# script that detects when a Boolean operation fails, but it’s a workaround, I really think that if Solid Difference produces an invalid Brep for whatever reason, it should be producing the same error that Cap Holes produces. Just sitting there being all nice and grey like nothing is wrong makes it really difficult to figure out, especially if you have a complicated model and with a lot of operations, and the whole model just disappears, and you have no way to see why it’s gone, you have to manually go look one item at a time until you figure it out, instead of just looking at the red thing.

I have no idea why this convoluted workaround works (at least, on this example), but… it does !

ClosedBrep.gh (9.9 KB)

@magicteddy Thanks for figuring that out.

I can see why it works, It’s removing the Non-Manifold condition by breaking the part and creating a second intersection between the cylinder and the part.

It would only work if it was on one of the edges aligned with the Y axis, but I think I can make it work no matter what edge it is on. I thought I could just check to see if it was on the edge of X or Y and use whatever is needed, but then it would not work if the edge of the part was on a diagonal.

So I think I can maybe check to see if the cylinder is tangent to the closest edge of the part and if it is, put the plane in and rotate it 90 degrees to the tangent point and cut the part there, then it should work no matter what angle it happens to be at.

Edit:
I got to thinking about this and I think that if I cut the part in both the X and Y direction and then do the Solid Difference, then put them all back together, it would always work no matter the angle, because there would always be 2 points of contact with the cylinder no matter how it was rotated. It seems to work:

ClosedBrep XY.gh (11.8 KB)

Edit… Again:
using this method with both X and Y has a flaw… this can happen:

325 Degrees:

An alternate method that works in this case is to rebuild and replace the invalid brep face.

Bool_Sub_Fail_Repair_230108.gh (13.8 KB)

-Kevin

Doing the same operations in Rhino results in a Brep with a non-manifold edge.

Another topic with a similar problem:

@Gijs why isn’t an invalid brep output displayed orange or red?

@Kevin
I like this idea better, because when you split the Brep and put it back together, you end up with these extra seams in the cylinder.
Screenshot 2023-01-09 034613

but this method doesn’t do that. It also seems to work no matter the angle. I put the rotation in to test it, then I noticed that this only needs to be fixed when it lands on an edge that is aligned to the X or Y Axis. So I made it only run the repair if it is needed, that should speed things up.

180 Degrees:


239 Degrees:


Bool_Sub_Fail_Repair_Rotated.gh (12.6 KB)

It would be nice if the Boolean Subtract in both Rhino and Grasshopper checked for this issue and rebuilt the surface internally the way @kev.r fixed it. It seems it would be possible to have the boolean function just do a check at the end to see if the Brep is invalid, and if it is, apply the steps to repair it, otherwise just output it.

Hi,

I have merged several ideas posted here, and made the pipe so that the seam of the cylinder is always on the inside. This seems to be consistent, whatever rotation, position of the point, radius or depth is chosen.

ClosedBrep.gh (16.4 KB)

1 Like

Rotating the cube and cylinder around a common center point should produce the same result. As long as they have faces that are touching, they should produce a non-manifold edge.

You need to be careful about passing data through text panels like you are doing here:


This is rounding these values to what you see in the text panel (looks like 6 decimal places here but depends on grasshopper settings). It’s strange but even with the text panel bypassed your file only produces an invalid brep at certain rotation angles.

Check this file:


Bool_Sub_Fail_Repair_Rotated_re.gh (14.8 KB)
The Solid Difference component here produces an invalid brep regardless of the rotation angle.

Same result here (as expected) invalid brep at all rotation angles:


Bool_Sub_Fail_Repair_Rotated_re2.gh (15.3 KB)

The difference between your file with the text panel bypassed and these two methods is minute (centroids of the cylinders differ by 3.17E-15 or less) but it’s apparently enough to change the results.

-Kevin

1 Like

@kev.r I didn’t realize the output of the panel was any different than the input, unless I typed something in there. Thank you for letting me know that, I will avoid using the panels in this way.

James

I just noticed a new issue, if I pass supply multiple inputs, it works up to the point where it needs to be repaired, but then it doesn’t continue with the rest of the inputs.

Here I gave it 5 input points, and I get 5 holes as expected:

But when I rotate it to a position where I have the invalid Brep, everything after the invalid Brep disappears.

Bool_Sub_Fail_Repair_Rotated_Multiple.gh (17.4 KB)

Also, I am not passing through the panels anymore but I still get this only when it’s at angles aligned to the XY axis. maybe it has to do with my Rhino tolerances? I think I am just in inches - small parts

It works if the “problematic” hole is the last one on the list… I guess the Solid difference stops working when it hits an invalid Brep ?

1 Like

That’s what seems to be happening. Is there some way to process each hole one at a time and keep passing the output of each stage to the next so that one in the middle could be fixed if needed and continue?

Bruteforce, maybe ? :sweat_smile:

image

private void RunScript(Brep B, List<Brep> cutters, ref object holedBrep)
  {
    Brep brep = B;
    for (int i = 0; i < cutters.Count; i++)
    {
      Brep[] sd = Brep.CreateBooleanDifference(brep, cutters[i], Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance);
      brep = sd[0];
      if (!brep.IsValid)
      {
        List<Brep> bps = new List<Brep>();
        foreach (BrepFace bf in brep.Faces)
        {
          Brep bfp = bf.DuplicateFace(false);
          if(!bfp.IsValid)
          {
            Curve[] nedges = bfp.DuplicateNakedEdgeCurves(true, false);
            Curve[] contour = Curve.JoinCurves(nedges);
            Brep[] newfaces = Brep.CreatePlanarBreps(contour, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance);
            bps.Add(newfaces[0]);
          }
          else
          {
            bps.Add(bfp);
          }


        }

        brep = Brep.JoinBreps(bps, Rhino.RhinoDoc.ActiveDoc.ModelAbsoluteTolerance)[0];

      }
    }
    holedBrep = brep;

  }

Bool_Sub_Fail_Repair_Rotated_Multiple.gh (16.5 KB)

That’s a great solution!

I thought it would be nice to know if the repair was needed, so I added a warning… but then I thought it would be even better if there was a second test after the repair, and if it was invalid again to issue an error… in case there is some situation where it’s not able to be repaired in this way, but I’m not sure what the syntax would be to make the second test after the repair.

So if it detected the invalid Brep and was able to repair it, issue a warning of “Invalid Brep Detected and Repaired”
and if it detects an invalid Brep a second time after the repair, issue an error of “Invalid Brep Detected. Unable to repair.”

I don’t know, but it would make sense to have it turn red though.
RH-72320 solid difference component doesn’t turn red on invalid result