Salome HOME
updated copyright message
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_WireBuilder.cpp
index a90d1e95320afd3bb302da0592dde07c4f5e9133..9aab0b6f2b4e5ad40be470ee7da3c7db11112155 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2019  CEA/DEN, EDF R&D
+// Copyright (C) 2014-2023  CEA, EDF
 //
 // This library is free software; you can redistribute it and/or
 // modify it under the terms of the GNU Lesser General Public
 #include <BRepBuilderAPI_MakeWire.hxx>
 #include <BRepTools_ReShape.hxx>
 #include <Geom_Curve.hxx>
+#include <Precision.hxx>
 #include <TopoDS.hxx>
 #include <TopoDS_Wire.hxx>
 #include <TopExp.hxx>
 #include <TopExp_Explorer.hxx>
 
+#include <cmath>
+#include <map>
+#include <set>
+
+class SetOfEdges
+{
+  class DoubleCompare {
+  public:
+    bool operator() (const double d1, const double d2) const {
+      return d1 + Precision::Confusion() < d2;
+    }
+  };
+
+  typedef std::map<double, std::set<double, DoubleCompare>, DoubleCompare> ParamMap;
+  std::map<Handle(Geom_Curve), ParamMap> myShapes;
+
+public:
+  bool add(const TopoDS_Shape& theEdge)
+  {
+    const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge);
+    if (anEdge.IsNull())
+      return true;
+
+    double aFirst, aLast;
+    Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
+
+    bool isAdded = true;
+    std::map<Handle(Geom_Curve), ParamMap>::iterator
+        aFound = myShapes.find(aCurve);
+    if (aFound == myShapes.end())
+      myShapes[aCurve][aFirst].insert(aLast);
+    else {
+      ParamMap::iterator aFoundPar = aFound->second.find(aFirst);
+      if (aFoundPar == aFound->second.end())
+        aFound->second[aFirst].insert(aLast);
+      else if (aFoundPar->second.find(aLast) == aFoundPar->second.end())
+        aFoundPar->second.insert(aLast);
+      else
+        isAdded = false;
+    }
+    return isAdded;
+  }
+
+  static bool isEqual(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2)
+  {
+    const TopoDS_Edge& anEdge1 = TopoDS::Edge(theShape1);
+    const TopoDS_Edge& anEdge2 = TopoDS::Edge(theShape2);
+    if (anEdge1.IsNull() || anEdge2.IsNull())
+      return false;
+
+    double aFirst1, aLast1;
+    Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aFirst1, aLast1);
+    double aFirst2, aLast2;
+    Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aFirst2, aLast2);
+    return aCurve1 == aCurve2 && fabs(aFirst1 - aFirst2) < Precision::Confusion() &&
+                                 fabs(aLast1 - aLast2) < Precision::Confusion();
+  }
+};
+
 static GeomShapePtr fromTopoDS(const TopoDS_Shape& theShape)
 {
   GeomShapePtr aResultShape(new GeomAPI_Shape());
@@ -45,21 +105,34 @@ GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
                                                  const bool theForceOpenWire)
 {
   TopTools_ListOfShape aListOfEdges;
+  SetOfEdges aProcessedEdges;
 
   ListOfShape::const_iterator anIt = theShapes.cbegin();
   for (; anIt != theShapes.cend(); ++anIt) {
-    const TopoDS_Shape& aShape = (*anIt)->impl<TopoDS_Shape>();
-    switch (aShape.ShapeType()) {
-    case TopAbs_EDGE: {
-      aListOfEdges.Append(aShape);
-      break;
-    }
-    case TopAbs_WIRE: {
-      for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
-        aListOfEdges.Append(anExp.Current());
+    TopoDS_Shape aShape = (*anIt)->impl<TopoDS_Shape>();
+    switch(aShape.ShapeType()) {
+      case TopAbs_EDGE: {
+        aShape.Orientation(TopAbs_FORWARD);
+        if (aProcessedEdges.add(aShape))
+          aListOfEdges.Append(aShape);
+        break;
+      }
+      case TopAbs_WIRE: {
+        for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
+          TopoDS_Shape anEdge = anExp.Current();
+          anEdge.Orientation(TopAbs_FORWARD);
+          // if the edge was already processed, remove it to keep original order of the current wire
+          if (!aProcessedEdges.add(anEdge)) {
+            for (TopTools_ListIteratorOfListOfShape aEIt(aListOfEdges); aEIt.More(); aEIt.Next())
+              if (SetOfEdges::isEqual(anEdge, aEIt.Value())) {
+                aListOfEdges.Remove(aEIt);
+                break;
+              }
+          }
+          aListOfEdges.Append(anEdge);
+        }
+        break;
       }
-      break;
-    }
     default:
       break;
     }
@@ -67,7 +140,7 @@ GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
 
   bool isSplitWire = false;
   gp_Pnt aSplitPoint;
-  if (theForceOpenWire) {
+  if (theForceOpenWire && aListOfEdges.Size() > 1) {
     // find a vertex to split the wire
     TopoDS_Vertex V1[2];
     TopExp::Vertices(TopoDS::Edge(aListOfEdges.First()), V1[0], V1[1]);
@@ -79,7 +152,7 @@ GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
     double Tol2[2] = { BRep_Tool::Tolerance(V2[0]), BRep_Tool::Tolerance(V2[1]) };
     for (int i = 0; i < 2 && !isSplitWire; ++i)
       for (int j = 0; j < 2 && !isSplitWire; ++j)
-        if (P1[i].Distance(P2[i]) < Max(Tol1[i], Tol2[j])) {
+        if (P1[i].Distance(P2[j]) < Max(Tol1[i], Tol2[j])) {
           aSplitPoint = P1[i];
           isSplitWire = true;
         }
@@ -168,7 +241,6 @@ bool GeomAlgoAPI_WireBuilder::isSelfIntersected(const GeomShapePtr& theWire)
   }
 
   // Check intersections between edges pair-wise
-  int aNbEdges = (int)anEdges.size();
   std::list<GeomShapePtr>::const_iterator anEdgesIt = anEdges.begin();
   for (int i = 0; anEdgesIt != anEdges.end(); ++anEdgesIt, i++) {
     GeomEdgePtr anEdge1(new GeomAPI_Edge(*anEdgesIt));