Salome HOME
Copyright update 2020
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_SketchBuilder.cpp
index c4bf9d6f38d37039a245433249aeb4b5a9997624..56fbfda740812ec99e1d006f409bf7aa21fde6ea 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2017  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2020  CEA/DEN, EDF R&D
 //
 // 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>
 #include <BRepTopAdaptor_FClass2d.hxx>
 #include <Geom_Plane.hxx>
 #include <Geom_TrimmedCurve.hxx>
@@ -63,7 +65,7 @@ static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape)
   return aStart;
 }
 
-static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape,
+static TopoDS_Vertex findStartVertex(const TopoDS_Wire& theWire, const TopoDS_Face& theFace,
     const std::list<std::shared_ptr<GeomAPI_Shape> >& theInitialShapes)
 {
   // Try to find edge lying on the one of original edges.
@@ -80,9 +82,9 @@ static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape,
     if (aCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
       aCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve)->BasisCurve();
 
-    TopExp_Explorer anExp(theShape, TopAbs_EDGE);
+    BRepTools_WireExplorer anExp(theWire, theFace);
     for (; anExp.More(); anExp.Next()) {
-      const TopoDS_Edge& aShapeEdge = TopoDS::Edge(anExp.Current());
+      const TopoDS_Edge& aShapeEdge = anExp.Current();
       double aF, aL;
       Handle(Geom_Curve) aShapeCurve = BRep_Tool::Curve(aShapeEdge, aF, aL);
       if (aShapeCurve->DynamicType() == STANDARD_TYPE(Geom_TrimmedCurve))
@@ -99,7 +101,7 @@ static TopoDS_Vertex findStartVertex(const TopoDS_Shape& theShape,
   }
 
   // start vertex is not found, use algorithm to search vertex with the greatest coordinates
-  return findStartVertex(theShape);
+  return findStartVertex(theWire);
 }
 
 // returns true if the first shape must be located earlier than the second
@@ -113,7 +115,7 @@ bool isFirst(const TopoDS_Shape& theFirst, const TopoDS_Shape& theSecond,
     if (!theAreaToIndex.IsBound(aShape)) { // fill the list of curve indices
       NCollection_List<int> aNewList;
       TopExp_Explorer anEdgesExp(aShape, TopAbs_EDGE);
-      for(; anEdgesExp.More(); anEdgesExp.Next()) {
+      for (; anEdgesExp.More(); anEdgesExp.Next()) {
         double aFirst, aLast;
         Handle(Geom_Curve) aCurve = BRep_Tool::Curve(
           TopoDS::Edge(anEdgesExp.Current()), aFirst, aLast);
@@ -123,24 +125,34 @@ bool isFirst(const TopoDS_Shape& theFirst, const TopoDS_Shape& theSecond,
           aNewList.Append(theCurveToIndex.Find(aCurve));
         }
       }
-      NCollection_Array1<int> aNewArray(1, aNewList.Extent());
-      NCollection_List<int>::Iterator aListIter(aNewList);
-      for(int anIndex = 1; aListIter.More(); aListIter.Next(), anIndex++) {
-        aNewArray.SetValue(anIndex, aListIter.Value());
+      if (aNewList.Extent()) {
+        NCollection_Array1<int> aNewArray(1, aNewList.Extent());
+        NCollection_List<int>::Iterator aListIter(aNewList);
+        for (int anIndex = 1; aListIter.More(); aListIter.Next(), anIndex++) {
+          aNewArray.SetValue(anIndex, aListIter.Value());
+        }
+        std::sort(aNewArray.begin(), aNewArray.end());
+        theAreaToIndex.Bind(aShape, aNewArray);
       }
-      std::sort(aNewArray.begin(), aNewArray.end());
-      theAreaToIndex.Bind(aShape, aNewArray);
     }
   }
-  // compare lists of indices one by one to find chich list indices are lower
-  NCollection_Array1<int>::Iterator aFirstList(theAreaToIndex.ChangeFind(theFirst));
-  NCollection_Array1<int>::Iterator aSecondList(theAreaToIndex.ChangeFind(theSecond));
-  for(; aFirstList.More() && aSecondList.More(); aFirstList.Next(), aSecondList.Next()) {
-    if (aFirstList.Value() < aSecondList.Value()) return true;
-    if (aFirstList.Value() > aSecondList.Value()) return false;
+  bool isFirst;
+  bool aGeomCompare = !theAreaToIndex.IsBound(theFirst) || !theAreaToIndex.IsBound(theSecond);
+  if (!aGeomCompare) {
+    // compare lists of indices one by one to find chich list indices are lower
+    NCollection_Array1<int>::Iterator aFirstList(theAreaToIndex.ChangeFind(theFirst));
+    NCollection_Array1<int>::Iterator aSecondList(theAreaToIndex.ChangeFind(theSecond));
+    for (; aFirstList.More() && aSecondList.More(); aFirstList.Next(), aSecondList.Next()) {
+      if (aFirstList.Value() < aSecondList.Value()) return true;
+      if (aFirstList.Value() > aSecondList.Value()) return false;
+    }
+    aGeomCompare = !aFirstList.More() && !aSecondList.More();
+    isFirst = !aFirstList.More();
+  } else {
+    isFirst = !theAreaToIndex.IsBound(theFirst);
   }
   // if faces are identical by curves names (circle splitted by line in seam-point), use parameters
-  if (!aFirstList.More() && !aSecondList.More()) {
+  if (aGeomCompare) {
     GProp_GProps aGProps;
     BRepGProp::SurfaceProperties(theFirst, aGProps);
     gp_Pnt aCentre1 = aGProps.CentreOfMass();
@@ -149,11 +161,11 @@ bool isFirst(const TopoDS_Shape& theFirst, const TopoDS_Shape& theSecond,
     return aCentre1.X() + aCentre1.Y() + aCentre1.Z() < aCentre2.X() + aCentre2.Y() + aCentre2.Z();
   }
   // if in first list there is no elements left, it is the first
-  return !aFirstList.More();
+  return isFirst;
 }
 
 // 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
@@ -188,14 +200,15 @@ 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;
@@ -205,25 +218,31 @@ void GeomAlgoAPI_SketchBuilder::createFaces(
   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);
+
+  setImpl(aBB);
+  setBuilderType(OCCT_BOPAlgo_Builder);
 
-  BOPCol_ListOfShape anEdges;
-  BOPCol_ListIteratorOfListOfShape aShapeIt;
-  std::list<std::shared_ptr<GeomAPI_Shape> >::const_iterator aFeatIt = theFeatures.begin();
-  for (; aFeatIt != theFeatures.end(); aFeatIt++) {
+  NCollection_List<TopoDS_Shape> anEdges;
+  NCollection_List<TopoDS_Shape>::Iterator aShapeIt;
+  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();
-  if (aBB.ErrorStatus())
+  aBB->Perform();
+  if (aBB->HasErrors())
     return;
 
+  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());
@@ -236,14 +255,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, theFeatures);
+      TopoDS_Vertex aStartVertex = findStartVertex(aWire, aFace, theEdges);
 
       TopoDS_Wire aNewWire;
       aBuilder.MakeWire(aNewWire);
@@ -251,12 +281,12 @@ void GeomAlgoAPI_SketchBuilder::createFaces(
       bool aStartFound = false;
 
       // remove internal edges from faces and make wire start from found vertex
-      TopExp_Explorer anExp(aWire, TopAbs_EDGE);
+      BRepTools_WireExplorer anExp(aWire, aFace);
       for (; anExp.More(); anExp.Next()) {
         if (anExp.Current().Orientation() == TopAbs_INTERNAL)
           continue;
         if (!aStartFound) {
-          const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current());
+          const TopoDS_Edge& anEdge = anExp.Current();
           TopoDS_Vertex aV1, aV2;
           TopExp::Vertices(anEdge, aV1, aV2, Standard_True);
           if (aV1.IsSame(aStartVertex) == Standard_True)
@@ -273,36 +303,49 @@ void GeomAlgoAPI_SketchBuilder::createFaces(
         aBuilder.Add(aNewWire, *aSkIt);
 
       // check the wire is empty
-      anExp.Init(aNewWire, TopAbs_EDGE);
+      anExp.Init(aNewWire);
       if (anExp.More())
         aBuilder.Add(aNewFace, aNewWire);
     }
 
     // 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);
     }
   }
 }