X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGeomAlgoAPI%2FGeomAlgoAPI_ShapeTools.cpp;h=bd52d74d7734d34974f0acb2594fddb895dbab0f;hb=4c86b629d1bf8daa737f90b64e934c7bd22f6525;hp=fd854afb74009ba5ea90e2adfdfd31eeaece85ed;hpb=2714903267d23cd0c81166c506fb3edd1e069d40;p=modules%2Fshaper.git diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp index fd854afb7..bd52d74d7 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp @@ -1,4 +1,4 @@ -// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// Copyright (C) 2014-2024 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,96 +12,185 @@ // // 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_ShapeTools.h" #include "GeomAlgoAPI_SketchBuilder.h" +#include + #include #include #include #include #include #include +#include + +#include #include -#include + +#include #include -#include +#include #include +#include #include +#include #include #include #include +#include +#include #include #include #include +#include #include +#include #include +#include #include #include +#include +#include + +#include + +#include +#include +#include +#include +#include + #include #include -#include -#include + +#include +#include #include #include +#include + +#if OCC_VERSION_LARGE < 0x07070000 +#include +#else +#include +#endif + #include +#include + #include #include #include + #include #include + #include #include -#include + #include #include -#include + +#include #include #include #include #include #include -#include +#include + +#include #include + #include +#include -#include -#include -#include +#include +#include //================================================================================================== -double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr theShape) +static GProp_GProps props(const TopoDS_Shape& theShape) { GProp_GProps aGProps; - if(!theShape.get()) { + + if (theShape.ShapeType() == TopAbs_EDGE || theShape.ShapeType() == TopAbs_WIRE) + { + BRepGProp::LinearProperties(theShape, aGProps); + } + else if (theShape.ShapeType() == TopAbs_FACE || theShape.ShapeType() == TopAbs_SHELL) + { + const Standard_Real anEps = 1.e-6; + BRepGProp::SurfaceProperties(theShape, aGProps, anEps); + } + else if (theShape.ShapeType() == TopAbs_SOLID || theShape.ShapeType() == TopAbs_COMPSOLID) + { + BRepGProp::VolumeProperties(theShape, aGProps); + } + else if (theShape.ShapeType() == TopAbs_COMPOUND) + { + for (TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) + { + aGProps.Add(props(anIt.Value())); + } + } + + return aGProps; +} + +//================================================================================================== +double GeomAlgoAPI_ShapeTools::length(const std::shared_ptr theShape) +{ + GProp_GProps aGProps; + if (!theShape.get()) { + return 0.0; + } + const TopoDS_Shape& aShape = theShape->impl(); + if (aShape.IsNull()) { + return 0.0; + } + + BRepGProp::LinearProperties(aShape, aGProps, Standard_True); + return aGProps.Mass(); +} + +//================================================================================================== +double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr theShape) +{ + if (!theShape.get()) { return 0.0; } const TopoDS_Shape& aShape = theShape->impl(); - if(aShape.IsNull()) { + if (aShape.IsNull()) { return 0.0; } const Standard_Real anEps = 1.e-6; - BRepGProp::VolumeProperties(aShape, aGProps, anEps); - return aGProps.Mass(); + double aVolume = 0.0; + for (TopExp_Explorer anExp(aShape, TopAbs_SOLID); anExp.More(); anExp.Next()) { + GProp_GProps aGProps; + BRepGProp::VolumeProperties(anExp.Current(), aGProps, anEps); + aVolume += aGProps.Mass(); + } + return aVolume; } //================================================================================================== double GeomAlgoAPI_ShapeTools::area (const std::shared_ptr theShape) { GProp_GProps aGProps; - if(!theShape.get()) { + if (!theShape.get()) { return 0.0; } const TopoDS_Shape& aShape = theShape->impl(); - if(aShape.IsNull()) { + if (aShape.IsNull()) { return 0.0; } const Standard_Real anEps = 1.e-6; @@ -110,127 +199,577 @@ double GeomAlgoAPI_ShapeTools::area (const std::shared_ptr theSha return aGProps.Mass(); } +//================================================================================================== +bool GeomAlgoAPI_ShapeTools::isContinuousFaces(const GeomShapePtr& theFace1, + const GeomShapePtr& theFace2, + const GeomPointPtr& thePoint, + const double & theAngle, + std::string& theError) +{ + + #ifdef _DEBUG + std::cout << "isContinuousFaces " << std::endl; + #endif + + if (!thePoint.get()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + const gp_Pnt& aPoint = thePoint->impl(); + + // Getting base shape. + if (!theFace1.get()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + TopoDS_Shape aShape1 = theFace1->impl(); + + if (aShape1.IsNull()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + // Getting base shape. + if (!theFace2.get()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + TopoDS_Shape aShape2 = theFace2->impl(); + + if (aShape2.IsNull()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + TopoDS_Face aFace1 = TopoDS::Face(aShape1); + if (aFace1.IsNull()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + Handle(Geom_Surface) aSurf1 = BRep_Tool::Surface(aFace1); + if (aSurf1.IsNull()) { + theError = "isContinuousFaces : An invalid surface"; + return false; + } + + ShapeAnalysis_Surface aSAS1(aSurf1); + gp_Pnt2d aPointOnFace1 = aSAS1.ValueOfUV(aPoint, Precision::Confusion()); + + TopoDS_Face aFace2 = TopoDS::Face(aShape2); + if (aFace2.IsNull()) { + theError = "isContinuousFaces : An invalid argument"; + return false; + } + + Handle(Geom_Surface) aSurf2 = BRep_Tool::Surface(aFace2); + if (aSurf2.IsNull()) { + theError = "isContinuousFaces : An invalid surface"; + return false; + } + + ShapeAnalysis_Surface aSAS2(aSurf2); + gp_Pnt2d aPointOnFace2= aSAS2.ValueOfUV(aPoint, Precision::Confusion()); + + bool aRes = false; + try { + OCC_CATCH_SIGNALS; + LocalAnalysis_SurfaceContinuity aLocAnal(aSurf1, + aPointOnFace1.X(), + aPointOnFace1.Y(), + aSurf2, + aPointOnFace2.X(), + aPointOnFace2.Y(), + GeomAbs_Shape::GeomAbs_G1, // Order + 0.001, // EpsNul + 0.001, // EpsC0 + 0.001, // EpsC1 + 0.001, // EpsC2 + theAngle * M_PI / 180.0); //EpsG1 + aRes = aLocAnal.IsG1(); + } + catch (Standard_Failure const& anException) { + theError = "LocalAnalysis_SurfaceContinuity error :"; + theError += anException.GetMessageString(); + } + + return aRes; +} + //================================================================================================== std::shared_ptr GeomAlgoAPI_ShapeTools::centreOfMass(const std::shared_ptr theShape) { GProp_GProps aGProps; - if(!theShape) { + if (!theShape) { return std::shared_ptr(); } const TopoDS_Shape& aShape = theShape->impl(); - if(aShape.IsNull()) { + if (aShape.IsNull()) { return std::shared_ptr(); } gp_Pnt aCentre; - if(aShape.ShapeType() == TopAbs_VERTEX) { + if (aShape.ShapeType() == TopAbs_VERTEX) { aCentre = BRep_Tool::Pnt(TopoDS::Vertex(aShape)); - } else if(aShape.ShapeType() == TopAbs_EDGE || aShape.ShapeType() == TopAbs_WIRE) { - BRepGProp::LinearProperties(aShape, aGProps); - aCentre = aGProps.CentreOfMass(); } else { - BRepGProp::SurfaceProperties(aShape, aGProps); + aGProps = props(aShape); aCentre = aGProps.CentreOfMass(); } + return std::shared_ptr(new GeomAPI_Pnt(aCentre.X(), aCentre.Y(), aCentre.Z())); } +//================================================================================================== +double GeomAlgoAPI_ShapeTools::radius(const std::shared_ptr& theCylinder) +{ + double aRadius = -1.0; + if (theCylinder->isCylindrical()) { + const TopoDS_Shape& aShape = theCylinder->impl(); + Handle(Geom_Surface) aSurf = BRep_Tool::Surface(TopoDS::Face(aShape)); + Handle(Geom_CylindricalSurface) aCyl = Handle(Geom_CylindricalSurface)::DownCast(aSurf); + if (!aCyl.IsNull()) + aRadius = aCyl->Radius(); + } + return aRadius; +} + +//================================================================================================== +namespace { + +auto getExtemaDistShape = [](const GeomShapePtr& theShape1, + const GeomShapePtr& theShape2) -> BRepExtrema_DistShapeShape +{ + const TopoDS_Shape& aShape1 = theShape1->impl(); + const TopoDS_Shape& aShape2 = theShape2->impl(); + + BRepExtrema_DistShapeShape aDist(aShape1, aShape2); + aDist.Perform(); + return aDist; +}; + +static void tessellateShape(const TopoDS_Shape& theShape) +{ + Standard_Boolean isTessellate = Standard_False; + TopLoc_Location aLoc; + for (TopExp_Explorer anExp(theShape, TopAbs_FACE); anExp.More() && !isTessellate; anExp.Next()) { + Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation(TopoDS::Face(anExp.Value()), aLoc); + isTessellate = aTria.IsNull(); + } + for (TopExp_Explorer anExp(theShape, TopAbs_EDGE); anExp.More() && !isTessellate; anExp.Next()) { + Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D(TopoDS::Edge(anExp.Value()), aLoc); + isTessellate = aPoly.IsNull(); + } + + if (isTessellate) { + BRepMesh_IncrementalMesh aMesher(theShape, 0.1); + Standard_ProgramError_Raise_if(!aMesher.IsDone(), "Meshing failed"); + } +} + +static Standard_Real paramOnCurve(const BRepAdaptor_Curve& theCurve, + const gp_Pnt& thePoint, + const Standard_Real theTol) +{ + Extrema_ExtPC aParamSearch(thePoint, + theCurve, + theCurve.FirstParameter(), + theCurve.LastParameter()); + if (aParamSearch.IsDone()) { + Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt(); + Standard_Real aSqDistMin = RealLast(); + for (Standard_Integer i = 1; i <= aNbExt; ++i) { + if (aParamSearch.SquareDistance(i) < aSqDistMin) { + anIndMin = i; + aSqDistMin = aParamSearch.SquareDistance(i); + } + } + if (anIndMin != 0 && aSqDistMin <= theTol * theTol) + return aParamSearch.Point(anIndMin).Parameter(); + } + return 0.5 * (theCurve.FirstParameter() + theCurve.LastParameter()); +} + +static void paramsOnSurf(const BRepAdaptor_Surface& theSurf, + const gp_Pnt& thePoint, + const Standard_Real theTol, + Standard_Real& theU, + Standard_Real& theV) +{ + Extrema_ExtPS aParamSearch(thePoint, theSurf, Precision::PConfusion(), Precision::PConfusion()); + if (aParamSearch.IsDone()) { + Standard_Integer anIndMin = 0, aNbExt = aParamSearch.NbExt(); + Standard_Real aSqDistMin = RealLast(); + for (Standard_Integer i = 1; i <= aNbExt; ++i) { + if (aParamSearch.SquareDistance(i) < aSqDistMin) { + anIndMin = i; + aSqDistMin = aParamSearch.SquareDistance(i); + } + } + if (anIndMin != 0 && aSqDistMin <= theTol * theTol) + return aParamSearch.Point(anIndMin).Parameter(theU, theV); + } + theU = 0.5 * (theSurf.FirstUParameter() + theSurf.LastUParameter()); + theV = 0.5 * (theSurf.FirstVParameter() + theSurf.LastVParameter()); +} + +static Standard_Real extremaEE(const TopoDS_Edge& theEdge1, + const TopoDS_Edge& theEdge2, + const gp_Pnt& thePoint1, + const gp_Pnt& thePoint2) +{ + BRepAdaptor_Curve aCurve1(theEdge1); + BRepAdaptor_Curve aCurve2(theEdge2); + + Standard_Real aU1 = paramOnCurve(aCurve1, thePoint1, BRep_Tool::Tolerance(theEdge1)); + Standard_Real aU2 = paramOnCurve(aCurve2, thePoint2, BRep_Tool::Tolerance(theEdge2)); + + Standard_Real aValue = -1.0; + Extrema_LocateExtCC anExtr(aCurve1, aCurve2, aU1, aU2); + if (anExtr.IsDone() && aValue > Precision::Confusion()) + aValue = Sqrt(anExtr.SquareDistance()); + return aValue; +} + +static Standard_Real extremaPE(const gp_Pnt& thePoint, + const TopoDS_Edge& theEdge, + gp_Pnt& thePointOnEdge) +{ + BRepAdaptor_Curve aCurve (theEdge); + + TopLoc_Location aLoc; + Standard_Real aTol = BRep_Tool::Tolerance(theEdge); + Handle(Poly_Polygon3D) aPoly = BRep_Tool::Polygon3D (theEdge, aLoc); + if (!aPoly.IsNull()) + aTol = Max (aTol, aPoly->Deflection()); + + Standard_Real aParam = paramOnCurve (aCurve, thePointOnEdge, 2*aTol); + + Standard_Real aValue = -1.0; + Extrema_LocateExtPC anExtr (thePoint, aCurve, aParam, Precision::PConfusion()); + if (anExtr.IsDone()) + { + aValue = Sqrt(anExtr.SquareDistance()); + + Extrema_POnCurv aPointOnCurve = anExtr.Point(); + thePointOnEdge = aPointOnCurve.Value(); + } + return aValue; +} + +static Standard_Real extremaPF(const gp_Pnt& thePoint, + const TopoDS_Face& theFace, + gp_Pnt& thePointOnFace) +{ + BRepAdaptor_Surface aSurf (theFace); + + TopLoc_Location aLoc; + Standard_Real aTol = BRep_Tool::Tolerance(theFace); + Handle(Poly_Triangulation) aTria = BRep_Tool::Triangulation (theFace, aLoc); + if (!aTria.IsNull()) + aTol = Max (aTol, aTria->Deflection()); + + Standard_Real aU, aV; + paramsOnSurf(aSurf, thePointOnFace, 2*aTol, aU, aV); + + Standard_Real aValue = -1.0; + Extrema_GenLocateExtPS anExtr (aSurf); + anExtr.Perform (thePoint, aU, aV); + if (anExtr.IsDone()) + { + aValue = Sqrt(anExtr.SquareDistance()); + + Extrema_POnSurf aPointOnSurf = anExtr.Point(); + thePointOnFace = aPointOnSurf.Value(); + } + return aValue; +} + +static Standard_Real extremaEF(const TopoDS_Edge& theEdge, + const TopoDS_Face& theFace, + const gp_Pnt& thePonE, + const gp_Pnt& thePonF) +{ + BRepAdaptor_Curve aCurve(theEdge); + BRepAdaptor_Surface aSurf(theFace); + + Standard_Real aP = paramOnCurve(aCurve, thePonE, BRep_Tool::Tolerance(theEdge)); + Standard_Real aU, aV; + paramsOnSurf(aSurf, thePonF, BRep_Tool::Tolerance(theFace), aU, aV); + + Standard_Real aValue = -1.0; + Extrema_GenLocateExtCS anExtr(aCurve, aSurf, aP, aU, aV, Precision::PConfusion(), Precision::PConfusion()); + if (anExtr.IsDone() && aValue > Precision::Confusion()) + aValue = Sqrt(anExtr.SquareDistance()); + return aValue; +} + +static Standard_Real extremaFF(const TopoDS_Face& theFace1, + const TopoDS_Face& theFace2, + const gp_Pnt& thePoint1, + const gp_Pnt& thePoint2) +{ + BRepAdaptor_Surface aSurf1(theFace1); + BRepAdaptor_Surface aSurf2(theFace2); + + Standard_Real aU1, aV1; + paramsOnSurf(aSurf1, thePoint1, BRep_Tool::Tolerance(theFace1), aU1, aV1); + Standard_Real aU2, aV2; + paramsOnSurf(aSurf2, thePoint2, BRep_Tool::Tolerance(theFace2), aU2, aV2); + + Standard_Real aValue = -1.0; + Extrema_GenLocateExtSS anExtr(aSurf1, aSurf2, aU1, aV1, aU2, aV2, Precision::PConfusion(), Precision::PConfusion()); + if (anExtr.IsDone() && aValue > Precision::Confusion()) + aValue = Sqrt(anExtr.SquareDistance()); + return aValue; +} + +} // namespace + +double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1, + const GeomShapePtr& theShape2) +{ + BRepExtrema_DistShapeShape aDist = getExtemaDistShape(theShape1, theShape2); + return aDist.IsDone() ? aDist.Value() : Precision::Infinite(); +} + +double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1, + const GeomShapePtr& theShape2, + std::array & fromShape1To2) +{ + BRepExtrema_DistShapeShape aDist = getExtemaDistShape(theShape1, theShape2); + const auto & pt1 = aDist.PointOnShape1(1); + const auto & pt2 = aDist.PointOnShape2(1) ; + fromShape1To2[0] = pt2.X() - pt1.X(); + fromShape1To2[1] = pt2.Y() - pt1.Y(); + fromShape1To2[2] = pt2.Z() - pt1.Z(); + return aDist.IsDone() ? aDist.Value() : Precision::Infinite(); +} + +//================================================================================================== +double GeomAlgoAPI_ShapeTools::shapeProximity(const GeomShapePtr& theShape1, + const GeomShapePtr& theShape2) +{ + double aResult = -1.0; + if (!theShape1.get() || !theShape2.get()) + return aResult; + + const TopoDS_Shape& aShape1 = theShape1->impl(); + const TopoDS_Shape& aShape2 = theShape2->impl(); + + TopAbs_ShapeEnum aType1 = aShape1.ShapeType(); + TopAbs_ShapeEnum aType2 = aShape2.ShapeType(); + + // tessellate shapes if there is no mesh exists + tessellateShape(aShape1); + tessellateShape(aShape2); + + BRepExtrema_ShapeProximity aDist (aShape1, aShape2); + aDist.Perform(); + if (aDist.IsDone()) { + aResult = aDist.Proximity(); + + // refine the result + gp_Pnt aPnt1 = aDist.ProximityPoint1(); + gp_Pnt aPnt2 = aDist.ProximityPoint2(); + + BRepExtrema_ProximityDistTool::ProxPnt_Status aStatus1 = aDist.ProxPntStatus1(); + BRepExtrema_ProximityDistTool::ProxPnt_Status aStatus2 = aDist.ProxPntStatus2(); + + double aValue = -1.0; + + if (aType1 == TopAbs_EDGE) + { + if (aType2 == TopAbs_EDGE) + { + if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE) + { + aValue = extremaEE(TopoDS::Edge(aShape1), TopoDS::Edge(aShape2), aPnt1, aPnt2); + } + else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE) + { + aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2); + } + else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER) + { + aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1); + } + } + else if (aType2 == TopAbs_FACE) + { + if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE) + { + aValue = extremaEF(TopoDS::Edge(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2); + } + else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE) + { + aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2); + } + else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER) + { + aValue = extremaPE(aPnt2, TopoDS::Edge(aShape1), aPnt1); + } + } + } + else if (aType1 == TopAbs_FACE) + { + if (aType2 == TopAbs_EDGE) + { + if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE) + { + aValue = extremaEF(TopoDS::Edge(aShape2), TopoDS::Face(aShape1), aPnt2, aPnt1); + } + else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE) + { + aValue = extremaPE(aPnt1, TopoDS::Edge(aShape2), aPnt2); + } + else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER) + { + aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1); + } + } + else if (aType2 == TopAbs_FACE) + { + if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE) + { + aValue = extremaFF(TopoDS::Face(aShape1), TopoDS::Face(aShape2), aPnt1, aPnt2); + } + else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE) + { + aValue = extremaPF(aPnt1, TopoDS::Face(aShape2), aPnt2); + } + else if (aStatus1 == BRepExtrema_ProximityDistTool::ProxPnt_Status_MIDDLE && + aStatus2 == BRepExtrema_ProximityDistTool::ProxPnt_Status_BORDER) + { + aValue = extremaPF(aPnt2, TopoDS::Face(aShape1), aPnt1); + } + } + } + + if (aValue > 0.0) + aResult = aValue; + } + return aResult; +} + //================================================================================================== std::shared_ptr GeomAlgoAPI_ShapeTools::combineShapes( const std::shared_ptr theCompound, const GeomAPI_Shape::ShapeType theType, - ListOfShape& theCombinedShapes, - ListOfShape& theFreeShapes) + ListOfShape& theResuts) { + + ListOfShape aResCombinedShapes; + ListOfShape aResFreeShapes; + GeomShapePtr aResult = theCompound; - if(!theCompound.get()) { + if (!theCompound.get()) { return aResult; } - if(theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) { + if (theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) { return aResult; } TopAbs_ShapeEnum aTS = TopAbs_EDGE; TopAbs_ShapeEnum aTA = TopAbs_FACE; - if(theType == GeomAPI_Shape::COMPSOLID) { + if (theType == GeomAPI_Shape::COMPSOLID) { aTS = TopAbs_FACE; aTA = TopAbs_SOLID; } - theCombinedShapes.clear(); - theFreeShapes.clear(); + // map from the resulting shapes to minimal index of the used shape from theCompound list + std::map anInputOrder; + // map from ancestors-shapes to the index of shapes in theCompound + NCollection_DataMap anAncestorsOrder; // Get free shapes. + int anOrder = 0; const TopoDS_Shape& aShapesComp = theCompound->impl(); - for(TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next() ) { + for (TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next(), anOrder++) { const TopoDS_Shape& aShape = anIter.Value(); - if(aShape.ShapeType() > aTA) { + if (aShape.ShapeType() > aTA) { std::shared_ptr aGeomShape(new GeomAPI_Shape); aGeomShape->setImpl(new TopoDS_Shape(aShape)); - theFreeShapes.push_back(aGeomShape); + aResFreeShapes.push_back(aGeomShape); + anInputOrder[aGeomShape] = anOrder; + } else { + for (TopExp_Explorer anExp(aShape, aTA); anExp.More(); anExp.Next()) { + anAncestorsOrder.Bind(anExp.Current(), anOrder); + } } } - // Map subshapes and shapes. - BOPCol_IndexedDataMapOfShapeListOfShape aMapSA; - BOPTools::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA); - if(aMapSA.IsEmpty()) { + // Map sub-shapes and shapes. + TopTools_IndexedDataMapOfShapeListOfShape aMapSA; + TopExp::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA); + if (aMapSA.IsEmpty()) { return aResult; } + theResuts.clear(); - // Get all shapes with common subshapes and free shapes. + // Get all shapes with common sub-shapes and free shapes. NCollection_Map aFreeShapes; NCollection_Vector> aShapesWithCommonSubshapes; - for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator + for (TopTools_IndexedDataMapOfShapeListOfShape::Iterator anIter(aMapSA); anIter.More(); anIter.Next()) { - const TopoDS_Shape& aShape = anIter.Key(); - BOPCol_ListOfShape& aListOfShape = anIter.ChangeValue(); - if(aListOfShape.IsEmpty()) { + TopTools_ListOfShape& aListOfShape = anIter.ChangeValue(); + if (aListOfShape.IsEmpty()) { continue; } - else if(aListOfShape.Size() == 1) { + else if (aListOfShape.Size() == 1) { const TopoDS_Shape& aF = aListOfShape.First(); aFreeShapes.Add(aF); aListOfShape.Clear(); } else { NCollection_List aTempList; NCollection_Map aTempMap; - const TopoDS_Shape& aF = aListOfShape.First(); - const TopoDS_Shape& aL = aListOfShape.Last(); - aTempList.Append(aF); - aTempList.Append(aL); - aTempMap.Add(aF); - aTempMap.Add(aL); - aFreeShapes.Remove(aF); - aFreeShapes.Remove(aL); + for (TopTools_ListOfShape::Iterator aListIt(aListOfShape); aListIt.More(); aListIt.Next()) { + aTempList.Append(aListIt.Value()); + aTempMap.Add(aListIt.Value()); + aFreeShapes.Remove(aListIt.Value()); + } aListOfShape.Clear(); - for(NCollection_List::Iterator + for (NCollection_List::Iterator aTempIter(aTempList); aTempIter.More(); aTempIter.Next()) { const TopoDS_Shape& aTempShape = aTempIter.Value(); - for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator - anIter(aMapSA); anIter.More(); anIter.Next()) { - BOPCol_ListOfShape& aTempListOfShape = anIter.ChangeValue(); - if(aTempListOfShape.IsEmpty()) { + for (TopTools_IndexedDataMapOfShapeListOfShape::Iterator + anIter2(aMapSA); anIter2.More(); anIter2.Next()) { + TopTools_ListOfShape& aTempListOfShape = anIter2.ChangeValue(); + if (aTempListOfShape.IsEmpty()) { continue; - } else if(aTempListOfShape.Size() == 1 && aTempListOfShape.First() == aTempShape) { + } else if (aTempListOfShape.Size() == 1 && aTempListOfShape.First() == aTempShape) { aTempListOfShape.Clear(); - } else if(aTempListOfShape.Size() > 1) { - if(aTempListOfShape.First() == aTempShape) { - const TopoDS_Shape& aTL = aTempListOfShape.Last(); - if(aTempMap.Add(aTL)) { - aTempList.Append(aTL); - aFreeShapes.Remove(aTL); - } - aTempListOfShape.Clear(); - } else if(aTempListOfShape.Last() == aTempShape) { - const TopoDS_Shape& aTF = aTempListOfShape.First(); - if(aTempMap.Add(aTF)) { - aTempList.Append(aTF); - aFreeShapes.Remove(aTF); + } else if (aTempListOfShape.Size() > 1) { + TopTools_ListOfShape::Iterator anIt1(aTempListOfShape); + for (; anIt1.More(); anIt1.Next()) { + if (anIt1.Value() == aTempShape) { + TopTools_ListOfShape::Iterator anIt2(aTempListOfShape); + for (; anIt2.More(); anIt2.Next()) + { + if (anIt2.Value() != anIt1.Value()) { + if (aTempMap.Add(anIt2.Value())) { + aTempList.Append(anIt2.Value()); + aFreeShapes.Remove(anIt2.Value()); + } + } + } + aTempListOfShape.Clear(); + break; } - aTempListOfShape.Clear(); } } } @@ -239,55 +778,65 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::combineShapes( } } - // Combine shapes with common subshapes. - for(NCollection_Vector>::Iterator + // Combine shapes with common sub-shapes. + for (NCollection_Vector>::Iterator anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) { TopoDS_Shell aShell; TopoDS_CompSolid aCSolid; TopoDS_Builder aBuilder; + anOrder = -1; theType == GeomAPI_Shape::COMPSOLID ? aBuilder.MakeCompSolid(aCSolid) : aBuilder.MakeShell(aShell); NCollection_Map& aShapesMap = anIter.ChangeValue(); - for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) { + for (TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) { const TopoDS_Shape& aShape = anExp.Current(); - if(aShapesMap.Contains(aShape)) { + if (aShapesMap.Contains(aShape)) { theType == GeomAPI_Shape::COMPSOLID ? aBuilder.Add(aCSolid, aShape) : aBuilder.Add(aShell, aShape); aShapesMap.Remove(aShape); + int aThisOrder = anAncestorsOrder.Find(aShape); + if (anOrder == -1 || aThisOrder < anOrder) + anOrder = aThisOrder; // take the minimum order position } } std::shared_ptr aGeomShape(new GeomAPI_Shape); TopoDS_Shape* aSh = theType == GeomAPI_Shape::COMPSOLID ? new TopoDS_Shape(aCSolid) : new TopoDS_Shape(aShell); aGeomShape->setImpl(aSh); - theCombinedShapes.push_back(aGeomShape); + aResCombinedShapes.push_back(aGeomShape); + anInputOrder[aGeomShape] = anOrder; } // Adding free shapes. - for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) { + for (TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) { const TopoDS_Shape& aShape = anExp.Current(); - if(aFreeShapes.Contains(aShape)) { + if (aFreeShapes.Contains(aShape)) { std::shared_ptr aGeomShape(new GeomAPI_Shape); aGeomShape->setImpl(new TopoDS_Shape(aShape)); - theFreeShapes.push_back(aGeomShape); + aResFreeShapes.push_back(aGeomShape); + anInputOrder[aGeomShape] = anAncestorsOrder.Find(aShape); } } - if(theCombinedShapes.size() == 1 && theFreeShapes.size() == 0) { - aResult = theCombinedShapes.front(); - } else if(theCombinedShapes.size() == 0 && theFreeShapes.size() == 1) { - aResult = theFreeShapes.front(); + if (aResCombinedShapes.size() == 1 && aResFreeShapes.size() == 0) { + aResult = aResCombinedShapes.front(); + theResuts.push_back(aResult); + } else if (aResCombinedShapes.size() == 0 && aResFreeShapes.size() == 1) { + aResult = aResFreeShapes.front(); + theResuts.push_back(aResult); } else { TopoDS_Compound aResultComp; TopoDS_Builder aBuilder; aBuilder.MakeCompound(aResultComp); - for(ListOfShape::const_iterator anIter = theCombinedShapes.cbegin(); - anIter != theCombinedShapes.cend(); anIter++) { - aBuilder.Add(aResultComp, (*anIter)->impl()); - } - for(ListOfShape::const_iterator anIter = theFreeShapes.cbegin(); - anIter != theFreeShapes.cend(); anIter++) { - aBuilder.Add(aResultComp, (*anIter)->impl()); + // put to result compound and result list in accordance to the order numbers + std::map::iterator anInputIter = anInputOrder.begin(); + std::map aNums; + for (; anInputIter != anInputOrder.end(); anInputIter++) + aNums[anInputIter->second] = anInputIter->first; + std::map::iterator aNumsIter = aNums.begin(); + for (; aNumsIter != aNums.end(); aNumsIter++) { + aBuilder.Add(aResultComp, (aNumsIter->second)->impl()); + theResuts.push_back(aNumsIter->second); } aResult->setImpl(new TopoDS_Shape(aResultComp)); } @@ -299,12 +848,12 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::combineShapes( static void addSimpleShapeToList(const TopoDS_Shape& theShape, NCollection_List& theList) { - if(theShape.IsNull()) { + if (theShape.IsNull()) { return; } - if(theShape.ShapeType() == TopAbs_COMPOUND) { - for(TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) { + if (theShape.ShapeType() == TopAbs_COMPOUND) { + for (TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) { addSimpleShapeToList(anIt.Value(), theList); } } else { @@ -320,7 +869,7 @@ static TopoDS_Compound makeCompound(const NCollection_List theShap BRep_Builder aBuilder; aBuilder.MakeCompound(aCompound); - for(NCollection_List::Iterator anIt(theShapes); anIt.More(); anIt.Next()) { + for (NCollection_List::Iterator anIt(theShapes); anIt.More(); anIt.Next()) { aBuilder.Add(aCompound, anIt.Value()); } @@ -333,7 +882,7 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::groupSharedTopology( { GeomShapePtr aResult = theCompound; - if(!theCompound.get()) { + if (!theCompound.get()) { return aResult; } @@ -342,23 +891,24 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::groupSharedTopology( addSimpleShapeToList(anInShape, anUngroupedShapes); // Iterate over all shapes and find shapes with shared vertices. - TopTools_ListOfShape aMapOrder; - BOPCol_DataMapOfShapeListOfShape aVertexShapesMap; - for(NCollection_List::Iterator aShapesIt(anUngroupedShapes); - aShapesIt.More(); - aShapesIt.Next()) { + TopTools_ListOfShape allVertices; + TopTools_DataMapOfShapeListOfShape aVertexShapesMap; + for (NCollection_List::Iterator aShapesIt(anUngroupedShapes); + aShapesIt.More(); + aShapesIt.Next()) { const TopoDS_Shape& aShape = aShapesIt.Value(); - for(TopExp_Explorer aShapeExp(aShape, TopAbs_VERTEX); - aShapeExp.More(); - aShapeExp.Next()) { + for (TopExp_Explorer aShapeExp(aShape, TopAbs_VERTEX); + aShapeExp.More(); + aShapeExp.Next()) { const TopoDS_Shape& aVertex = aShapeExp.Current(); if (!aVertexShapesMap.IsBound(aVertex)) { NCollection_List aList; aList.Append(aShape); - aMapOrder.Append(aVertex); + allVertices.Append(aVertex); aVertexShapesMap.Bind(aVertex, aList); - } else { - if(!aVertexShapesMap.ChangeFind(aVertex).Contains(aShape)) { + } + else { + if (!aVertexShapesMap.ChangeFind(aVertex).Contains(aShape)) { aVertexShapesMap.ChangeFind(aVertex).Append(aShape); } } @@ -366,55 +916,56 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::groupSharedTopology( } // Iterate over the map and group shapes. - NCollection_Vector aGroups; - while (!aMapOrder.IsEmpty()) { + NCollection_Vector aGroups; // groups of shapes connected by vertices + while (!allVertices.IsEmpty()) { // Get first group of shapes in map, and then unbind it. - const TopoDS_Shape& aKey = aMapOrder.First(); - TopTools_ListOfShape aGroupedShapes = aVertexShapesMap.Find(aKey); + const TopoDS_Shape& aKey = allVertices.First(); + TopTools_ListOfShape aConnectedShapes = aVertexShapesMap.Find(aKey); aVertexShapesMap.UnBind(aKey); - aMapOrder.Remove(aKey); + allVertices.Remove(aKey); // Iterate over shapes in this group and add to it shapes from groups in map. - for(TopTools_ListOfShape::Iterator aGroupIt(aGroupedShapes); - aGroupIt.More(); aGroupIt.Next()) { - const TopoDS_Shape& aGroupedShape = aGroupIt.Value(); + for (TopTools_ListOfShape::Iterator aConnectedIt(aConnectedShapes); + aConnectedIt.More(); aConnectedIt.Next()) { + const TopoDS_Shape& aConnected = aConnectedIt.Value(); TopTools_ListOfShape aKeysToUnbind; - for(TopTools_ListOfShape::Iterator aKeysIt(aMapOrder); - aKeysIt.More(); - aKeysIt.Next()) { - const TopTools_ListOfShape& aGroupInMap = aVertexShapesMap(aKeysIt.Value()); - if(!aGroupInMap.Contains(aGroupedShape)) { - // Group in map does not containt shape from our group, so go to the next group in map. + for (TopTools_ListOfShape::Iterator aKeysIt(allVertices); + aKeysIt.More(); + aKeysIt.Next()) { + const TopTools_ListOfShape& anOtherConnected = aVertexShapesMap(aKeysIt.Value()); + if (!anOtherConnected.Contains(aConnected)) { + // Other connected group does not contain shape from our connected group continue; } - // Iterate over shape in group in map, and add new shapes into our group. - for(TopTools_ListOfShape::Iterator aGroupInMapIt(aGroupInMap); - aGroupInMapIt.More(); - aGroupInMapIt.Next()) { - const TopoDS_Shape& aShape = aGroupInMapIt.Value(); - if (!aGroupedShapes.Contains(aShape)) { - aGroupedShapes.Append(aShape); + // Other is connected to our, so add them to our connected + for (TopTools_ListOfShape::Iterator anOtherIt(anOtherConnected); + anOtherIt.More(); + anOtherIt.Next()) { + const TopoDS_Shape& aShape = anOtherIt.Value(); + if (!aConnectedShapes.Contains(aShape)) { + aConnectedShapes.Append(aShape); } } // Save key to unbind from this map. aKeysToUnbind.Append(aKeysIt.Value()); } // Unbind groups from map that we added to our group. - for(TopTools_ListOfShape::Iterator aKeysIt(aKeysToUnbind); - aKeysIt.More(); - aKeysIt.Next()) { + for (TopTools_ListOfShape::Iterator aKeysIt(aKeysToUnbind); + aKeysIt.More(); + aKeysIt.Next()) { aVertexShapesMap.UnBind(aKeysIt.Value()); - aMapOrder.Remove(aKeysIt.Value()); + allVertices.Remove(aKeysIt.Value()); } } - // Sort shapes. - TopTools_ListOfShape aSortedGroup; - for(int aST = TopAbs_COMPOUND; aST <= TopAbs_SHAPE; ++aST) { - TopTools_ListOfShape::Iterator anIt(aGroupedShapes); + // Sort shapes from the most complicated to the simplest ones + TopTools_MapOfShape aSortedGroup; + for (int aST = TopAbs_COMPOUND; aST <= TopAbs_SHAPE; ++aST) { + TopTools_ListOfShape::Iterator anIt(aConnectedShapes); while (anIt.More()) { - if(anIt.Value().ShapeType() == aST) { - aSortedGroup.Append(anIt.Value()); - aGroupedShapes.Remove(anIt); - } else { + if (anIt.Value().ShapeType() == aST) { + aSortedGroup.Add(anIt.Value()); + aConnectedShapes.Remove(anIt); + } + else { anIt.Next(); } } @@ -425,30 +976,54 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::groupSharedTopology( TopoDS_Compound aCompound; BRep_Builder aBuilder; aBuilder.MakeCompound(aCompound); - ListOfShape aCompSolids, aFreeSolids; - for(NCollection_Vector>::Iterator - anIt(aGroups); anIt.More(); anIt.Next()) { - NCollection_List aGroup = anIt.Value(); + ListOfShape aSolids; + for (NCollection_Vector::Iterator anIt(aGroups); anIt.More(); anIt.Next()) { + const TopTools_MapOfShape& aGroup = anIt.ChangeValue(); GeomShapePtr aGeomShape(new GeomAPI_Shape()); - if(aGroup.Size() == 1) { - aGeomShape->setImpl(new TopoDS_Shape(aGroup.First())); + if (aGroup.Size() == 1) { + TopTools_MapOfShape::Iterator aOneShapeIter(aGroup); + aGeomShape->setImpl(new TopoDS_Shape(aOneShapeIter.Value())); } else { - aGeomShape->setImpl(new TopoDS_Shape(makeCompound(aGroup))); + // make sub-shapes in the group have order same as in original shape + TopTools_ListOfShape anOrderedGoup; + NCollection_List::Iterator anUngrouped(anUngroupedShapes); + for (; anUngrouped.More(); anUngrouped.Next()) { + if (aGroup.Contains(anUngrouped.Value())) + anOrderedGoup.Append(anUngrouped.Value()); + } + aGeomShape->setImpl(new TopoDS_Shape(makeCompound(anOrderedGoup))); aGeomShape = GeomAlgoAPI_ShapeTools::combineShapes(aGeomShape, GeomAPI_Shape::COMPSOLID, - aCompSolids, - aFreeSolids); + aSolids); } aBuilder.Add(aCompound, aGeomShape->impl()); } - if(!aCompound.IsNull()) { + if (!aCompound.IsNull()) { aResult->setImpl(new TopoDS_Shape(aCompound)); } return aResult; } +//================================================================================================== +bool GeomAlgoAPI_ShapeTools::hasSharedTopology(const ListOfShape& theShapes, + const GeomAPI_Shape::ShapeType theShapeType) +{ + TopTools_IndexedMapOfShape aSubs; + for (ListOfShape::const_iterator anIt = theShapes.begin(); anIt != theShapes.end(); ++anIt) { + TopTools_IndexedMapOfShape aCurSubs; + TopExp::MapShapes((*anIt)->impl(), (TopAbs_ShapeEnum)theShapeType, aCurSubs); + for (TopTools_IndexedMapOfShape::Iterator aSubIt(aCurSubs); aSubIt.More(); aSubIt.Next()) { + if (aSubs.Contains(aSubIt.Value())) + return true; + else + aSubs.Add(aSubIt.Value()); + } + } + return false; +} + //================================================================================================== std::list > GeomAlgoAPI_ShapeTools::getBoundingBox(const ListOfShape& theShapes, const double theEnlarge) @@ -463,7 +1038,7 @@ std::list > BRepBndLib::Add(aShape, aBndBox); } - if(theEnlarge != 0.0) { + if (theEnlarge != 0.0) { // We enlarge bounding box just to be sure that plane will be large enough to cut all objects. aBndBox.Enlarge(theEnlarge); } @@ -472,10 +1047,9 @@ std::list > Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()}; Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()}; std::list > aResultPoints; - int aNum = 0; - for(int i = 0; i < 2; i++) { - for(int j = 0; j < 2; j++) { - for(int k = 0; k < 2; k++) { + for (int i = 0; i < 2; i++) { + for (int j = 0; j < 2; j++) { + for (int k = 0; k < 2; k++) { std::shared_ptr aPnt(new GeomAPI_Pnt(aXArr[i], aYArr[j], aZArr[k])); aResultPoints.push_back(aPnt); } @@ -485,29 +1059,6 @@ std::list > return aResultPoints; } -//================================================================================================== -std::shared_ptr - GeomAlgoAPI_ShapeTools::faceToInfinitePlane(const std::shared_ptr theFace) -{ - if (!theFace.get()) - return std::shared_ptr(); - - TopoDS_Face aPlaneFace = TopoDS::Face(theFace->impl()); - if (aPlaneFace.IsNull()) - return std::shared_ptr(); - - Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(aPlaneFace)); - if (aPlane.IsNull()) - return std::shared_ptr(); - - // make an infinity face on the plane - TopoDS_Shape anInfiniteFace = BRepBuilderAPI_MakeFace(aPlane->Pln()).Shape(); - - std::shared_ptr aResult(new GeomAPI_Shape); - aResult->setImpl(new TopoDS_Shape(anInfiniteFace)); - return aResult; -} - //================================================================================================== std::shared_ptr GeomAlgoAPI_ShapeTools::fitPlaneToBox( const std::shared_ptr thePlane, @@ -515,27 +1066,27 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::fitPlaneToBox( { std::shared_ptr aResultFace; - if(!thePlane.get()) { + if (!thePlane.get()) { return aResultFace; } const TopoDS_Shape& aShape = thePlane->impl(); - if(aShape.ShapeType() != TopAbs_FACE) { + if (aShape.ShapeType() != TopAbs_FACE) { return aResultFace; } TopoDS_Face aFace = TopoDS::Face(aShape); Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace); - if(aSurf.IsNull()) { + if (aSurf.IsNull()) { return aResultFace; } GeomLib_IsPlanarSurface isPlanar(aSurf); - if(!isPlanar.IsPlanar()) { + if (!isPlanar.IsPlanar()) { return aResultFace; } - if(thePoints.size() != 8) { + if (thePoints.size() != 8) { return aResultFace; } @@ -552,10 +1103,10 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::fitPlaneToBox( const gp_Pnt& aPntOnFace = anIntAna.Point(1); Standard_Real aPntU(0), aPntV(0); GeomLib_Tool::Parameters(aFacePlane, aPntOnFace, Precision::Confusion(), aPntU, aPntV); - if(aPntU < UMin) UMin = aPntU; - if(aPntU > UMax) UMax = aPntU; - if(aPntV < VMin) VMin = aPntV; - if(aPntV > VMax) VMax = aPntV; + if (aPntU < UMin) UMin = aPntU; + if (aPntU > UMax) UMax = aPntU; + if (aPntV < VMin) VMin = aPntV; + if (aPntV > VMax) VMax = aPntV; } aResultFace.reset(new GeomAPI_Face()); aResultFace->setImpl(new TopoDS_Face(BRepLib_MakeFace(aFacePln, UMin, UMax, VMin, VMax).Face())); @@ -568,23 +1119,26 @@ void GeomAlgoAPI_ShapeTools::findBounds(const std::shared_ptr the std::shared_ptr& theV1, std::shared_ptr& theV2) { - if(!theShape.get()) { - std::shared_ptr aVertex(new GeomAPI_Vertex); + static GeomVertexPtr aVertex; + if (!aVertex) { + aVertex = GeomVertexPtr(new GeomAPI_Vertex); aVertex->setImpl(new TopoDS_Vertex()); - theV1 = aVertex; - theV2 = aVertex; - return; } - const TopoDS_Shape& aShape = theShape->impl(); - TopoDS_Vertex aV1, aV2; - ShapeAnalysis::FindBounds(aShape, aV1, aV2); + theV1 = aVertex; + theV2 = aVertex; - std::shared_ptr aGeomV1(new GeomAPI_Vertex()), aGeomV2(new GeomAPI_Vertex()); - aGeomV1->setImpl(new TopoDS_Vertex(aV1)); - aGeomV2->setImpl(new TopoDS_Vertex(aV2)); - theV1 = aGeomV1; - theV2 = aGeomV2; + if (theShape) { + const TopoDS_Shape& aShape = theShape->impl(); + TopoDS_Vertex aV1, aV2; + ShapeAnalysis::FindBounds(aShape, aV1, aV2); + + std::shared_ptr aGeomV1(new GeomAPI_Vertex()), aGeomV2(new GeomAPI_Vertex()); + aGeomV1->setImpl(new TopoDS_Vertex(aV1)); + aGeomV2->setImpl(new TopoDS_Vertex(aV2)); + theV1 = aGeomV1; + theV2 = aGeomV2; + } } //================================================================================================== @@ -599,7 +1153,7 @@ void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptrimpl()); @@ -608,11 +1162,11 @@ void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptrsetImpl(new TopoDS_Shape(aFRestrictor.Current())); theFaces.push_back(aShape); @@ -626,12 +1180,12 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::findPlane(const ListOfShape BRep_Builder aBuilder; aBuilder.MakeCompound(aCompound); - for(ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) { + for (ListOfShape::const_iterator anIt = theShapes.cbegin(); anIt != theShapes.cend(); ++anIt) { aBuilder.Add(aCompound, (*anIt)->impl()); } BRepBuilderAPI_FindPlane aFindPlane(aCompound); - if(aFindPlane.Found() != Standard_True) { + if (aFindPlane.Found() != Standard_True) { return std::shared_ptr(); } @@ -652,28 +1206,28 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape( const std::shared_ptr theSubShape, const std::shared_ptr theBaseShape) { - if(!theSubShape.get() || !theBaseShape.get()) { + if (!theSubShape.get() || !theBaseShape.get()) { return false; } const TopoDS_Shape& aSubShape = theSubShape->impl(); const TopoDS_Shape& aBaseShape = theBaseShape->impl(); - if(aSubShape.ShapeType() == TopAbs_VERTEX) { + if (aSubShape.ShapeType() == TopAbs_VERTEX) { // If sub-shape is a vertex check distance to shape. If it is <= Precision::Confusion() then OK. BRepExtrema_DistShapeShape aDist(aBaseShape, aSubShape); aDist.Perform(); - if(!aDist.IsDone() || aDist.Value() > Precision::Confusion()) { + if (!aDist.IsDone() || aDist.Value() > Precision::Confusion()) { return false; } } else if (aSubShape.ShapeType() == TopAbs_EDGE) { - if(aBaseShape.ShapeType() == TopAbs_FACE) { + if (aBaseShape.ShapeType() == TopAbs_FACE) { // Check that edge is on face surface. TopoDS_Face aFace = TopoDS::Face(aBaseShape); TopoDS_Edge anEdge = TopoDS::Edge(aSubShape); BRepLib_CheckCurveOnSurface aCheck(anEdge, aFace); aCheck.Perform(); - if(!aCheck.IsDone() || aCheck.MaxDistance() > Precision::Confusion()) { + if (!aCheck.IsDone() || aCheck.MaxDistance() > Precision::Confusion()) { return false; } @@ -682,15 +1236,15 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape( ShapeAnalysis::FindBounds(anEdge, aV1, aV2); gp_Pnt aPnt1 = BRep_Tool::Pnt(aV1); gp_Pnt aPnt2 = BRep_Tool::Pnt(aV2); - for(TopExp_Explorer anExp(aBaseShape, TopAbs_EDGE); anExp.More(); anExp.Next()) { + for (TopExp_Explorer anExp(aBaseShape, TopAbs_EDGE); anExp.More(); anExp.Next()) { const TopoDS_Shape& anEdgeOnFace = anExp.Current(); BRepExtrema_DistShapeShape aDist(anEdgeOnFace, anEdge); aDist.Perform(); - if(aDist.IsDone() && aDist.Value() <= Precision::Confusion()) { + if (aDist.IsDone() && aDist.Value() <= Precision::Confusion()) { // Edge intersect face bound. Check that it is not on edge begin or end. - for(Standard_Integer anIndex = 1; anIndex <= aDist.NbSolution(); ++anIndex) { + for (Standard_Integer anIndex = 1; anIndex <= aDist.NbSolution(); ++anIndex) { gp_Pnt aPntOnSubShape = aDist.PointOnShape2(anIndex); - if(aPntOnSubShape.Distance(aPnt1) > Precision::Confusion() + if (aPntOnSubShape.Distance(aPnt1) > Precision::Confusion() && aPntOnSubShape.Distance(aPnt2) > Precision::Confusion()) { return false; } @@ -707,7 +1261,7 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape( ShapeAnalysis_Surface aSAS(aSurface); gp_Pnt2d aPointOnFace = aSAS.ValueOfUV(aPointToCheck, Precision::Confusion()); BRepTopAdaptor_FClass2d aFClass2d(aFace, Precision::Confusion()); - if(aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) { + if (aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) { return false; } @@ -724,7 +1278,7 @@ bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape( //================================================================================================== bool GeomAlgoAPI_ShapeTools::isShapeValid(const std::shared_ptr theShape) { - if(!theShape.get()) { + if (!theShape.get()) { return false; } @@ -738,7 +1292,7 @@ std::shared_ptr { GeomShapePtr anOuterWire; - if(!theFace.get() || !theFace->isFace()) { + if (!theFace.get() || !theFace->isFace()) { return anOuterWire; } @@ -751,11 +1305,49 @@ std::shared_ptr return anOuterWire; } +//================================================================================================== +static bool boundaryOfEdge(const std::shared_ptr theEdge, + const std::shared_ptr theVertex, + double& theParam) +{ + GeomPointPtr aPoint = theVertex->point(); + GeomPointPtr aFirstPnt = theEdge->firstPoint(); + double aFirstPntTol = theEdge->firstPointTolerance(); + GeomPointPtr aLastPnt = theEdge->lastPoint(); + double aLastPntTol = theEdge->lastPointTolerance(); + + double aFirst, aLast; + theEdge->getRange(aFirst, aLast); + + bool isFirst = aPoint->distance(aFirstPnt) <= aFirstPntTol; + bool isLast = aPoint->distance(aLastPnt) <= aLastPntTol; + if (isFirst) + theParam = aFirst; + else if (isLast) + theParam = aLast; + + return isFirst != isLast; +} + +bool GeomAlgoAPI_ShapeTools::isTangent(const std::shared_ptr theEdge1, + const std::shared_ptr theEdge2, + const std::shared_ptr theTgPoint) +{ + double aParE1 = 0, aParE2 = 0; + if (!boundaryOfEdge(theEdge1, theTgPoint, aParE1) || + !boundaryOfEdge(theEdge2, theTgPoint, aParE2)) + return false; + + BRepAdaptor_Curve aC1(theEdge1->impl()); + BRepAdaptor_Curve aC2(theEdge2->impl()); + return BRepLProp::Continuity(aC1, aC2, aParE1, aParE2) >= GeomAbs_G1; +} + //================================================================================================== bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr theEdge, const std::shared_ptr theFace) { - if(!theEdge.get() || !theFace.get()) { + if (!theEdge.get() || !theFace.get()) { return false; } @@ -768,11 +1360,10 @@ bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr theE //================================================================================================== std::list > GeomAlgoAPI_ShapeTools::intersect( - const std::shared_ptr theEdge, const std::shared_ptr theFace, - const bool thePointsOutsideFace) + const std::shared_ptr theEdge, const std::shared_ptr theFace) { std::list > aResult; - if(!theEdge.get() || !theFace.get()) { + if (!theEdge.get() || !theFace.get()) { return aResult; } @@ -787,7 +1378,7 @@ std::list > GeomAlgoAPI_ShapeTools::intersect( if (!anIntAlgo.IsDone()) return aResult; // searching for points-intersection - for(int anIntNum = 1; anIntNum <= anIntAlgo.NbPoints() + anIntAlgo.NbSegments(); anIntNum++) { + for (int anIntNum = 1; anIntNum <= anIntAlgo.NbPoints() + anIntAlgo.NbSegments(); anIntNum++) { gp_Pnt anInt; if (anIntNum <= anIntAlgo.NbPoints()) { anInt = anIntAlgo.Point(anIntNum); @@ -838,13 +1429,8 @@ void GeomAlgoAPI_ShapeTools::splitShape(const std::shared_ptr& th } aBOP.Perform(); -#ifdef USE_OCCT_720 if (aBOP.HasErrors()) return; -#else - if (aBOP.ErrorStatus()) - return; -#endif // Collect splits const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge); @@ -888,13 +1474,8 @@ void GeomAlgoAPI_ShapeTools::splitShape_p(const std::shared_ptr& } aBOP.Perform(); -#ifdef USE_OCCT_720 if (aBOP.HasErrors()) return; -#else - if (aBOP.ErrorStatus()) - return; -#endif // Collect splits const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge); @@ -938,6 +1519,7 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::findShape( } //================================================================================================== +#ifdef FEATURE_MULTIROTATION_TWO_DIRECTIONS std::shared_ptr GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape( const std::shared_ptr theBaseShape, const std::shared_ptr theAxis) @@ -953,3 +1535,266 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape( aCentreOfMassPoint.Z()-aPoint.Z())); return aDir; } +#endif + +//================================================================================================== +static TopoDS_Wire fixParametricGaps(const TopoDS_Wire& theWire) +{ + TopoDS_Wire aFixedWire; + Handle(Geom_Curve) aPrevCurve; + double aPrevLastParam = -Precision::Infinite(); + + BRep_Builder aBuilder; + aBuilder.MakeWire(aFixedWire); + + BRepTools_WireExplorer aWExp(theWire); + for (; aWExp.More(); aWExp.Next()) { + TopoDS_Edge anEdge = aWExp.Current(); + double aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirst, aLast); + if (aCurve == aPrevCurve && Abs(aFirst - aPrevLastParam) > Precision::Confusion()) { + // if parametric gap occurs, create new edge based on the copied curve + aCurve = Handle(Geom_Curve)::DownCast(aCurve->Copy()); + TopoDS_Vertex aV1, aV2; + TopExp::Vertices(anEdge, aV1, aV2); + anEdge = TopoDS::Edge(anEdge.EmptyCopied()); + aBuilder.UpdateEdge(anEdge, aCurve, BRep_Tool::Tolerance(anEdge)); + aBuilder.Add(anEdge, aV1); + aBuilder.Add(anEdge, aV2); + } + + aBuilder.Add(aFixedWire, anEdge); + + aPrevCurve = aCurve; + aPrevLastParam = aLast; + } + + return aFixedWire; +} + +//================================================================================================== +std::shared_ptr GeomAlgoAPI_ShapeTools::wireToEdge( + const std::shared_ptr& theWire) +{ + GeomEdgePtr anEdge; + if (theWire) { + TopoDS_Wire aWire = theWire->impl(); + BRepTools_WireExplorer aWExp(aWire); + TopoDS_Edge aNewEdge = aWExp.Current(); + aWExp.Next(); + if (aWExp.More()) { + // Workaround for the closed wire to avoid jumping of its start point: + // split this wire for two parts, convert them to edges, then compose together + if (BRep_Tool::IsClosed(aWire)) { + aWire = TopoDS::Wire(BRepBuilderAPI_Copy(aWire).Shape()); + aWExp.Init(aWire); + aNewEdge = aWExp.Current(); + + BRep_Builder().Remove(aWire, aNewEdge); + GeomWirePtr aSplitWire(new GeomAPI_Wire); + aSplitWire->setImpl(new TopoDS_Wire(aWire)); + GeomEdgePtr aMergedEdge = wireToEdge(aSplitWire); + + aWire = BRepBuilderAPI_MakeWire(aNewEdge, aMergedEdge->impl()); + } + + // Workaround: when concatenate a wire consisting of two edges based on the same B-spline + // curve (non-periodic, but having equal start and end points), first of which is placed + // at the end on the curve and second is placed at the start, this workaround copies + // second curve to avoid treating these edges as a single curve by setting trim parameters. + aWire = fixParametricGaps(aWire); + aWire = BRepAlgo::ConcatenateWire(aWire, GeomAbs_G1); // join smooth parts of wire + aNewEdge = BRepAlgo::ConcatenateWireC0(aWire); // join C0 parts of wire + + // Reapproximate the result edge to have the parameter equal to curvilinear abscissa. + static const int THE_MAX_DEGREE = 14; + static const int THE_MAX_INTERVALS = 32; + double aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aNewEdge, aFirst, aLast); +#if OCC_VERSION_LARGE < 0x07070000 + Handle(GeomAdaptor_HCurve) aHCurve = new GeomAdaptor_HCurve(aCurve); +#else + Handle(GeomAdaptor_Curve) aHCurve = new GeomAdaptor_Curve(aCurve); +#endif + Approx_CurvilinearParameter anApprox(aHCurve, Precision::Confusion(), aCurve->Continuity(), + THE_MAX_DEGREE, THE_MAX_INTERVALS); + if (anApprox.HasResult()) { + Handle(Geom_BSplineCurve) aNewCurve = anApprox.Curve3d(); + TColStd_Array1OfReal aKnots = aNewCurve->Knots(); + BSplCLib::Reparametrize(aFirst, aLast, aKnots); + aNewCurve->SetKnots(aKnots); + BRep_Builder().UpdateEdge(aNewEdge, aNewCurve, BRep_Tool::Tolerance(aNewEdge)); + } + } + anEdge = GeomEdgePtr(new GeomAPI_Edge); + anEdge->setImpl(new TopoDS_Edge(aNewEdge)); + } + return anEdge; +} + +//================================================================================================== +ListOfShape GeomAlgoAPI_ShapeTools::getLowLevelSubShapes(const GeomShapePtr& theShape) +{ + ListOfShape aSubShapes; + + if (!theShape->isCompound() && !theShape->isCompSolid() && + !theShape->isShell() && !theShape->isWire()) { + return aSubShapes; + } + + for (GeomAPI_ShapeIterator anIt(theShape); anIt.more(); anIt.next()) { + GeomShapePtr aSubShape = anIt.current(); + if (aSubShape->isVertex() || aSubShape->isEdge() || + aSubShape->isFace() || aSubShape->isSolid()) { + aSubShapes.push_back(aSubShape); + } else { + aSubShapes.splice(aSubShapes.end(), getLowLevelSubShapes(aSubShape)); + } + } + + return aSubShapes; +} + +//================================================================================================== +static void getMinMaxPointsOnLine(const std::list >& thePoints, + const gp_Dir theDir, + double& theMin, double& theMax) +{ + theMin = RealLast(); + theMax = RealFirst(); + // Project bounding points on theDir + for (std::list >::const_iterator + aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) { + const gp_Pnt& aPnt = (*aPointsIt)->impl(); + gp_Dir aPntDir (aPnt.XYZ()); + Standard_Real proj = (theDir*aPntDir) * aPnt.XYZ().Modulus(); + if (proj < theMin) theMin = proj; + if (proj > theMax) theMax = proj; + } +} + +//================================================================================================== +void GeomAlgoAPI_ShapeTools::computeThroughAll(const ListOfShape& theObjects, + const ListOfShape& theBaseShapes, + const std::shared_ptr theDir, + double& theToSize, double& theFromSize) +{ + // Bounding box of objects + std::list > aBndObjs = + GeomAlgoAPI_ShapeTools::getBoundingBox(theObjects); + if (aBndObjs.size() != 8) { + return; + } + + // the value to enlarge the bounding box of each object to make the extruded shape + // a little bit larger than overall objects to get the correct result of Boolean CUT operation + double anEnlargement = 0.1 * aBndObjs.front()->distance(aBndObjs.back()); + + // Prism direction + if (theDir.get()) { + // One direction for all prisms + gp_Dir aDir = theDir->impl(); + + // Bounding box of the base + std::list > aBndBases = + GeomAlgoAPI_ShapeTools::getBoundingBox(theBaseShapes); + if (aBndBases.size() != 8) { + return; + } + + // Objects bounds + Standard_Real lowBnd, upperBnd; + getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd); + + // Base bounds + Standard_Real lowBase, upperBase; + getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase); + + // ----------.-----.---------.--------------.-----------> theDir + // lowBnd lowBase upperBase upperBnd + + theToSize = upperBnd - lowBase; + theFromSize = upperBase - lowBnd; + } else { + // Direction is a normal to each base shape (different normals to bases) + // So we calculate own sizes for each base shape + theToSize = 0.0; + theFromSize = 0.0; + + for (ListOfShape::const_iterator anIt = theBaseShapes.begin(); + anIt != theBaseShapes.end(); ++anIt) { + const GeomShapePtr& aBaseShape_i = (*anIt); + ListOfShape aBaseShapes_i; + aBaseShapes_i.push_back(aBaseShape_i); + + // Bounding box of the base + std::list > aBndBases = + GeomAlgoAPI_ShapeTools::getBoundingBox(aBaseShapes_i, anEnlargement); + if (aBndBases.size() != 8) { + return; + } + + // Direction (normal to aBaseShapes_i) + // Code like in GeomAlgoAPI_Prism + gp_Dir aDir; + const TopoDS_Shape& aBaseShape = aBaseShape_i->impl(); + BRepBuilderAPI_FindPlane aFindPlane(aBaseShape); + if (aFindPlane.Found() == Standard_True) { + Handle(Geom_Plane) aPlane; + if (aBaseShape.ShapeType() == TopAbs_FACE || aBaseShape.ShapeType() == TopAbs_SHELL) { + TopExp_Explorer anExp(aBaseShape, TopAbs_FACE); + const TopoDS_Shape& aFace = anExp.Current(); + Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aFace)); + if (aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) { + Handle(Geom_RectangularTrimmedSurface) aTrimSurface = + Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface); + aSurface = aTrimSurface->BasisSurface(); + } + if (aSurface->DynamicType() != STANDARD_TYPE(Geom_Plane)) { + return; + } + aPlane = Handle(Geom_Plane)::DownCast(aSurface); + } else { + aPlane = aFindPlane.Plane(); + } + aDir = aPlane->Axis().Direction(); + } else { + return; + } + + // Objects bounds + Standard_Real lowBnd, upperBnd; + getMinMaxPointsOnLine(aBndObjs, aDir, lowBnd, upperBnd); + + // Base bounds + Standard_Real lowBase, upperBase; + getMinMaxPointsOnLine(aBndBases, aDir, lowBase, upperBase); + + // ----------.-----.---------.--------------.-----------> theDir + // lowBnd lowBase upperBase upperBnd + + double aToSize_i = upperBnd - lowBase; + double aFromSize_i = upperBase - lowBnd; + + if (aToSize_i > theToSize) theToSize = aToSize_i; + if (aFromSize_i > theFromSize) theFromSize = aFromSize_i; + } + } +} + +ListOfShape GeomAlgoAPI_ShapeTools::getSharedFaces(const GeomShapePtr& theShape) +{ + ListOfShape aSharedFaces; + TopTools_IndexedDataMapOfShapeListOfShape aMapFS; + TopExp::MapShapesAndUniqueAncestors(theShape->impl(), + TopAbs_FACE, TopAbs_SOLID, aMapFS); + for (Standard_Integer i = 1; i <= aMapFS.Extent(); i++) { + const TopTools_ListOfShape& ancestors = aMapFS.FindFromIndex(i); + if (ancestors.Size() > 1) { + GeomShapePtr aFace(new GeomAPI_Shape); + aFace->setImpl(new TopoDS_Shape(aMapFS.FindKey(i))); + aSharedFaces.push_back(aFace); + } + } + return aSharedFaces; +}