Salome HOME
Task #3231: Sketcher Offset of a curve.
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_WireBuilder.cpp
1 // Copyright (C) 2014-2019  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 <TopoDS.hxx>
33 #include <TopoDS_Wire.hxx>
34 #include <TopExp.hxx>
35 #include <TopExp_Explorer.hxx>
36
37 static GeomShapePtr fromTopoDS(const TopoDS_Shape& theShape)
38 {
39   GeomShapePtr aResultShape(new GeomAPI_Shape());
40   aResultShape->setImpl(new TopoDS_Shape(theShape));
41   return aResultShape;
42 }
43
44 GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
45                                                  const bool theForceOpenWire)
46 {
47   TopTools_ListOfShape aListOfEdges;
48
49   ListOfShape::const_iterator anIt = theShapes.cbegin();
50   for (; anIt != theShapes.cend(); ++anIt) {
51     const TopoDS_Shape& aShape = (*anIt)->impl<TopoDS_Shape>();
52     switch (aShape.ShapeType()) {
53     case TopAbs_EDGE: {
54       aListOfEdges.Append(aShape);
55       break;
56     }
57     case TopAbs_WIRE: {
58       for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
59         aListOfEdges.Append(anExp.Current());
60       }
61       break;
62     }
63     default:
64       break;
65     }
66   }
67
68   bool isSplitWire = false;
69   gp_Pnt aSplitPoint;
70   if (theForceOpenWire) {
71     // find a vertex to split the wire
72     TopoDS_Vertex V1[2];
73     TopExp::Vertices(TopoDS::Edge(aListOfEdges.First()), V1[0], V1[1]);
74     TopoDS_Vertex V2[2];
75     TopExp::Vertices(TopoDS::Edge(aListOfEdges.Last()), V2[0], V2[1]);
76     gp_Pnt P1[2] = { BRep_Tool::Pnt(V1[0]), BRep_Tool::Pnt(V1[1]) };
77     gp_Pnt P2[2] = { BRep_Tool::Pnt(V2[0]), BRep_Tool::Pnt(V2[1]) };
78     double Tol1[2] = { BRep_Tool::Tolerance(V1[0]), BRep_Tool::Tolerance(V1[1]) };
79     double Tol2[2] = { BRep_Tool::Tolerance(V2[0]), BRep_Tool::Tolerance(V2[1]) };
80     for (int i = 0; i < 2 && !isSplitWire; ++i)
81       for (int j = 0; j < 2 && !isSplitWire; ++j)
82         if (P1[i].Distance(P2[i]) < Max(Tol1[i], Tol2[j])) {
83           aSplitPoint = P1[i];
84           isSplitWire = true;
85         }
86   }
87
88   BRepBuilderAPI_MakeWire* aWireBuilder = new BRepBuilderAPI_MakeWire;
89   aWireBuilder->Add(aListOfEdges);
90   if (aWireBuilder->Error() == BRepBuilderAPI_WireDone) {
91     setImpl(aWireBuilder);
92     setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
93
94     // split the result wire
95     TopoDS_Wire aWire = aWireBuilder->Wire();
96     if (isSplitWire && BRep_Tool::IsClosed(aWire)) {
97       TopoDS_Wire aNewWire;
98       BRep_Builder aBuilder;
99       aBuilder.MakeWire(aNewWire);
100       for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
101         TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
102         if (isSplitWire) {
103           bool isToReshape = false;
104           BRepTools_ReShape aReshape;
105           TopoDS_Vertex aVF, aVL;
106           TopExp::Vertices(aNewCurrent, aVF, aVL);
107           gp_Pnt aPF = BRep_Tool::Pnt(aVF);
108           double aTolF = BRep_Tool::Tolerance(aVF);
109           gp_Pnt aPL = BRep_Tool::Pnt(aVL);
110           double aTolL = BRep_Tool::Tolerance(aVL);
111           if (aSplitPoint.SquareDistance(aPF) < aTolF * aTolF) {
112             aReshape.Replace(aVF, aReshape.CopyVertex(aVF));
113             isToReshape = true;
114           }
115           else if (aSplitPoint.SquareDistance(aPL) < aTolL * aTolL) {
116             aReshape.Replace(aVL, aReshape.CopyVertex(aVL));
117             isToReshape = true;
118           }
119           if (isToReshape) {
120             aNewCurrent = TopoDS::Edge(aReshape.Apply(aNewCurrent));
121             isSplitWire = false; // no need to continue splitting
122           }
123         }
124         aBuilder.Add(aNewWire, aNewCurrent);
125       }
126       aWire = aNewWire;
127     }
128
129     // store generated/modified shapes
130     for (TopTools_ListOfShape::Iterator aBaseIt(aListOfEdges); aBaseIt.More(); aBaseIt.Next()) {
131       TopoDS_Edge aBaseCurrent = TopoDS::Edge(aBaseIt.Value());
132       Standard_Real aFirst, aLast;
133       Handle(Geom_Curve) aBaseCurve = BRep_Tool::Curve(aBaseCurrent, aFirst, aLast);
134
135       for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
136         TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
137         Handle(Geom_Curve) aNewCurve = BRep_Tool::Curve(aNewCurrent, aFirst, aLast);
138         if (aBaseCurve == aNewCurve) {
139           GeomShapePtr aBaseShape = fromTopoDS(aBaseCurrent);
140           GeomShapePtr aNewShape = fromTopoDS(aNewCurrent);
141           addGenerated(aBaseShape, aNewShape);
142           addModified(aBaseShape, aNewShape);
143         }
144       }
145     }
146
147     setShape(fromTopoDS(aWire));
148     setDone(true);
149   }
150 }
151
152 //=================================================================================================
153 GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
154 {
155   return GeomAlgoAPI_WireBuilder(theShapes).shape();
156 }
157
158 //=================================================================================================
159 bool GeomAlgoAPI_WireBuilder::isSelfIntersected(const GeomShapePtr& theWire)
160 {
161   // Collect edges.
162   ListOfShape anEdges;
163
164   GeomAPI_ShapeExplorer anExp(theWire, GeomAPI_Shape::EDGE);
165   for (; anExp.more(); anExp.next()) {
166     GeomShapePtr anEdge = anExp.current();
167     anEdges.push_back(anEdge);
168   }
169
170   // Check intersections between edges pair-wise
171   int aNbEdges = (int)anEdges.size();
172   std::list<GeomShapePtr>::const_iterator anEdgesIt = anEdges.begin();
173   for (int i = 0; anEdgesIt != anEdges.end(); ++anEdgesIt, i++) {
174     GeomEdgePtr anEdge1(new GeomAPI_Edge(*anEdgesIt));
175
176     std::list<GeomShapePtr>::const_iterator anOtherEdgesIt = std::next(anEdgesIt);
177     for (int j = i + 1; anOtherEdgesIt != anEdges.end(); ++anOtherEdgesIt, j++) {
178       GeomEdgePtr anEdge2(new GeomAPI_Edge(*anOtherEdgesIt));
179       GeomShapePtr anInter = anEdge1->intersect(anEdge2);
180       if (!anInter.get()) {
181         continue;
182       }
183
184       bool isOk = false;
185
186       if (anInter->isVertex()) {
187         GeomVertexPtr aVertex(new GeomAPI_Vertex(anInter));
188         GeomPointPtr aPnt = aVertex->point();
189
190         GeomPointPtr aFirstPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
191                                   anEdge1->firstPoint() : anEdge1->lastPoint();
192         GeomPointPtr aLastPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
193                                  anEdge1->lastPoint() : anEdge1->firstPoint();
194         GeomPointPtr aFirstPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
195                                   anEdge2->firstPoint() : anEdge2->lastPoint();
196         GeomPointPtr aLastPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
197                                  anEdge2->lastPoint() : anEdge2->firstPoint();
198
199         GeomPointPtr aCommonEndPnt;
200         if (aFirstPnt1->isEqual(aLastPnt2)) {
201           aCommonEndPnt = aFirstPnt1;
202         } else if(aLastPnt1->isEqual(aFirstPnt2)) {
203           aCommonEndPnt = aLastPnt1;
204         }
205
206         isOk = aCommonEndPnt && aPnt->isEqual(aCommonEndPnt);
207       }
208
209       if (!isOk) {
210         return true;
211       }
212     }
213   }
214
215   return false;
216 }