]> SALOME platform Git repositories - modules/shaper.git/blob - src/GeomAlgoAPI/GeomAlgoAPI_WireBuilder.cpp
Salome HOME
bos #20546: EDF 22644 - Offset not closed.
[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_Builder.hxx>
28 #include <BRep_Tool.hxx>
29 #include <BRepBuilderAPI_MakeWire.hxx>
30 #include <BRepTools_ReShape.hxx>
31 #include <Geom_Curve.hxx>
32 #include <Precision.hxx>
33 #include <TopoDS.hxx>
34 #include <TopoDS_Wire.hxx>
35 #include <TopExp.hxx>
36 #include <TopExp_Explorer.hxx>
37 #include <ShapeFix_Wire.hxx>
38
39 #include <cmath>
40 #include <map>
41 #include <set>
42
43 class SetOfEdges
44 {
45   class DoubleCompare {
46   public:
47     bool operator() (const double d1, const double d2) const {
48       return d1 + Precision::Confusion() < d2;
49     }
50   };
51
52   typedef std::map<double, std::set<double, DoubleCompare>, DoubleCompare> ParamMap;
53   std::map<Handle(Geom_Curve), ParamMap> myShapes;
54
55 public:
56   bool add(const TopoDS_Shape& theEdge)
57   {
58     const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge);
59     if (anEdge.IsNull())
60       return true;
61
62     double aFirst, aLast;
63     Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
64
65     bool isAdded = true;
66     std::map<Handle(Geom_Curve), ParamMap>::iterator
67         aFound = myShapes.find(aCurve);
68     if (aFound == myShapes.end())
69       myShapes[aCurve][aFirst].insert(aLast);
70     else {
71       ParamMap::iterator aFoundPar = aFound->second.find(aFirst);
72       if (aFoundPar == aFound->second.end())
73         aFound->second[aFirst].insert(aLast);
74       else if (aFoundPar->second.find(aLast) == aFoundPar->second.end())
75         aFoundPar->second.insert(aLast);
76       else
77         isAdded = false;
78     }
79     return isAdded;
80   }
81
82   static bool isEqual(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2)
83   {
84     const TopoDS_Edge& anEdge1 = TopoDS::Edge(theShape1);
85     const TopoDS_Edge& anEdge2 = TopoDS::Edge(theShape2);
86     if (anEdge1.IsNull() || anEdge2.IsNull())
87       return false;
88
89     double aFirst1, aLast1;
90     Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aFirst1, aLast1);
91     double aFirst2, aLast2;
92     Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aFirst2, aLast2);
93     return aCurve1 == aCurve2 && fabs(aFirst1 - aFirst2) < Precision::Confusion() &&
94                                  fabs(aLast1 - aLast2) < Precision::Confusion();
95   }
96 };
97
98 static GeomShapePtr fromTopoDS(const TopoDS_Shape& theShape)
99 {
100   GeomShapePtr aResultShape(new GeomAPI_Shape());
101   aResultShape->setImpl(new TopoDS_Shape(theShape));
102   return aResultShape;
103 }
104
105 GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
106                                                  const bool theForceOpenWire)
107 {
108   TopTools_ListOfShape aListOfEdges;
109   SetOfEdges aProcessedEdges;
110
111   ListOfShape::const_iterator anIt = theShapes.cbegin();
112   for (; anIt != theShapes.cend(); ++anIt) {
113     TopoDS_Shape aShape = (*anIt)->impl<TopoDS_Shape>();
114     switch(aShape.ShapeType()) {
115       case TopAbs_EDGE: {
116         aShape.Orientation(TopAbs_FORWARD);
117         if (aProcessedEdges.add(aShape))
118           aListOfEdges.Append(aShape);
119         break;
120       }
121       case TopAbs_WIRE: {
122         for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
123           TopoDS_Shape anEdge = anExp.Current();
124           anEdge.Orientation(TopAbs_FORWARD);
125           // if the edge was already processed, remove it to keep original order of the current wire
126           if (!aProcessedEdges.add(anEdge)) {
127             for (TopTools_ListIteratorOfListOfShape aEIt(aListOfEdges); aEIt.More(); aEIt.Next())
128               if (SetOfEdges::isEqual(anEdge, aEIt.Value())) {
129                 aListOfEdges.Remove(aEIt);
130                 break;
131               }
132           }
133           aListOfEdges.Append(anEdge);
134         }
135         break;
136       }
137     default:
138       break;
139     }
140   }
141
142   bool isSplitWire = false;
143   gp_Pnt aSplitPoint;
144   if (theForceOpenWire && aListOfEdges.Size() > 1) {
145     // find a vertex to split the wire
146     TopoDS_Vertex V1[2];
147     TopExp::Vertices(TopoDS::Edge(aListOfEdges.First()), V1[0], V1[1]);
148     TopoDS_Vertex V2[2];
149     TopExp::Vertices(TopoDS::Edge(aListOfEdges.Last()), V2[0], V2[1]);
150     gp_Pnt P1[2] = { BRep_Tool::Pnt(V1[0]), BRep_Tool::Pnt(V1[1]) };
151     gp_Pnt P2[2] = { BRep_Tool::Pnt(V2[0]), BRep_Tool::Pnt(V2[1]) };
152     double Tol1[2] = { BRep_Tool::Tolerance(V1[0]), BRep_Tool::Tolerance(V1[1]) };
153     double Tol2[2] = { BRep_Tool::Tolerance(V2[0]), BRep_Tool::Tolerance(V2[1]) };
154     for (int i = 0; i < 2 && !isSplitWire; ++i)
155       for (int j = 0; j < 2 && !isSplitWire; ++j)
156         if (P1[i].Distance(P2[j]) < Max(Tol1[i], Tol2[j])) {
157           aSplitPoint = P1[i];
158           isSplitWire = true;
159         }
160   }
161
162   BRepBuilderAPI_MakeWire* aWireBuilder = new BRepBuilderAPI_MakeWire;
163   aWireBuilder->Add(aListOfEdges);
164   if (aWireBuilder->Error() == BRepBuilderAPI_WireDone) {
165     setImpl(aWireBuilder);
166     setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
167
168     // fix edges order (bos #20546)
169     TopoDS_Wire aWire = aWireBuilder->Wire();
170     Handle(ShapeFix_Wire) aFW = new ShapeFix_Wire;
171     aFW->Load(aWire);
172     aFW->FixReorder();
173     if (aFW->StatusReorder(ShapeExtend_DONE))
174       aWire = aFW->WireAPIMake();
175
176     // split the result wire
177     if (isSplitWire && BRep_Tool::IsClosed(aWire)) {
178       TopoDS_Wire aNewWire;
179       BRep_Builder aBuilder;
180       aBuilder.MakeWire(aNewWire);
181       for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
182         TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
183         if (isSplitWire) {
184           bool isToReshape = false;
185           BRepTools_ReShape aReshape;
186           TopoDS_Vertex aVF, aVL;
187           TopExp::Vertices(aNewCurrent, aVF, aVL);
188           gp_Pnt aPF = BRep_Tool::Pnt(aVF);
189           double aTolF = BRep_Tool::Tolerance(aVF);
190           gp_Pnt aPL = BRep_Tool::Pnt(aVL);
191           double aTolL = BRep_Tool::Tolerance(aVL);
192           if (aSplitPoint.SquareDistance(aPF) < aTolF * aTolF) {
193             aReshape.Replace(aVF, aReshape.CopyVertex(aVF));
194             isToReshape = true;
195           }
196           else if (aSplitPoint.SquareDistance(aPL) < aTolL * aTolL) {
197             aReshape.Replace(aVL, aReshape.CopyVertex(aVL));
198             isToReshape = true;
199           }
200           if (isToReshape) {
201             aNewCurrent = TopoDS::Edge(aReshape.Apply(aNewCurrent));
202             isSplitWire = false; // no need to continue splitting
203           }
204         }
205         aBuilder.Add(aNewWire, aNewCurrent);
206       }
207       aWire = aNewWire;
208     }
209
210     // store generated/modified shapes
211     for (TopTools_ListOfShape::Iterator aBaseIt(aListOfEdges); aBaseIt.More(); aBaseIt.Next()) {
212       TopoDS_Edge aBaseCurrent = TopoDS::Edge(aBaseIt.Value());
213       Standard_Real aFirst, aLast;
214       Handle(Geom_Curve) aBaseCurve = BRep_Tool::Curve(aBaseCurrent, aFirst, aLast);
215
216       for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
217         TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
218         Handle(Geom_Curve) aNewCurve = BRep_Tool::Curve(aNewCurrent, aFirst, aLast);
219         if (aBaseCurve == aNewCurve) {
220           GeomShapePtr aBaseShape = fromTopoDS(aBaseCurrent);
221           GeomShapePtr aNewShape = fromTopoDS(aNewCurrent);
222           addGenerated(aBaseShape, aNewShape);
223           addModified(aBaseShape, aNewShape);
224         }
225       }
226     }
227
228     setShape(fromTopoDS(aWire));
229     setDone(true);
230   }
231 }
232
233 //=================================================================================================
234 GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
235 {
236   return GeomAlgoAPI_WireBuilder(theShapes).shape();
237 }
238
239 //=================================================================================================
240 bool GeomAlgoAPI_WireBuilder::isSelfIntersected(const GeomShapePtr& theWire)
241 {
242   // Collect edges.
243   ListOfShape anEdges;
244
245   GeomAPI_ShapeExplorer anExp(theWire, GeomAPI_Shape::EDGE);
246   for (; anExp.more(); anExp.next()) {
247     GeomShapePtr anEdge = anExp.current();
248     anEdges.push_back(anEdge);
249   }
250
251   // Check intersections between edges pair-wise
252   std::list<GeomShapePtr>::const_iterator anEdgesIt = anEdges.begin();
253   for (int i = 0; anEdgesIt != anEdges.end(); ++anEdgesIt, i++) {
254     GeomEdgePtr anEdge1(new GeomAPI_Edge(*anEdgesIt));
255
256     std::list<GeomShapePtr>::const_iterator anOtherEdgesIt = std::next(anEdgesIt);
257     for (int j = i + 1; anOtherEdgesIt != anEdges.end(); ++anOtherEdgesIt, j++) {
258       GeomEdgePtr anEdge2(new GeomAPI_Edge(*anOtherEdgesIt));
259       GeomShapePtr anInter = anEdge1->intersect(anEdge2);
260       if (!anInter.get()) {
261         continue;
262       }
263
264       bool isOk = false;
265
266       if (anInter->isVertex()) {
267         GeomVertexPtr aVertex(new GeomAPI_Vertex(anInter));
268         GeomPointPtr aPnt = aVertex->point();
269
270         GeomPointPtr aFirstPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
271                                   anEdge1->firstPoint() : anEdge1->lastPoint();
272         GeomPointPtr aLastPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
273                                  anEdge1->lastPoint() : anEdge1->firstPoint();
274         GeomPointPtr aFirstPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
275                                   anEdge2->firstPoint() : anEdge2->lastPoint();
276         GeomPointPtr aLastPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
277                                  anEdge2->lastPoint() : anEdge2->firstPoint();
278
279         GeomPointPtr aCommonEndPnt;
280         if (aFirstPnt1->isEqual(aLastPnt2)) {
281           aCommonEndPnt = aFirstPnt1;
282         } else if(aLastPnt1->isEqual(aFirstPnt2)) {
283           aCommonEndPnt = aLastPnt1;
284         }
285
286         isOk = aCommonEndPnt && aPnt->isEqual(aCommonEndPnt);
287       }
288
289       if (!isOk) {
290         return true;
291       }
292     }
293   }
294
295   return false;
296 }