1 // Copyright (C) 2014-2020 CEA/DEN, EDF R&D
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.
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.
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
17 // See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
20 #include "GeomAlgoAPI_WireBuilder.h"
22 #include <GeomAPI_Edge.h>
23 #include <GeomAPI_Pnt.h>
24 #include <GeomAPI_Vertex.h>
25 #include <GeomAPI_ShapeExplorer.h>
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>
34 #include <TopoDS_Wire.hxx>
36 #include <TopExp_Explorer.hxx>
46 bool operator() (const double d1, const double d2) const {
47 return d1 + Precision::Confusion() < d2;
51 typedef std::map<double, std::set<double, DoubleCompare>, DoubleCompare> ParamMap;
52 std::map<Handle(Geom_Curve), ParamMap> myShapes;
55 bool add(const TopoDS_Shape& theEdge)
57 const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge);
62 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
65 std::map<Handle(Geom_Curve), ParamMap>::iterator
66 aFound = myShapes.find(aCurve);
67 if (aFound == myShapes.end())
68 myShapes[aCurve][aFirst].insert(aLast);
70 ParamMap::iterator aFoundPar = aFound->second.find(aFirst);
71 if (aFoundPar == aFound->second.end())
72 aFound->second[aFirst].insert(aLast);
73 else if (aFoundPar->second.find(aLast) == aFoundPar->second.end())
74 aFoundPar->second.insert(aLast);
81 static bool isEqual(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2)
83 const TopoDS_Edge& anEdge1 = TopoDS::Edge(theShape1);
84 const TopoDS_Edge& anEdge2 = TopoDS::Edge(theShape2);
85 if (anEdge1.IsNull() || anEdge2.IsNull())
88 double aFirst1, aLast1;
89 Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aFirst1, aLast1);
90 double aFirst2, aLast2;
91 Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aFirst2, aLast2);
92 return aCurve1 == aCurve2 && fabs(aFirst1 - aFirst2) < Precision::Confusion() &&
93 fabs(aLast1 - aLast2) < Precision::Confusion();
97 static GeomShapePtr fromTopoDS(const TopoDS_Shape& theShape)
99 GeomShapePtr aResultShape(new GeomAPI_Shape());
100 aResultShape->setImpl(new TopoDS_Shape(theShape));
104 GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
105 const bool theForceOpenWire)
107 TopTools_ListOfShape aListOfEdges;
108 SetOfEdges aProcessedEdges;
110 ListOfShape::const_iterator anIt = theShapes.cbegin();
111 for (; anIt != theShapes.cend(); ++anIt) {
112 TopoDS_Shape aShape = (*anIt)->impl<TopoDS_Shape>();
113 switch(aShape.ShapeType()) {
115 aShape.Orientation(TopAbs_FORWARD);
116 if (aProcessedEdges.add(aShape))
117 aListOfEdges.Append(aShape);
121 for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) {
122 TopoDS_Shape anEdge = anExp.Current();
123 anEdge.Orientation(TopAbs_FORWARD);
124 // if the edge was already processed, remove it to keep original order of the current wire
125 if (!aProcessedEdges.add(anEdge)) {
126 for (TopTools_ListIteratorOfListOfShape aEIt(aListOfEdges); aEIt.More(); aEIt.Next())
127 if (SetOfEdges::isEqual(anEdge, aEIt.Value())) {
128 aListOfEdges.Remove(aEIt);
132 aListOfEdges.Append(anEdge);
141 bool isSplitWire = false;
143 if (theForceOpenWire && aListOfEdges.Size() > 1) {
144 // find a vertex to split the wire
146 TopExp::Vertices(TopoDS::Edge(aListOfEdges.First()), V1[0], V1[1]);
148 TopExp::Vertices(TopoDS::Edge(aListOfEdges.Last()), V2[0], V2[1]);
149 gp_Pnt P1[2] = { BRep_Tool::Pnt(V1[0]), BRep_Tool::Pnt(V1[1]) };
150 gp_Pnt P2[2] = { BRep_Tool::Pnt(V2[0]), BRep_Tool::Pnt(V2[1]) };
151 double Tol1[2] = { BRep_Tool::Tolerance(V1[0]), BRep_Tool::Tolerance(V1[1]) };
152 double Tol2[2] = { BRep_Tool::Tolerance(V2[0]), BRep_Tool::Tolerance(V2[1]) };
153 for (int i = 0; i < 2 && !isSplitWire; ++i)
154 for (int j = 0; j < 2 && !isSplitWire; ++j)
155 if (P1[i].Distance(P2[j]) < Max(Tol1[i], Tol2[j])) {
161 BRepBuilderAPI_MakeWire* aWireBuilder = new BRepBuilderAPI_MakeWire;
162 aWireBuilder->Add(aListOfEdges);
163 if (aWireBuilder->Error() == BRepBuilderAPI_WireDone) {
164 setImpl(aWireBuilder);
165 setBuilderType(OCCT_BRepBuilderAPI_MakeShape);
167 // split the result wire
168 TopoDS_Wire aWire = aWireBuilder->Wire();
169 if (isSplitWire && BRep_Tool::IsClosed(aWire)) {
170 TopoDS_Wire aNewWire;
171 BRep_Builder aBuilder;
172 aBuilder.MakeWire(aNewWire);
173 for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
174 TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
176 bool isToReshape = false;
177 BRepTools_ReShape aReshape;
178 TopoDS_Vertex aVF, aVL;
179 TopExp::Vertices(aNewCurrent, aVF, aVL);
180 gp_Pnt aPF = BRep_Tool::Pnt(aVF);
181 double aTolF = BRep_Tool::Tolerance(aVF);
182 gp_Pnt aPL = BRep_Tool::Pnt(aVL);
183 double aTolL = BRep_Tool::Tolerance(aVL);
184 if (aSplitPoint.SquareDistance(aPF) < aTolF * aTolF) {
185 aReshape.Replace(aVF, aReshape.CopyVertex(aVF));
188 else if (aSplitPoint.SquareDistance(aPL) < aTolL * aTolL) {
189 aReshape.Replace(aVL, aReshape.CopyVertex(aVL));
193 aNewCurrent = TopoDS::Edge(aReshape.Apply(aNewCurrent));
194 isSplitWire = false; // no need to continue splitting
197 aBuilder.Add(aNewWire, aNewCurrent);
202 // store generated/modified shapes
203 for (TopTools_ListOfShape::Iterator aBaseIt(aListOfEdges); aBaseIt.More(); aBaseIt.Next()) {
204 TopoDS_Edge aBaseCurrent = TopoDS::Edge(aBaseIt.Value());
205 Standard_Real aFirst, aLast;
206 Handle(Geom_Curve) aBaseCurve = BRep_Tool::Curve(aBaseCurrent, aFirst, aLast);
208 for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) {
209 TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current());
210 Handle(Geom_Curve) aNewCurve = BRep_Tool::Curve(aNewCurrent, aFirst, aLast);
211 if (aBaseCurve == aNewCurve) {
212 GeomShapePtr aBaseShape = fromTopoDS(aBaseCurrent);
213 GeomShapePtr aNewShape = fromTopoDS(aNewCurrent);
214 addGenerated(aBaseShape, aNewShape);
215 addModified(aBaseShape, aNewShape);
220 setShape(fromTopoDS(aWire));
225 //=================================================================================================
226 GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
228 return GeomAlgoAPI_WireBuilder(theShapes).shape();
231 //=================================================================================================
232 bool GeomAlgoAPI_WireBuilder::isSelfIntersected(const GeomShapePtr& theWire)
237 GeomAPI_ShapeExplorer anExp(theWire, GeomAPI_Shape::EDGE);
238 for (; anExp.more(); anExp.next()) {
239 GeomShapePtr anEdge = anExp.current();
240 anEdges.push_back(anEdge);
243 // Check intersections between edges pair-wise
244 std::list<GeomShapePtr>::const_iterator anEdgesIt = anEdges.begin();
245 for (int i = 0; anEdgesIt != anEdges.end(); ++anEdgesIt, i++) {
246 GeomEdgePtr anEdge1(new GeomAPI_Edge(*anEdgesIt));
248 std::list<GeomShapePtr>::const_iterator anOtherEdgesIt = std::next(anEdgesIt);
249 for (int j = i + 1; anOtherEdgesIt != anEdges.end(); ++anOtherEdgesIt, j++) {
250 GeomEdgePtr anEdge2(new GeomAPI_Edge(*anOtherEdgesIt));
251 GeomShapePtr anInter = anEdge1->intersect(anEdge2);
252 if (!anInter.get()) {
258 if (anInter->isVertex()) {
259 GeomVertexPtr aVertex(new GeomAPI_Vertex(anInter));
260 GeomPointPtr aPnt = aVertex->point();
262 GeomPointPtr aFirstPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
263 anEdge1->firstPoint() : anEdge1->lastPoint();
264 GeomPointPtr aLastPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ?
265 anEdge1->lastPoint() : anEdge1->firstPoint();
266 GeomPointPtr aFirstPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
267 anEdge2->firstPoint() : anEdge2->lastPoint();
268 GeomPointPtr aLastPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ?
269 anEdge2->lastPoint() : anEdge2->firstPoint();
271 GeomPointPtr aCommonEndPnt;
272 if (aFirstPnt1->isEqual(aLastPnt2)) {
273 aCommonEndPnt = aFirstPnt1;
274 } else if(aLastPnt1->isEqual(aFirstPnt2)) {
275 aCommonEndPnt = aLastPnt1;
278 isOk = aCommonEndPnt && aPnt->isEqual(aCommonEndPnt);