Salome HOME
Get rid of compilation warnings. Part II. MSVC warnings.
[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 aEIt(aListOfEdges); aEIt.More(); aEIt.Next())
117               if (SetOfEdges::isEqual(anEdge, aEIt.Value())) {
118                 aListOfEdges.Remove(aEIt);
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   std::list<GeomShapePtr>::const_iterator anEdgesIt = anEdges.begin();
157   for (int i = 0; anEdgesIt != anEdges.end(); ++anEdgesIt, i++) {
158     GeomEdgePtr anEdge1(new GeomAPI_Edge(*anEdgesIt));
159
160     std::list<GeomShapePtr>::const_iterator anOtherEdgesIt = std::next(anEdgesIt);
161     for (int j = i + 1; anOtherEdgesIt != anEdges.end(); ++anOtherEdgesIt, j++) {
162       GeomEdgePtr anEdge2(new GeomAPI_Edge(*anOtherEdgesIt));
163       GeomShapePtr anInter = anEdge1->intersect(anEdge2);
164       if (!anInter.get()) {
165         continue;
166       }
167
168       bool isOk = false;
169
170       if (anInter->isVertex()) {
171         GeomVertexPtr aVertex(new GeomAPI_Vertex(anInter));
172         GeomPointPtr aPnt = aVertex->point();
173
174         GeomPointPtr aFirstPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
175                                   anEdge1->firstPoint() : anEdge1->lastPoint();
176         GeomPointPtr aLastPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
177                                  anEdge1->lastPoint() : anEdge1->firstPoint();
178         GeomPointPtr aFirstPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
179                                   anEdge2->firstPoint() : anEdge2->lastPoint();
180         GeomPointPtr aLastPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
181                                  anEdge2->lastPoint() : anEdge2->firstPoint();
182
183         GeomPointPtr aCommonEndPnt;
184         if (aFirstPnt1->isEqual(aLastPnt2)) {
185           aCommonEndPnt = aFirstPnt1;
186         } else if(aLastPnt1->isEqual(aFirstPnt2)) {
187           aCommonEndPnt = aLastPnt1;
188         }
189
190         isOk = aCommonEndPnt && aPnt->isEqual(aCommonEndPnt);
191       }
192
193       if (!isOk) {
194         return true;
195       }
196     }
197   }
198
199   return false;
200 }