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>
37 #include <ShapeFix_Wire.hxx>
47 bool operator() (const double d1, const double d2) const {
48 return d1 + Precision::Confusion() < d2;
52 typedef std::map<double, std::set<double, DoubleCompare>, DoubleCompare> ParamMap;
53 std::map<Handle(Geom_Curve), ParamMap> myShapes;
56 bool add(const TopoDS_Shape& theEdge)
58 const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge);
63 Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast);
66 std::map<Handle(Geom_Curve), ParamMap>::iterator
67 aFound = myShapes.find(aCurve);
68 if (aFound == myShapes.end())
69 myShapes[aCurve][aFirst].insert(aLast);
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);
82 static bool isEqual(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2)
84 const TopoDS_Edge& anEdge1 = TopoDS::Edge(theShape1);
85 const TopoDS_Edge& anEdge2 = TopoDS::Edge(theShape2);
86 if (anEdge1.IsNull() || anEdge2.IsNull())
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();
98 static GeomShapePtr fromTopoDS(const TopoDS_Shape& theShape)
100 GeomShapePtr aResultShape(new GeomAPI_Shape());
101 aResultShape->setImpl(new TopoDS_Shape(theShape));
105 GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes,
106 const bool theForceOpenWire)
108 TopTools_ListOfShape aListOfEdges;
109 SetOfEdges aProcessedEdges;
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()) {
116 aShape.Orientation(TopAbs_FORWARD);
117 if (aProcessedEdges.add(aShape))
118 aListOfEdges.Append(aShape);
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);
133 aListOfEdges.Append(anEdge);
142 bool isSplitWire = false;
144 if (theForceOpenWire && aListOfEdges.Size() > 1) {
145 // find a vertex to split the wire
147 TopExp::Vertices(TopoDS::Edge(aListOfEdges.First()), V1[0], V1[1]);
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])) {
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);
168 // fix edges order (bos #20546)
169 TopoDS_Wire aWire = aWireBuilder->Wire();
170 Handle(ShapeFix_Wire) aFW = new ShapeFix_Wire;
173 if (aFW->StatusReorder(ShapeExtend_DONE))
174 aWire = aFW->WireAPIMake();
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());
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));
196 else if (aSplitPoint.SquareDistance(aPL) < aTolL * aTolL) {
197 aReshape.Replace(aVL, aReshape.CopyVertex(aVL));
201 aNewCurrent = TopoDS::Edge(aReshape.Apply(aNewCurrent));
202 isSplitWire = false; // no need to continue splitting
205 aBuilder.Add(aNewWire, aNewCurrent);
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);
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);
228 setShape(fromTopoDS(aWire));
233 //=================================================================================================
234 GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes)
236 return GeomAlgoAPI_WireBuilder(theShapes).shape();
239 //=================================================================================================
240 bool GeomAlgoAPI_WireBuilder::isSelfIntersected(const GeomShapePtr& theWire)
245 GeomAPI_ShapeExplorer anExp(theWire, GeomAPI_Shape::EDGE);
246 for (; anExp.more(); anExp.next()) {
247 GeomShapePtr anEdge = anExp.current();
248 anEdges.push_back(anEdge);
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));
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()) {
266 if (anInter->isVertex()) {
267 GeomVertexPtr aVertex(new GeomAPI_Vertex(anInter));
268 GeomPointPtr aPnt = aVertex->point();
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();
279 GeomPointPtr aCommonEndPnt;
280 if (aFirstPnt1->isEqual(aLastPnt2)) {
281 aCommonEndPnt = aFirstPnt1;
282 } else if(aLastPnt1->isEqual(aFirstPnt2)) {
283 aCommonEndPnt = aLastPnt1;
286 isOk = aCommonEndPnt && aPnt->isEqual(aCommonEndPnt);