(Common) Boolean Intersection between Shapes

Lingkan

CAD practitioner
Hey folks,

I recently converted some of my code from computing Intersections at Geom Level to resolving them at Topology Level as BRepAlgoAPI provides a more robust out-of-the-box toolkit handling different use cases when it comes to intersecting different types of shapes.

However, using tools like BRepAlgoAPI_Common and/or BRepAlgoAPI_Section doesn't seem to accomplish my goal of finding the intersection between two shapes (essentially faces) which then the resulting edge is limited by a bounding box (solid). I attached the shapes below to read as STEP.

I appreciate any guidance on how to accomplish such an intersection, which should essentially result in a single edge.

Please provide me with some sample code to work with. Also if one is using ASITUS to visualize I appreciate some screenshots of the commands used when working with boolean API, so I'm able to debug such problems myself in the future :)
 

Attachments

  • dump.stp
    34.2 KB · Views: 3

Quaoar

Administrator
Staff member
Well, as we know, Booleans are based on the so called "general fuse" operator which is not that bad. Therefore, I would recommend using it for intersecting the shapes:

1714992230863.png

Once done, you can extract all nonmanifold edges as a result.

Code:
> clear; load-part C:/Users/serge/Desktop/dump.stp; fit
> explode
> bop-fuse-gen r "SHELL 1" "SHELL 2"
> set-as-part r
> donly

1714992369309.png

Does that make sense?
 

Lingkan

CAD practitioner
Hey Quaoar,

I indeed have tried such an approach before but unfortunately, my fuse result doesn't contain the intersecting edges...

I'll have a look using ASITUS General Fuse impl and report back my results. Thanks in advance :)
 

Quaoar

Administrator
Staff member
It worked for the inputs you provided, it essentially just intersects everything with everything, without any restrictions on the dimensionality of inputs (unlike "solid" Booleans).
 

Lingkan

CAD practitioner
I tried to fuse my two shapes as they are in the provided STEP, but when mapping the edges it only contains "14" which means it don't contain the "fused ones"...

I implemented the GeneralFuse as of: https://gitlab.com/ssv/AnalysisSitus/-/blob/master/src/asiAlgo/auxiliary/asiAlgo_Utils.cpp#L4036

C++:
BRep_Builder builder;

TopoDS_Compound dbgDump;
builder.MakeCompound(dbgDump);
builder.Add(dbgDump, shape1);
builder.Add(dbgDump, shape2);
//
// step_export::ExportSTEP(dbgDump, "generated/dump.stp");

BOPAlgo_Builder API;
TopoDS_Shape fused =
    BooleanGeneralFuse(list_utils::ToOCCList({shape1, shape2}),
                       Precision::Confusion(), API, false);

std::vector<TopoDS_Edge> nonManifoldEdges;

// Find non-manifold edges (asitus SDK)
//
// Get child-parent relationships
TopTools_IndexedDataMapOfShapeListOfShape M;
TopExp::MapShapesAndAncestors(fused, TopAbs_EDGE, TopAbs_FACE, M);

// Check for every edge the number of its owning faces
const int nEdges = M.Extent();
for (int e = 1; e <= nEdges; ++e) {
  const TopoDS_Edge &E = TopoDS::Edge(M.FindKey(e));
  //
  if (BRep_Tool::Degenerated(E)) continue;

  const int nOwningFaces = M.FindFromIndex(e).Extent();
  if (nOwningFaces > 2) {
    nonManifoldEdges.push_back(E);
    //
    builder.Add(dbgDump, E);
  }
}
step_export::ExportSTEP(dbgDump, "generated/dump.stp");
 

Quaoar

Administrator
Staff member
Here's what I tried:

Code:
int MISC_Test(const Handle(asiTcl_Interp)& interp,
              int                          /*argc*/,
              const char**                 /*argv*/)
{
  BRep_Builder builder;

  TopoDS_Shape shape1, shape2;
  BRepTools::Read(shape1, "C:/Users/serge/Desktop/shape1.brep", builder);
  BRepTools::Read(shape2, "C:/Users/serge/Desktop/shape2.brep", builder);

  TopoDS_Compound dbgDump;
  builder.MakeCompound(dbgDump);
  builder.Add(dbgDump, shape1);
  builder.Add(dbgDump, shape2);
  //
  // step_export::ExportSTEP(dbgDump, "generated/dump.stp");

  TopTools_ListOfShape args;
  args.Append(shape1);
  args.Append(shape2);

  BOPAlgo_Builder API;
  TopoDS_Shape fused =
    asiAlgo_Utils::BooleanGeneralFuse(args,
                                      Precision::Confusion(), API, true);

  interp->GetPlotter().REDRAW_SHAPE("fused", fused);

  std::vector<TopoDS_Edge> nonManifoldEdges;

  // Find non-manifold edges (asitus SDK)
  //
  // Get child-parent relationships
  TopTools_IndexedDataMapOfShapeListOfShape M;
  TopExp::MapShapesAndAncestors(fused, TopAbs_EDGE, TopAbs_FACE, M);

  TopoDS_Compound dbgDumpEdges;
  builder.MakeCompound(dbgDumpEdges);

  // Check for every edge the number of its owning faces
  const int nEdges = M.Extent();
  for (int e = 1; e <= nEdges; ++e) {
    const TopoDS_Edge &E = TopoDS::Edge(M.FindKey(e));
    //
    if (BRep_Tool::Degenerated(E)) continue;

    const int nOwningFaces = M.FindFromIndex(e).Extent();
    if (nOwningFaces > 2) {
      nonManifoldEdges.push_back(E);
      //
      builder.Add(dbgDumpEdges, E);
    }
  }
  //step_export::ExportSTEP(dbgDump, "generated/dump.stp");

  interp->GetPlotter().REDRAW_SHAPE("dbgDumpEdges", dbgDumpEdges);

  return TCL_OK;
}

