X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGeomAlgoAPI%2FGeomAlgoAPI_WireBuilder.cpp;h=9aab0b6f2b4e5ad40be470ee7da3c7db11112155;hb=06e7f5859095193fc7f498bd89a7d28009794f53;hp=a251c76a0455cc080b2c7157f5933c40acae6c17;hpb=a94fc319f2aa64b43c9a73b5ff7063923648faec;p=modules%2Fshaper.git diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_WireBuilder.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_WireBuilder.cpp index a251c76a0..9aab0b6f2 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_WireBuilder.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_WireBuilder.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2023 CEA, EDF // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public @@ -12,50 +12,277 @@ // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // -// See http://www.salome-platform.org/ or -// email : webmaster.salome@opencascade.com +// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com // #include "GeomAlgoAPI_WireBuilder.h" +#include +#include +#include +#include + +#include +#include #include +#include +#include +#include #include #include +#include #include -//================================================================================================= -std::shared_ptr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes) +#include +#include +#include + +class SetOfEdges +{ + class DoubleCompare { + public: + bool operator() (const double d1, const double d2) const { + return d1 + Precision::Confusion() < d2; + } + }; + + typedef std::map, DoubleCompare> ParamMap; + std::map myShapes; + +public: + bool add(const TopoDS_Shape& theEdge) + { + const TopoDS_Edge& anEdge = TopoDS::Edge(theEdge); + if (anEdge.IsNull()) + return true; + + double aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + + bool isAdded = true; + std::map::iterator + aFound = myShapes.find(aCurve); + if (aFound == myShapes.end()) + myShapes[aCurve][aFirst].insert(aLast); + else { + ParamMap::iterator aFoundPar = aFound->second.find(aFirst); + if (aFoundPar == aFound->second.end()) + aFound->second[aFirst].insert(aLast); + else if (aFoundPar->second.find(aLast) == aFoundPar->second.end()) + aFoundPar->second.insert(aLast); + else + isAdded = false; + } + return isAdded; + } + + static bool isEqual(const TopoDS_Shape& theShape1, const TopoDS_Shape& theShape2) + { + const TopoDS_Edge& anEdge1 = TopoDS::Edge(theShape1); + const TopoDS_Edge& anEdge2 = TopoDS::Edge(theShape2); + if (anEdge1.IsNull() || anEdge2.IsNull()) + return false; + + double aFirst1, aLast1; + Handle(Geom_Curve) aCurve1 = BRep_Tool::Curve(anEdge1, aFirst1, aLast1); + double aFirst2, aLast2; + Handle(Geom_Curve) aCurve2 = BRep_Tool::Curve(anEdge2, aFirst2, aLast2); + return aCurve1 == aCurve2 && fabs(aFirst1 - aFirst2) < Precision::Confusion() && + fabs(aLast1 - aLast2) < Precision::Confusion(); + } +}; + +static GeomShapePtr fromTopoDS(const TopoDS_Shape& theShape) +{ + GeomShapePtr aResultShape(new GeomAPI_Shape()); + aResultShape->setImpl(new TopoDS_Shape(theShape)); + return aResultShape; +} + +GeomAlgoAPI_WireBuilder::GeomAlgoAPI_WireBuilder(const ListOfShape& theShapes, + const bool theForceOpenWire) { TopTools_ListOfShape aListOfEdges; + SetOfEdges aProcessedEdges; - for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) { - const TopoDS_Shape& aShape = (*anIt)->impl(); + ListOfShape::const_iterator anIt = theShapes.cbegin(); + for (; anIt != theShapes.cend(); ++anIt) { + TopoDS_Shape aShape = (*anIt)->impl(); switch(aShape.ShapeType()) { case TopAbs_EDGE: { - aListOfEdges.Append(aShape); + aShape.Orientation(TopAbs_FORWARD); + if (aProcessedEdges.add(aShape)) + aListOfEdges.Append(aShape); break; } case TopAbs_WIRE: { - for(TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) { - aListOfEdges.Append(anExp.Current()); + for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) { + TopoDS_Shape anEdge = anExp.Current(); + anEdge.Orientation(TopAbs_FORWARD); + // if the edge was already processed, remove it to keep original order of the current wire + if (!aProcessedEdges.add(anEdge)) { + for (TopTools_ListIteratorOfListOfShape aEIt(aListOfEdges); aEIt.More(); aEIt.Next()) + if (SetOfEdges::isEqual(anEdge, aEIt.Value())) { + aListOfEdges.Remove(aEIt); + break; + } + } + aListOfEdges.Append(anEdge); } break; } - default: { - return GeomShapePtr(); - } + default: + break; } } - BRepBuilderAPI_MakeWire aWireBuilder; - aWireBuilder.Add(aListOfEdges); - if(aWireBuilder.Error() != BRepBuilderAPI_WireDone) { - return GeomShapePtr(); + bool isSplitWire = false; + gp_Pnt aSplitPoint; + if (theForceOpenWire && aListOfEdges.Size() > 1) { + // find a vertex to split the wire + TopoDS_Vertex V1[2]; + TopExp::Vertices(TopoDS::Edge(aListOfEdges.First()), V1[0], V1[1]); + TopoDS_Vertex V2[2]; + TopExp::Vertices(TopoDS::Edge(aListOfEdges.Last()), V2[0], V2[1]); + gp_Pnt P1[2] = { BRep_Tool::Pnt(V1[0]), BRep_Tool::Pnt(V1[1]) }; + gp_Pnt P2[2] = { BRep_Tool::Pnt(V2[0]), BRep_Tool::Pnt(V2[1]) }; + double Tol1[2] = { BRep_Tool::Tolerance(V1[0]), BRep_Tool::Tolerance(V1[1]) }; + double Tol2[2] = { BRep_Tool::Tolerance(V2[0]), BRep_Tool::Tolerance(V2[1]) }; + for (int i = 0; i < 2 && !isSplitWire; ++i) + for (int j = 0; j < 2 && !isSplitWire; ++j) + if (P1[i].Distance(P2[j]) < Max(Tol1[i], Tol2[j])) { + aSplitPoint = P1[i]; + isSplitWire = true; + } } - GeomShapePtr aResultShape(new GeomAPI_Shape()); - aResultShape->setImpl(new TopoDS_Shape(aWireBuilder.Wire())); - return aResultShape; + BRepBuilderAPI_MakeWire* aWireBuilder = new BRepBuilderAPI_MakeWire; + aWireBuilder->Add(aListOfEdges); + if (aWireBuilder->Error() == BRepBuilderAPI_WireDone) { + setImpl(aWireBuilder); + setBuilderType(OCCT_BRepBuilderAPI_MakeShape); + + // split the result wire + TopoDS_Wire aWire = aWireBuilder->Wire(); + if (isSplitWire && BRep_Tool::IsClosed(aWire)) { + TopoDS_Wire aNewWire; + BRep_Builder aBuilder; + aBuilder.MakeWire(aNewWire); + for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) { + TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current()); + if (isSplitWire) { + bool isToReshape = false; + BRepTools_ReShape aReshape; + TopoDS_Vertex aVF, aVL; + TopExp::Vertices(aNewCurrent, aVF, aVL); + gp_Pnt aPF = BRep_Tool::Pnt(aVF); + double aTolF = BRep_Tool::Tolerance(aVF); + gp_Pnt aPL = BRep_Tool::Pnt(aVL); + double aTolL = BRep_Tool::Tolerance(aVL); + if (aSplitPoint.SquareDistance(aPF) < aTolF * aTolF) { + aReshape.Replace(aVF, aReshape.CopyVertex(aVF)); + isToReshape = true; + } + else if (aSplitPoint.SquareDistance(aPL) < aTolL * aTolL) { + aReshape.Replace(aVL, aReshape.CopyVertex(aVL)); + isToReshape = true; + } + if (isToReshape) { + aNewCurrent = TopoDS::Edge(aReshape.Apply(aNewCurrent)); + isSplitWire = false; // no need to continue splitting + } + } + aBuilder.Add(aNewWire, aNewCurrent); + } + aWire = aNewWire; + } + + // store generated/modified shapes + for (TopTools_ListOfShape::Iterator aBaseIt(aListOfEdges); aBaseIt.More(); aBaseIt.Next()) { + TopoDS_Edge aBaseCurrent = TopoDS::Edge(aBaseIt.Value()); + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aBaseCurve = BRep_Tool::Curve(aBaseCurrent, aFirst, aLast); + + for (TopExp_Explorer anExp(aWire, TopAbs_EDGE); anExp.More(); anExp.Next()) { + TopoDS_Edge aNewCurrent = TopoDS::Edge(anExp.Current()); + Handle(Geom_Curve) aNewCurve = BRep_Tool::Curve(aNewCurrent, aFirst, aLast); + if (aBaseCurve == aNewCurve) { + GeomShapePtr aBaseShape = fromTopoDS(aBaseCurrent); + GeomShapePtr aNewShape = fromTopoDS(aNewCurrent); + addGenerated(aBaseShape, aNewShape); + addModified(aBaseShape, aNewShape); + } + } + } + + setShape(fromTopoDS(aWire)); + setDone(true); + } } + +//================================================================================================= +GeomShapePtr GeomAlgoAPI_WireBuilder::wire(const ListOfShape& theShapes) +{ + return GeomAlgoAPI_WireBuilder(theShapes).shape(); +} + +//================================================================================================= +bool GeomAlgoAPI_WireBuilder::isSelfIntersected(const GeomShapePtr& theWire) +{ + // Collect edges. + ListOfShape anEdges; + + GeomAPI_ShapeExplorer anExp(theWire, GeomAPI_Shape::EDGE); + for (; anExp.more(); anExp.next()) { + GeomShapePtr anEdge = anExp.current(); + anEdges.push_back(anEdge); + } + + // Check intersections between edges pair-wise + std::list::const_iterator anEdgesIt = anEdges.begin(); + for (int i = 0; anEdgesIt != anEdges.end(); ++anEdgesIt, i++) { + GeomEdgePtr anEdge1(new GeomAPI_Edge(*anEdgesIt)); + + std::list::const_iterator anOtherEdgesIt = std::next(anEdgesIt); + for (int j = i + 1; anOtherEdgesIt != anEdges.end(); ++anOtherEdgesIt, j++) { + GeomEdgePtr anEdge2(new GeomAPI_Edge(*anOtherEdgesIt)); + GeomShapePtr anInter = anEdge1->intersect(anEdge2); + if (!anInter.get()) { + continue; + } + + bool isOk = false; + + if (anInter->isVertex()) { + GeomVertexPtr aVertex(new GeomAPI_Vertex(anInter)); + GeomPointPtr aPnt = aVertex->point(); + + GeomPointPtr aFirstPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ? + anEdge1->firstPoint() : anEdge1->lastPoint(); + GeomPointPtr aLastPnt1 = anEdge1->orientation() == GeomAPI_Shape::FORWARD ? + anEdge1->lastPoint() : anEdge1->firstPoint(); + GeomPointPtr aFirstPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ? + anEdge2->firstPoint() : anEdge2->lastPoint(); + GeomPointPtr aLastPnt2 = anEdge2->orientation() == GeomAPI_Shape::FORWARD ? + anEdge2->lastPoint() : anEdge2->firstPoint(); + + GeomPointPtr aCommonEndPnt; + if (aFirstPnt1->isEqual(aLastPnt2)) { + aCommonEndPnt = aFirstPnt1; + } else if(aLastPnt1->isEqual(aFirstPnt2)) { + aCommonEndPnt = aLastPnt1; + } + + isOk = aCommonEndPnt && aPnt->isEqual(aCommonEndPnt); + } + + if (!isOk) { + return true; + } + } + } + + return false; +} \ No newline at end of file