Salome HOME
Merge branch 'jfa/40620_ExportXAO_separate_BREP'
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_SketchBuilder.cpp
index bbeccf7b2a310dc48e8fcddbe45ed3cd5ecdf546..5dd1a6a901eb69975047a41d8ba7a1ee46ac1cd7 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2024  CEA, EDF
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 //
 // You should have received a copy of the GNU Lesser General Public
 // License along with this library; if not, write to the Free Software
-// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
 //
-// See http://www.salome-platform.org/ or
-// email : webmaster.salome@opencascade.com<mailto:webmaster.salome@opencascade.com>
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
 //
 
 #include <GeomAlgoAPI_SketchBuilder.h>
 #include <GeomAPI_PlanarEdges.h>
 
+#include <GeomAPI_Pln.h>
+
 #include <BOPAlgo_Builder.hxx>
 #include <BRep_Builder.hxx>
 #include <BRepTools_WireExplorer.hxx>
@@ -164,7 +165,7 @@ bool isFirst(const TopoDS_Shape& theFirst, const TopoDS_Shape& theSecond,
 }
 
 // sorts faces (in theAreas list) to make persistent order: by initial shapes edges
-static void sortFaces(TopTools_ListOfShape& theAreas,
+static void sortAreas(TopTools_ListOfShape& theAreas,
   const std::list<std::shared_ptr<GeomAPI_Shape> >& theInitialShapes)
 {
   // collect indices of all edges to operate them quickly
@@ -199,46 +200,54 @@ static void sortFaces(TopTools_ListOfShape& theAreas,
   }
 }
 
-void GeomAlgoAPI_SketchBuilder::createFaces(
+void GeomAlgoAPI_SketchBuilder::build(
     const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
     const std::shared_ptr<GeomAPI_Dir>& theDirX,
     const std::shared_ptr<GeomAPI_Dir>& theNorm,
-    const std::list<std::shared_ptr<GeomAPI_Shape> >& theFeatures,
-    std::list<std::shared_ptr<GeomAPI_Shape> >& theResultFaces)
+    const std::list<std::shared_ptr<GeomAPI_Shape> >& theEdges)
 {
-  if (theFeatures.empty())
+  myResultFaces.clear();
+  setDone(false);
+  if (theEdges.empty())
     return;
 
   BRep_Builder aBuilder;
   // Planar face, where the sketch was built
-  Handle(Geom_Surface) aPlane(new Geom_Plane(theOrigin->impl<gp_Pnt>(), theNorm->impl<gp_Dir>()));
+  gp_Ax3 aPlnAxes(theOrigin->impl<gp_Pnt>(), theNorm->impl<gp_Dir>(), theDirX->impl<gp_Dir>());
+  Handle(Geom_Surface) aPlane(new Geom_Plane(aPlnAxes));
   TopoDS_Face aPlnFace;
   aBuilder.MakeFace(aPlnFace, aPlane, Precision::Confusion());
 
   // Use General Fuse algorithm to prepare all subfaces, bounded by given list of edges
-  BOPAlgo_Builder aBB;
-  aBB.AddArgument(aPlnFace);
+  BOPAlgo_Builder* aBB = new BOPAlgo_Builder;
+  aBB->AddArgument(aPlnFace);
+  // Set fuzzy value for BOP, because PlaneGCS can solve the set of constraints with
+  // the precision up to 5.e-5 if the sketch contains arcs.
+  static const double THE_FUZZY_TOL = 5.e-5;
+  aBB->SetFuzzyValue(THE_FUZZY_TOL);
+
+  setImpl(aBB);
+  setBuilderType(OCCT_BOPAlgo_Builder);
 
   NCollection_List<TopoDS_Shape> anEdges;
   NCollection_List<TopoDS_Shape>::Iterator aShapeIt;
-  std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFeatIt = theFeatures.begin();
-  for (; aFeatIt != theFeatures.end(); aFeatIt++) {
+  std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFeatIt = theEdges.begin();
+  for (; aFeatIt != theEdges.end(); aFeatIt++) {
     std::shared_ptr<GeomAPI_Shape> aShape(*aFeatIt);
     const TopoDS_Edge& anEdge = aShape->impl<TopoDS_Edge>();
     if (anEdge.ShapeType() == TopAbs_EDGE)
-      aBB.AddArgument(anEdge);
+      aBB->AddArgument(anEdge);
   }
-  aBB.Perform();
-#ifdef USE_OCCT_720
-  if (aBB.HasErrors())
+  aBB->Perform();
+  if (aBB->HasErrors())
     return;
-#else
-  if (aBB.ErrorStatus())
-    return;
-#endif
+
+  TopoDS_Compound aResult;
+  aBuilder.MakeCompound(aResult);
+
   // Collect faces
-  TopTools_ListOfShape anAreas = aBB.Modified(aPlnFace);
-  sortFaces(anAreas, theFeatures); // sort faces by the edges in them
+  TopTools_ListOfShape anAreas = aBB->Modified(aPlnFace);
+  sortAreas(anAreas, theEdges); // sort faces by the edges in them
   TopTools_ListIteratorOfListOfShape anIt(anAreas);
   for (; anIt.More(); anIt.Next()) {
     TopoDS_Face aFace = TopoDS::Face(anIt.Value());
@@ -251,14 +260,25 @@ void GeomAlgoAPI_SketchBuilder::createFaces(
     TopoDS_Face aNewFace;
     aBuilder.MakeFace(aNewFace, aPlane, Precision::Confusion());
 
-    // iterate on wires
+    // sort inner wires according to the original edges as well as faces
+    TopTools_ListOfShape aWires;
     TopExp_Explorer aWireExp(aFace, TopAbs_WIRE);
-    for (; aWireExp.More(); aWireExp.Next()) {
-      TopoDS_Wire aWire = TopoDS::Wire(aWireExp.Current());
+    for (; aWireExp.More(); aWireExp.Next())
+      aWires.Append(aWireExp.Current());
+    if (aWires.Size() > 2) {
+      TopoDS_Shape anOuterWire = aWires.First();
+      aWires.RemoveFirst();
+      sortAreas(aWires, theEdges);
+      aWires.Prepend(anOuterWire);
+    }
+
+    // iterate on wires
+    for (TopTools_ListIteratorOfListOfShape aWIt(aWires); aWIt.More(); aWIt.Next()) {
+      TopoDS_Wire aWire = TopoDS::Wire(aWIt.Value());
 
       // to make faces equal on different platforms, we will find
       // a vertex lying on an edge with the lowest index in the list of initial edges
-      TopoDS_Vertex aStartVertex = findStartVertex(aWire, aFace, theFeatures);
+      TopoDS_Vertex aStartVertex = findStartVertex(aWire, aFace, theEdges);
 
       TopoDS_Wire aNewWire;
       aBuilder.MakeWire(aNewWire);
@@ -294,30 +314,43 @@ void GeomAlgoAPI_SketchBuilder::createFaces(
     }
 
     // store face
-    aFace = aNewFace;
+    aBuilder.Add(aResult, aNewFace);
     std::shared_ptr<GeomAPI_Shape> aResFace(new GeomAPI_Shape);
-    aResFace->setImpl(new TopoDS_Face(aFace));
-    theResultFaces.push_back(aResFace);
+    aResFace->setImpl(new TopoDS_Face(aNewFace));
+    myResultFaces.push_back(aResFace);
   }
+
+  // update results
+  GeomShapePtr aResShape(new GeomAPI_Shape);
+  aResShape->setImpl(new TopoDS_Shape(aResult));
+  setShape(aResShape);
+  setDone(true);
+}
+
+GeomAlgoAPI_SketchBuilder::GeomAlgoAPI_SketchBuilder(
+  const std::shared_ptr<GeomAPI_Pln>& thePlane,
+  const std::list<std::shared_ptr<GeomAPI_Shape> >& theEdges)
+{
+  build(thePlane->location(), thePlane->xDirection(), thePlane->direction(), theEdges);
 }
 
-void GeomAlgoAPI_SketchBuilder::createFaces(const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
-                                            const std::shared_ptr<GeomAPI_Dir>& theDirX,
-                                            const std::shared_ptr<GeomAPI_Dir>& theNorm,
-                                            const std::shared_ptr<GeomAPI_Shape>& theWire,
-                                std::list<std::shared_ptr<GeomAPI_Shape> >& theResultFaces)
+GeomAlgoAPI_SketchBuilder::GeomAlgoAPI_SketchBuilder(
+    const std::shared_ptr<GeomAPI_Pnt>& theOrigin,
+    const std::shared_ptr<GeomAPI_Dir>& theDirX,
+    const std::shared_ptr<GeomAPI_Dir>& theNorm,
+    const std::shared_ptr<GeomAPI_Shape>& theWire)
 {
   std::shared_ptr<GeomAPI_PlanarEdges> aWire =
     std::dynamic_pointer_cast<GeomAPI_PlanarEdges>(theWire);
   if(aWire) {
     // Filter wires, return only faces.
-    createFaces(theOrigin, theDirX, theNorm, aWire->getEdges(), theResultFaces);
+    build(theOrigin, theDirX, theNorm, aWire->getEdges());
   } else { // it may be only one circle
     std::shared_ptr<GeomAPI_Edge> anEdge = std::dynamic_pointer_cast<GeomAPI_Edge>(theWire);
     if (anEdge) {
       std::list<std::shared_ptr<GeomAPI_Shape> > aList;
       aList.push_back(anEdge);
-      createFaces(theOrigin, theDirX, theNorm, aList, theResultFaces);
+      build(theOrigin, theDirX, theNorm, aList);
     }
   }
 }