Notice that I changed the compound for the edges being collected to a new one, which is dbgDumpEdges. Here's the video (I had to speed it up by x2 to compress for attachment):
 

Attachments

  • bopfuse.gif
    bopfuse.gif
    9 MB · Views: 2
  • shape1.brep
    1.1 KB · Views: 1
  • shape2.brep
    3.1 KB · Views: 1

Lingkan

CAD practitioner
I see no actual difference here... Maybe it's because of different shape types you, as used to you exploded the shapes first before working with them?

As I see your fuse result should contain const in nEdges = 17 then, right?

1715010572333.png
 
Last edited:

Lingkan

CAD practitioner
Otherwise I need to have a look at downgrading opencascade to some earlier versions, as the latest one might contain some bugs, which I consider highly unlikely…
 

Quaoar

Administrator
Staff member
There's something strange in your initial data:

1715011442821.png
In my experiments, I ignored this little face.
 

Lingkan

CAD practitioner
This is the bounding box solid which I use to restrict the filtered edges later... but it is not used for fusing the initial shapes so you were right ignoring this one...

I'm now having a look at other versions of OCC...
 
Last edited:

Quaoar

Administrator
Staff member
Maybe it's because of different shape types you, as used to you exploded the shapes first before working with them?
I exploded your initial model onto the first-level shapes, and it gave me two shells, which I then exported to BREP. Have you tried the attached BREP files? The same problem?

Btw, you can more or less easily test the "general fuse" algorithm from OpenCascade's native draw, without recompiling your app. Here is how I did that (you can check it with your present version of OpenCascade to see if the issue comes from your app or not):
 

Attachments

  • bopfusedraw.gif
    bopfusedraw.gif
    2 MB · Views: 2

Lingkan

CAD practitioner
I compiled everything till down to your version (7.6.0) but no success. I think it might have to do with the shape types...

Maybe the following gives us a hint: The STEP file I provided was transferred with:

C++:
STEPControl_Writer writer;
Interface_Static::SetIVal("write.step.nonmanifold", 1);
//
IFSelect_ReturnStatus transferStatus = writer.Transfer(shape, STEPControl_AsIs);
 

Lingkan

CAD practitioner
OK. I think i comes down to the "explode" function you have used here to get the shells and intersect them. ... Maybe it comes down to only fuse face on face or shell with instead of shell and face?

Reading and fusing the brep files works with my app (OCC 7.8.1)

I think with this we come full circle as somehow the shapes might be corrupted but writing them to disk and loading them back will allow us to fuse them... Have you ever experienced such an issue? What can we do about it?
 
Last edited:

Quaoar

Administrator
Staff member
Maybe it comes down to only fuse face on face or shell with instead of shell and face?
I just checked on a face + shell, and it worked smoothly. My experience with "general fuse" tells me that it should not be a problem. So you tried the BREP files and it worked that way? Can it be that you pass wrong shapes to the Boolean operation?
 

Lingkan

CAD practitioner
Reading and fusing the brep files works with my app (OCC 7.8.1)

I think with this we come full circle as somehow the shapes might be corrupted but writing them to disk and loading them back will allow us to fuse them... Have you ever experienced such an issue? What can we do about it?
I just checked on a face + shell, and it worked smoothly. My experience with "general fuse" tells me that it should not be a problem. So you tried the BREP files and it worked that way? Can it be that you pass wrong shapes to the Boolean operation?
Yes! I checked for face shell fuse with the brep files and it worked for me too...

I'm definitely passing the shapes the way u did in your example which is not different than my snippet...
 

Lingkan

CAD practitioner
Let me export my shapes as brep instead of STEP maybe we can debug it now.
 

Attachments

  • original_shape2.brep
    3.3 KB · Views: 2
  • original_shape1.brep
    1.3 KB · Views: 1

Quaoar

Administrator
Staff member
Just out of curiosity, can you try the following trick? Take each of your shapes (shape1 and shape2) and override them with BRepBuilderAPI_Copy, i.e.:

shape1 = BRepBuilderAPI_Copy(shape1);
shape2 = BRepBuilderAPI_Copy(shape2);

Do this before you pass them to Booleans. Would it change anything?
 

Lingkan

CAD practitioner
When trying to load the brep as i exported it vs the brep you provided it seems that there is a defect:

1715030350498.png1715030386247.png

















It gives the Warning:

[23:15:55] [WARNING] *** No polygons available for edge 1.

[23:15:55] [WARNING] *** No polygons available for edge 2.

[23:15:55] [WARNING] *** No polygons available for edge 3.

[23:15:55] [WARNING] *** No polygons available for edge 4.

[23:15:55] [WARNING] Too faulty face 1 detected: visualization facets skipped.
 

Quaoar

Administrator
Staff member
1715031346253.png

Looking at this, I see that the wire is incorrectly oriented. This face is rather a gap in infinite space. Look at the red arrows: the material is all way to the left. It is the original_shape1.brep you posted. How did that happen?
 
Top