Salome HOME
Issue #19066: SIGSEGV in pipe by section
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_WireBuilder.cpp
1 // Copyright (C) 2014-2020  CEA/DEN, EDF R&D
2 //
3 // This library is free software; you can redistribute it and/or
4 // modify it under the terms of the GNU Lesser General Public
5 // License as published by the Free Software Foundation; either
6 // version 2.1 of the License, or (at your option) any later version.
7 //
8 // This library is distributed in the hope that it will be useful,
9 // but WITHOUT ANY WARRANTY; without even the implied warranty of
10 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11 // Lesser General Public License for more details.
12 //
13 // You should have received a copy of the GNU Lesser General Public
14 // License along with this library; if not, write to the Free Software
15 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307 USA
16 //
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
18 //
19
20 #include "GeomAlgoAPI_WireBuilder.h"
21
22 #include <GeomAPI_Edge.h>
23 #include <GeomAPI_Pnt.h>
24 #include <GeomAPI_Vertex.h>
25 #include <GeomAPI_ShapeExplorer.h>
26
27 #include <BRep_Tool.hxx>
28 #include <BRepBuilderAPI_MakeWire.hxx>
29 #include <Geom_Curve.hxx>
30 #include <Precision.hxx>
31 #include <TopoDS.hxx>
32 #include <TopoDS_Wire.hxx>
33 #include <TopExp_Explorer.hxx>
34
35 #include <cmath>
36 #include <map>
37 #include <set>
38
39 class SetOfEdges
40 {
41   class DoubleCompare {
42   public:
43     bool operator() (const double d1, const double d2) const {
44       return d1 + Precision::Confusion() < d2;
45     }
46   };
47
48   typedef std::map<double, std::set<double, DoubleCompare>, DoubleCompare> ParamMap;
49   std::map<Handle(Geom_Curve), ParamMap> myShapes;
50
51 public:
52   bool add(const TopoDS_Shape& theEdge)
53   {
54     const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge);
55     if (anEdge.IsNull())
56       return true;
57
58     double aFirst, aLast;
59     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
60
61     bool isAdded = true;
62     std::map<Handle(Geom_Curve), ParamMap>::iterator
63         aFound = myShapes.find(aCurve);
64     if (aFound == myShapes.end())
65       myShapes[aCurve][aFirst].insert(aLast);
66     else {
67       ParamMap::iterator aFoundPar = aFound->second.find(aFirst);
68       if (aFoundPar == aFound->second.end())
69         aFound->second[aFirst].insert(aLast);
70       else if (aFoundPar->second.find(aLast) == aFoundPar->second.end())
71         aFoundPar->second.insert(aLast);
72       else
73         isAdded = false;
74     }
75     return isAdded;
76   }
77
78   static bool isEqual(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2)
79   {
80     const TopoDS_Edge& anEdge1 = TopoDS::Edge(theShape1);
81     const TopoDS_Edge& anEdge2 = TopoDS::Edge(theShape2);
82     if (anEdge1.IsNull() || anEdge2.IsNull())
83       return false;
84
85     double aFirst1, aLast1;
86     Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aFirst1, aLast1);
87     double aFirst2, aLast2;
88     Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aFirst2, aLast2);
89     return aCurve1 == aCurve2 && fabs(aFirst1 - aFirst2) < Precision::Confusion() &&
90                                  fabs(aLast1 - aLast2) < Precision::Confusion();
91   }
92 };
93
94 //=================================================================================================
95 GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
96 {
97   TopTools_ListOfShape aListOfEdges;
98   SetOfEdges aProcessedEdges;
99
100   ListOfShape::const_iterator anIt = theShapes.cbegin();
101   for(; anIt != theShapes.cend(); ++anIt) {
102     TopoDS_Shape aShape = (*anIt)->impl<TopoDS_Shape>();
103     switch(aShape.ShapeType()) {
104       case TopAbs_EDGE: {
105         aShape.Orientation(TopAbs_FORWARD);
106         if (aProcessedEdges.add(aShape))
107           aListOfEdges.Append(aShape);
108         break;
109       }
110       case TopAbs_WIRE: {
111         for(TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
112           TopoDS_Shape anEdge = anExp.Current();
113           anEdge.Orientation(TopAbs_FORWARD);
114           // if the edge was already processed, remove it to keep original order of the current wire
115           if (!aProcessedEdges.add(anEdge)) {
116             for (TopTools_ListIteratorOfListOfShape anIt(aListOfEdges); anIt.More(); anIt.Next())
117               if (SetOfEdges::isEqual(anEdge, anIt.Value())) {
118                 aListOfEdges.Remove(anIt);
119                 break;
120               }
121           }
122           aListOfEdges.Append(anEdge);
123         }
124         break;
125       }
126       default: {
127         return GeomShapePtr();
128       }
129     }
130   }
131
132   BRepBuilderAPI_MakeWire aWireBuilder;
133   aWireBuilder.Add(aListOfEdges);
134   if(aWireBuilder.Error() != BRepBuilderAPI_WireDone) {
135     return GeomShapePtr();
136   }
137
138   GeomShapePtr aResultShape(new GeomAPI_Shape());
139   aResultShape->setImpl(new TopoDS_Shape(aWireBuilder.Wire()));
140   return aResultShape;
141 }
142
143 //=================================================================================================
144 bool GeomAlgoAPI_WireBuilder::isSelfIntersected(const GeomShapePtr& theWire)
145 {
146   // Collect edges.
147   ListOfShape anEdges;
148
149   GeomAPI_ShapeExplorer anExp(theWire, GeomAPI_Shape::EDGE);
150   for (; anExp.more(); anExp.next()) {
151     GeomShapePtr anEdge = anExp.current();
152     anEdges.push_back(anEdge);
153   }
154
155   // Check intersections between edges pair-wise
156   int aNbEdges = (int)anEdges.size();
157   std::list<GeomShapePtr>::const_iterator anEdgesIt = anEdges.begin();
158   for (int i = 0; anEdgesIt != anEdges.end(); ++anEdgesIt, i++) {
159     GeomEdgePtr anEdge1(new GeomAPI_Edge(*anEdgesIt));
160
161     std::list<GeomShapePtr>::const_iterator anOtherEdgesIt = std::next(anEdgesIt);
162     for (int j = i + 1; anOtherEdgesIt != anEdges.end(); ++anOtherEdgesIt, j++) {
163       GeomEdgePtr anEdge2(new GeomAPI_Edge(*anOtherEdgesIt));
164       GeomShapePtr anInter = anEdge1->intersect(anEdge2);
165       if (!anInter.get()) {
166         continue;
167       }
168
169       bool isOk = false;
170
171       if (anInter->isVertex()) {
172         GeomVertexPtr aVertex(new GeomAPI_Vertex(anInter));
173         GeomPointPtr aPnt = aVertex->point();
174
175         GeomPointPtr aFirstPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
176                                   anEdge1->firstPoint() : anEdge1->lastPoint();
177         GeomPointPtr aLastPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
178                                  anEdge1->lastPoint() : anEdge1->firstPoint();
179         GeomPointPtr aFirstPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
180                                   anEdge2->firstPoint() : anEdge2->lastPoint();
181         GeomPointPtr aLastPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
182                                  anEdge2->lastPoint() : anEdge2->firstPoint();
183
184         GeomPointPtr aCommonEndPnt;
185         if (aFirstPnt1->isEqual(aLastPnt2)) {
186           aCommonEndPnt = aFirstPnt1;
187         } else if(aLastPnt1->isEqual(aFirstPnt2)) {
188           aCommonEndPnt = aLastPnt1;
189         }
190
191         isOk = aCommonEndPnt && aPnt->isEqual(aCommonEndPnt);
192       }
193
194       if (!isOk) {
195         return true;
196       }
197     }
198   }
199
200   return false;
201 }