X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGeomAlgoAPI%2FGeomAlgoAPI_ShapeTools.cpp;h=a47c77c7f28d1fa298a72a1613b71a5eabdd06ff;hb=5fb6a80c4e86e21b1181b4e6ee940d946b5c52e4;hp=de201f61c10e071b8c92d7f475d13483bd123061;hpb=34afe547352180006fee9600173c4dc93dc1f6c3;p=modules%2Fshaper.git diff --git a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp index de201f61c..a47c77c7f 100644 --- a/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp +++ b/src/GeomAlgoAPI/GeomAlgoAPI_ShapeTools.cpp @@ -1,55 +1,155 @@ -// Copyright (C) 2014-20xx CEA/DEN, EDF R&D +// Copyright (C) 2014-2017 CEA/DEN, EDF R&D +// +// This library is free software; you can redistribute it and/or +// modify it under the terms of the GNU Lesser General Public +// License as published by the Free Software Foundation; either +// version 2.1 of the License, or (at your option) any later version. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// Lesser General Public License for more details. +// +// 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 +// +// See http://www.salome-platform.org/ or +// email : webmaster.salome@opencascade.com +// -// File: GeomAlgoAPI_ShapeTools.h -// Created: 3 August 2015 -// Author: Dmitry Bobylev +#include "GeomAlgoAPI_ShapeTools.h" -#include +#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 #include +#include #include +#include #include +#include + + +#include +#include +#include + +//================================================================================================== +static GProp_GProps props(const TopoDS_Shape& theShape) +{ + GProp_GProps aGProps; + 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::volume(const std::shared_ptr theShape) { GProp_GProps aGProps; - if(!theShape) { + if(!theShape.get()) { return 0.0; } const TopoDS_Shape& aShape = theShape->impl(); if(aShape.IsNull()) { return 0.0; } - BRepGProp::VolumeProperties(aShape, aGProps); + const Standard_Real anEps = 1.e-6; + if (aShape.ShapeType() <= TopAbs_SOLID) + BRepGProp::VolumeProperties(aShape, aGProps, anEps); + else + BRepGProp::SurfaceProperties(aShape, aGProps, anEps); return aGProps.Mass(); } -//================================================================================================= -std::shared_ptr GeomAlgoAPI_ShapeTools::centreOfMass(const std::shared_ptr theShape) +//================================================================================================== +double GeomAlgoAPI_ShapeTools::area (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; + } + const Standard_Real anEps = 1.e-6; + + BRepGProp::SurfaceProperties(aShape, aGProps, anEps); + return aGProps.Mass(); +} + +//================================================================================================== +std::shared_ptr + GeomAlgoAPI_ShapeTools::centreOfMass(const std::shared_ptr theShape) { GProp_GProps aGProps; if(!theShape) { @@ -59,23 +159,58 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::centreOfMass(const std::sha if(aShape.IsNull()) { return std::shared_ptr(); } - BRepGProp::SurfaceProperties(aShape, aGProps); - gp_Pnt aCentre = aGProps.CentreOfMass(); + gp_Pnt aCentre; + if(aShape.ShapeType() == TopAbs_VERTEX) { + aCentre = BRep_Tool::Pnt(TopoDS::Vertex(aShape)); + } else { + aGProps = props(aShape); + aCentre = aGProps.CentreOfMass(); + } + return std::shared_ptr(new GeomAPI_Pnt(aCentre.X(), aCentre.Y(), aCentre.Z())); } -//================================================================================================= -void GeomAlgoAPI_ShapeTools::combineShapes(const std::shared_ptr theCompound, - const GeomAPI_Shape::ShapeType theType, - ListOfShape& theCombinedShapes, - ListOfShape& theFreeShapes) +//================================================================================================== +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; +} + +//================================================================================================== +double GeomAlgoAPI_ShapeTools::minimalDistance(const GeomShapePtr& theShape1, + const GeomShapePtr& theShape2) +{ + const TopoDS_Shape& aShape1 = theShape1->impl(); + const TopoDS_Shape& aShape2 = theShape2->impl(); + + BRepExtrema_DistShapeShape aDist(aShape1, aShape2); + aDist.Perform(); + return aDist.IsDone() ? aDist.Value() : Precision::Infinite(); +} + +//================================================================================================== +std::shared_ptr GeomAlgoAPI_ShapeTools::combineShapes( + const std::shared_ptr theCompound, + const GeomAPI_Shape::ShapeType theType, + ListOfShape& theCombinedShapes, + ListOfShape& theFreeShapes) { + GeomShapePtr aResult = theCompound; + if(!theCompound.get()) { - return; + return aResult; } if(theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) { - return; + return aResult; } TopAbs_ShapeEnum aTS = TopAbs_EDGE; @@ -85,20 +220,34 @@ void GeomAlgoAPI_ShapeTools::combineShapes(const std::shared_ptr aTA = TopAbs_SOLID; } - // Map subshapes and shapes. + theCombinedShapes.clear(); + theFreeShapes.clear(); + + // Get free shapes. const TopoDS_Shape& aShapesComp = theCompound->impl(); - BOPCol_IndexedDataMapOfShapeListOfShape aMapEF; - BOPTools::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapEF); - if(aMapEF.IsEmpty()) { - return; + for(TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next() ) { + const TopoDS_Shape& aShape = anIter.Value(); + if(aShape.ShapeType() > aTA) { + std::shared_ptr aGeomShape(new GeomAPI_Shape); + aGeomShape->setImpl(new TopoDS_Shape(aShape)); + theFreeShapes.push_back(aGeomShape); + } + } + + // Map subshapes and shapes. + TopTools_IndexedDataMapOfShapeListOfShape aMapSA; + TopExp::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA); + if(aMapSA.IsEmpty()) { + return aResult; } // Get all shapes with common subshapes and free shapes. NCollection_Map aFreeShapes; NCollection_Vector> aShapesWithCommonSubshapes; - for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator anIter(aMapEF); anIter.More(); anIter.Next()) { + for(TopTools_IndexedDataMapOfShapeListOfShape::Iterator + anIter(aMapSA); anIter.More(); anIter.Next()) { const TopoDS_Shape& aShape = anIter.Key(); - BOPCol_ListOfShape& aListOfShape = anIter.ChangeValue(); + TopTools_ListOfShape& aListOfShape = anIter.ChangeValue(); if(aListOfShape.IsEmpty()) { continue; } @@ -109,38 +258,39 @@ void GeomAlgoAPI_ShapeTools::combineShapes(const std::shared_ptr } 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 aTempIter(aTempList); aTempIter.More(); aTempIter.Next()) { + for(NCollection_List::Iterator + aTempIter(aTempList); aTempIter.More(); aTempIter.Next()) { const TopoDS_Shape& aTempShape = aTempIter.Value(); - for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator anIter(aMapEF); anIter.More(); anIter.Next()) { - BOPCol_ListOfShape& aTempListOfShape = anIter.ChangeValue(); + for(TopTools_IndexedDataMapOfShapeListOfShape::Iterator + anIter(aMapSA); anIter.More(); anIter.Next()) { + TopTools_ListOfShape& aTempListOfShape = anIter.ChangeValue(); if(aTempListOfShape.IsEmpty()) { continue; } 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); + 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(); } } } @@ -150,21 +300,25 @@ void GeomAlgoAPI_ShapeTools::combineShapes(const std::shared_ptr } // Combine shapes with common subshapes. - for(NCollection_Vector>::Iterator anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) { + for(NCollection_Vector>::Iterator + anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) { TopoDS_Shell aShell; TopoDS_CompSolid aCSolid; TopoDS_Builder aBuilder; - theType == GeomAPI_Shape::COMPSOLID ? aBuilder.MakeCompSolid(aCSolid) : aBuilder.MakeShell(aShell); + 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()) { const TopoDS_Shape& aShape = anExp.Current(); if(aShapesMap.Contains(aShape)) { - theType == GeomAPI_Shape::COMPSOLID ? aBuilder.Add(aCSolid, aShape) : aBuilder.Add(aShell, aShape); + theType == + GeomAPI_Shape::COMPSOLID ? aBuilder.Add(aCSolid, aShape) : aBuilder.Add(aShell, aShape); aShapesMap.Remove(aShape); } } std::shared_ptr aGeomShape(new GeomAPI_Shape); - TopoDS_Shape* aSh = theType == GeomAPI_Shape::COMPSOLID ? new TopoDS_Shape(aCSolid) : new TopoDS_Shape(aShell); + TopoDS_Shape* aSh = theType == GeomAPI_Shape::COMPSOLID ? new TopoDS_Shape(aCSolid) : + new TopoDS_Shape(aShell); aGeomShape->setImpl(aSh); theCombinedShapes.push_back(aGeomShape); } @@ -178,16 +332,202 @@ void GeomAlgoAPI_ShapeTools::combineShapes(const std::shared_ptr theFreeShapes.push_back(aGeomShape); } } + + if(theCombinedShapes.size() == 1 && theFreeShapes.size() == 0) { + aResult = theCombinedShapes.front(); + } else if(theCombinedShapes.size() == 0 && theFreeShapes.size() == 1) { + aResult = theFreeShapes.front(); + } 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()); + } + aResult->setImpl(new TopoDS_Shape(aResultComp)); + } + + return aResult; } -//================================================================================================= -std::list > GeomAlgoAPI_ShapeTools::getBoundingBox(const ListOfShape& theShapes, const double theEnlarge) +//================================================================================================== +static void addSimpleShapeToList(const TopoDS_Shape& theShape, + NCollection_List& theList) +{ + if(theShape.IsNull()) { + return; + } + + if(theShape.ShapeType() == TopAbs_COMPOUND) { + for(TopoDS_Iterator anIt(theShape); anIt.More(); anIt.Next()) { + addSimpleShapeToList(anIt.Value(), theList); + } + } else { + theList.Append(theShape); + } +} + +//================================================================================================== +static TopoDS_Compound makeCompound(const NCollection_List theShapes) +{ + TopoDS_Compound aCompound; + + BRep_Builder aBuilder; + aBuilder.MakeCompound(aCompound); + + for(NCollection_List::Iterator anIt(theShapes); anIt.More(); anIt.Next()) { + aBuilder.Add(aCompound, anIt.Value()); + } + + return aCompound; +} + +//================================================================================================== +std::shared_ptr GeomAlgoAPI_ShapeTools::groupSharedTopology( + const std::shared_ptr theCompound) +{ + GeomShapePtr aResult = theCompound; + + if (!theCompound.get()) { + return aResult; + } + + TopoDS_Shape anInShape = aResult->impl(); + NCollection_List anUngroupedShapes, aStillUngroupedShapes; + addSimpleShapeToList(anInShape, anUngroupedShapes); + + // Iterate over all shapes and find shapes with shared vertices. + 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()) { + const TopoDS_Shape& aVertex = aShapeExp.Current(); + if (!aVertexShapesMap.IsBound(aVertex)) { + NCollection_List aList; + aList.Append(aShape); + allVertices.Append(aVertex); + aVertexShapesMap.Bind(aVertex, aList); + } + else { + if (!aVertexShapesMap.ChangeFind(aVertex).Contains(aShape)) { + aVertexShapesMap.ChangeFind(aVertex).Append(aShape); + } + } + } + } + + // Iterate over the map and group shapes. + 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 = allVertices.First(); + TopTools_ListOfShape aConnectedShapes = aVertexShapesMap.Find(aKey); + aVertexShapesMap.UnBind(aKey); + allVertices.Remove(aKey); + // Iterate over shapes in this group and add to it shapes from groups in map. + for (TopTools_ListOfShape::Iterator aConnectedIt(aConnectedShapes); + aConnectedIt.More(); aConnectedIt.Next()) { + const TopoDS_Shape& aConnected = aConnectedIt.Value(); + TopTools_ListOfShape aKeysToUnbind; + 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 containt shape from our connected group + continue; + } + // 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()) { + aVertexShapesMap.UnBind(aKeysIt.Value()); + allVertices.Remove(aKeysIt.Value()); + } + } + // 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.Add(anIt.Value()); + aConnectedShapes.Remove(anIt); + } + else { + anIt.Next(); + } + } + } + aGroups.Append(aSortedGroup); + } + + TopoDS_Compound aCompound; + BRep_Builder aBuilder; + aBuilder.MakeCompound(aCompound); + ListOfShape aCompSolids, aFreeSolids; + 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) { + TopTools_MapOfShape::Iterator aOneShapeIter(aGroup); + aGeomShape->setImpl(new TopoDS_Shape(aOneShapeIter.Value())); + } else { + // 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); + } + aBuilder.Add(aCompound, aGeomShape->impl()); + } + + if(!aCompound.IsNull()) { + aResult->setImpl(new TopoDS_Shape(aCompound)); + } + + return aResult; +} + +//================================================================================================== +std::list > + GeomAlgoAPI_ShapeTools::getBoundingBox(const ListOfShape& theShapes, const double theEnlarge) { // Bounding box of all objects. Bnd_Box aBndBox; // Getting box. - for (ListOfShape::const_iterator anObjectsIt = theShapes.begin(); anObjectsIt != theShapes.end(); anObjectsIt++) { + for (ListOfShape::const_iterator + anObjectsIt = theShapes.begin(); anObjectsIt != theShapes.end(); anObjectsIt++) { const TopoDS_Shape& aShape = (*anObjectsIt)->impl(); BRepBndLib::Add(aShape, aBndBox); } @@ -214,8 +554,9 @@ std::list > GeomAlgoAPI_ShapeTools::getBoundingBox( return aResultPoints; } -//================================================================================================= -std::shared_ptr GeomAlgoAPI_ShapeTools::faceToInfinitePlane(const std::shared_ptr theFace) +//================================================================================================== +std::shared_ptr + GeomAlgoAPI_ShapeTools::faceToInfinitePlane(const std::shared_ptr theFace) { if (!theFace.get()) return std::shared_ptr(); @@ -236,34 +577,35 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::faceToInfinitePlane(const return aResult; } -//================================================================================================= -std::shared_ptr GeomAlgoAPI_ShapeTools::fitPlaneToBox(const std::shared_ptr thePlane, - const std::list >& thePoints) +//================================================================================================== +std::shared_ptr GeomAlgoAPI_ShapeTools::fitPlaneToBox( + const std::shared_ptr thePlane, + const std::list >& thePoints) { - std::shared_ptr aResultShape; + std::shared_ptr aResultFace; if(!thePlane.get()) { - return aResultShape; + return aResultFace; } const TopoDS_Shape& aShape = thePlane->impl(); if(aShape.ShapeType() != TopAbs_FACE) { - return aResultShape; + return aResultFace; } TopoDS_Face aFace = TopoDS::Face(aShape); Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace); if(aSurf.IsNull()) { - return aResultShape; + return aResultFace; } GeomLib_IsPlanarSurface isPlanar(aSurf); if(!isPlanar.IsPlanar()) { - return aResultShape; + return aResultFace; } if(thePoints.size() != 8) { - return aResultShape; + return aResultFace; } const gp_Pln& aFacePln = isPlanar.Plan(); @@ -271,7 +613,8 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::fitPlaneToBox(const std:: IntAna_Quadric aQuadric(aFacePln); Standard_Real UMin, UMax, VMin, VMax; UMin = UMax = VMin = VMax = 0; - for (std::list >::const_iterator aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) { + for (std::list >::const_iterator + aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) { const gp_Pnt& aPnt = (*aPointsIt)->impl(); gp_Lin aLin(aPnt, aFacePln.Axis().Direction()); IntAna_IntConicQuad anIntAna(aLin, aQuadric); @@ -283,8 +626,464 @@ std::shared_ptr GeomAlgoAPI_ShapeTools::fitPlaneToBox(const std:: if(aPntV < VMin) VMin = aPntV; if(aPntV > VMax) VMax = aPntV; } - aResultShape.reset(new GeomAPI_Shape); - aResultShape->setImpl(new TopoDS_Shape(BRepLib_MakeFace(aFacePln, UMin, UMax, VMin, VMax).Face())); + aResultFace.reset(new GeomAPI_Face()); + aResultFace->setImpl(new TopoDS_Face(BRepLib_MakeFace(aFacePln, UMin, UMax, VMin, VMax).Face())); + + return aResultFace; +} + +//================================================================================================== +void GeomAlgoAPI_ShapeTools::findBounds(const std::shared_ptr theShape, + std::shared_ptr& theV1, + std::shared_ptr& theV2) +{ + if(!theShape.get()) { + std::shared_ptr aVertex(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); + + 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; +} + +//================================================================================================== +void GeomAlgoAPI_ShapeTools::makeFacesWithHoles(const std::shared_ptr theOrigin, + const std::shared_ptr theDirection, + const ListOfShape& theWires, + ListOfShape& theFaces) +{ + BRepBuilderAPI_MakeFace aMKFace(gp_Pln(theOrigin->impl(), + theDirection->impl())); + TopoDS_Face aFace = aMKFace.Face(); + + BRepAlgo_FaceRestrictor aFRestrictor; + aFRestrictor.Init(aFace, Standard_False, Standard_True); + for(ListOfShape::const_iterator anIt = theWires.cbegin(); + anIt != theWires.cend(); + ++anIt) { + TopoDS_Wire aWire = TopoDS::Wire((*anIt)->impl()); + aFRestrictor.Add(aWire); + } + + aFRestrictor.Perform(); + + if(!aFRestrictor.IsDone()) { + return; + } + + for(; aFRestrictor.More(); aFRestrictor.Next()) { + GeomShapePtr aShape(new GeomAPI_Shape()); + aShape->setImpl(new TopoDS_Shape(aFRestrictor.Current())); + theFaces.push_back(aShape); + } +} + +//================================================================================================== +std::shared_ptr GeomAlgoAPI_ShapeTools::findPlane(const ListOfShape& theShapes) +{ + TopoDS_Compound aCompound; + BRep_Builder aBuilder; + aBuilder.MakeCompound(aCompound); + + 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) { + return std::shared_ptr(); + } + + Handle(Geom_Plane) aPlane = aFindPlane.Plane(); + gp_Pnt aLoc = aPlane->Location(); + gp_Dir aDir = aPlane->Axis().Direction(); + + std::shared_ptr aGeomPnt(new GeomAPI_Pnt(aLoc.X(), aLoc.Y(), aLoc.Z())); + std::shared_ptr aGeomDir(new GeomAPI_Dir(aDir.X(), aDir.Y(), aDir.Z())); + + std::shared_ptr aPln(new GeomAPI_Pln(aGeomPnt, aGeomDir)); + + return aPln; +} + +//================================================================================================== +bool GeomAlgoAPI_ShapeTools::isSubShapeInsideShape( + const std::shared_ptr theSubShape, + const std::shared_ptr theBaseShape) +{ + 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 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()) { + return false; + } + } else if (aSubShape.ShapeType() == TopAbs_EDGE) { + 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()) { + return false; + } + + // Check intersections. + TopoDS_Vertex aV1, aV2; + 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()) { + const TopoDS_Shape& anEdgeOnFace = anExp.Current(); + BRepExtrema_DistShapeShape aDist(anEdgeOnFace, anEdge); + aDist.Perform(); + 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) { + gp_Pnt aPntOnSubShape = aDist.PointOnShape2(anIndex); + if(aPntOnSubShape.Distance(aPnt1) > Precision::Confusion() + && aPntOnSubShape.Distance(aPnt2) > Precision::Confusion()) { + return false; + } + } + } + } + + // No intersections found. Edge is inside or outside face. Check it. + BRepAdaptor_Curve aCurveAdaptor(anEdge); + gp_Pnt aPointToCheck = + aCurveAdaptor.Value((aCurveAdaptor.FirstParameter() + + aCurveAdaptor.LastParameter()) / 2.0); + Handle(Geom_Surface) aSurface = BRep_Tool::Surface(aFace); + ShapeAnalysis_Surface aSAS(aSurface); + gp_Pnt2d aPointOnFace = aSAS.ValueOfUV(aPointToCheck, Precision::Confusion()); + BRepTopAdaptor_FClass2d aFClass2d(aFace, Precision::Confusion()); + if(aFClass2d.Perform(aPointOnFace) == TopAbs_OUT) { + return false; + } + + } else { + return false; + } + } else { + return false; + } + + return true; +} + +//================================================================================================== +bool GeomAlgoAPI_ShapeTools::isShapeValid(const std::shared_ptr theShape) +{ + if(!theShape.get()) { + return false; + } + + BRepCheck_Analyzer aChecker(theShape->impl()); + return (aChecker.IsValid() == Standard_True); +} + +//================================================================================================== +std::shared_ptr + GeomAlgoAPI_ShapeTools::getFaceOuterWire(const std::shared_ptr theFace) +{ + GeomShapePtr anOuterWire; + + if(!theFace.get() || !theFace->isFace()) { + return anOuterWire; + } + + TopoDS_Face aFace = TopoDS::Face(theFace->impl()); + TopoDS_Wire aWire = BRepTools::OuterWire(aFace); + + anOuterWire.reset(new GeomAPI_Shape()); + anOuterWire->setImpl(new TopoDS_Shape(aWire)); + + return anOuterWire; +} + +//================================================================================================== +bool GeomAlgoAPI_ShapeTools::isParallel(const std::shared_ptr theEdge, + const std::shared_ptr theFace) +{ + if(!theEdge.get() || !theFace.get()) { + return false; + } + + TopoDS_Edge anEdge = TopoDS::Edge(theEdge->impl()); + TopoDS_Face aFace = TopoDS::Face(theFace->impl()); + + BRepExtrema_ExtCF anExt(anEdge, aFace); + return anExt.IsParallel() == Standard_True; +} + +//================================================================================================== +std::list > GeomAlgoAPI_ShapeTools::intersect( + const std::shared_ptr theEdge, const std::shared_ptr theFace, + const bool thePointsOutsideFace) +{ + std::list > aResult; + if(!theEdge.get() || !theFace.get()) { + return aResult; + } + + TopoDS_Edge anEdge = TopoDS::Edge(theEdge->impl()); + double aFirstOnCurve, aLastOnCurve; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(anEdge, aFirstOnCurve, aLastOnCurve); + + TopoDS_Face aFace = TopoDS::Face(theFace->impl()); + Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace); + + GeomAPI_IntCS anIntAlgo(aCurve, aSurf); + if (!anIntAlgo.IsDone()) + return aResult; + // searching for points-intersection + for(int anIntNum = 1; anIntNum <= anIntAlgo.NbPoints() + anIntAlgo.NbSegments(); anIntNum++) { + gp_Pnt anInt; + if (anIntNum <= anIntAlgo.NbPoints()) { + anInt = anIntAlgo.Point(anIntNum); + } else { // take the middle point on the segment of the intersection + Handle(Geom_Curve) anIntCurve = anIntAlgo.Segment(anIntNum - anIntAlgo.NbPoints()); + anIntCurve->D0((anIntCurve->FirstParameter() + anIntCurve->LastParameter()) / 2., anInt); + } + aResult.push_back(std::shared_ptr( + new GeomAPI_Vertex(anInt.X(), anInt.Y(), anInt.Z()))); + } + return aResult; +} + +//================================================================================================== +void GeomAlgoAPI_ShapeTools::splitShape(const std::shared_ptr& theBaseShape, + const GeomAlgoAPI_ShapeTools::PointToRefsMap& thePointsInfo, + std::set >& theShapes) +{ + // to split shape at least one point should be presented in the points container + if (thePointsInfo.empty()) + return; + + // General Fuse to split edge by vertices + BOPAlgo_Builder aBOP; + TopoDS_Edge aBaseEdge = theBaseShape->impl(); + // Rebuild closed edge to place vertex to one of split points. + // This will prevent edge to be split on same vertex. + if (BRep_Tool::IsClosed(aBaseEdge)) + { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aBaseEdge, aFirst, aLast); + + PointToRefsMap::const_iterator aPIt = thePointsInfo.begin(); + std::shared_ptr aPnt = aPIt->first; + gp_Pnt aPoint(aPnt->x(), aPnt->y(), aPnt->z()); + + TopAbs_Orientation anOrientation = aBaseEdge.Orientation(); + aBaseEdge = BRepBuilderAPI_MakeEdge(aCurve, aPoint, aPoint).Edge(); + aBaseEdge.Orientation(anOrientation); + } + aBOP.AddArgument(aBaseEdge); + + PointToRefsMap::const_iterator aPIt = thePointsInfo.begin(); + for (; aPIt != thePointsInfo.end(); ++aPIt) { + std::shared_ptr aPnt = aPIt->first; + TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(aPnt->x(), aPnt->y(), aPnt->z())); + aBOP.AddArgument(aV); + } + + aBOP.Perform(); + if (aBOP.HasErrors()) + return; + + // Collect splits + const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge); + TopTools_ListIteratorOfListOfShape anIt(aSplits); + for (; anIt.More(); anIt.Next()) { + std::shared_ptr anEdge(new GeomAPI_Shape); + anEdge->setImpl(new TopoDS_Shape(anIt.Value())); + theShapes.insert(anEdge); + } +} + +//================================================================================================== +void GeomAlgoAPI_ShapeTools::splitShape_p(const std::shared_ptr& theBaseShape, + const std::list >& thePoints, + std::set >& theShapes) +{ + // General Fuse to split edge by vertices + BOPAlgo_Builder aBOP; + TopoDS_Edge aBaseEdge = theBaseShape->impl(); + // Rebuild closed edge to place vertex to one of split points. + // This will prevent edge to be split on seam vertex. + if (BRep_Tool::IsClosed(aBaseEdge)) + { + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(aBaseEdge, aFirst, aLast); + + std::list >::const_iterator aPIt = thePoints.begin(); + gp_Pnt aPoint((*aPIt)->x(), (*aPIt)->y(), (*aPIt)->z()); + + TopAbs_Orientation anOrientation = aBaseEdge.Orientation(); + aBaseEdge = BRepBuilderAPI_MakeEdge(aCurve, aPoint, aPoint).Edge(); + aBaseEdge.Orientation(anOrientation); + } + aBOP.AddArgument(aBaseEdge); + + std::list >::const_iterator aPtIt = thePoints.begin(); + for (; aPtIt != thePoints.end(); ++aPtIt) { + std::shared_ptr aPnt = *aPtIt; + TopoDS_Vertex aV = BRepBuilderAPI_MakeVertex(gp_Pnt(aPnt->x(), aPnt->y(), aPnt->z())); + aBOP.AddArgument(aV); + } + + aBOP.Perform(); + if (aBOP.HasErrors()) + return; + + // Collect splits + const TopTools_ListOfShape& aSplits = aBOP.Modified(aBaseEdge); + TopTools_ListIteratorOfListOfShape anIt(aSplits); + for (; anIt.More(); anIt.Next()) { + std::shared_ptr anEdge(new GeomAPI_Shape); + anEdge->setImpl(new TopoDS_Shape(anIt.Value())); + theShapes.insert(anEdge); + } +} + +//================================================================================================== +std::shared_ptr GeomAlgoAPI_ShapeTools::findShape( + const std::list >& thePoints, + const std::set >& theShapes) +{ + std::shared_ptr aResultShape; + + if (thePoints.size() == 2) { + std::list >::const_iterator aPntIt = thePoints.begin(); + std::shared_ptr aFirstPoint = *aPntIt; + aPntIt++; + std::shared_ptr aLastPoint = *aPntIt; + + std::set >::const_iterator anIt = theShapes.begin(), + aLast = theShapes.end(); + for (; anIt != aLast; anIt++) { + GeomShapePtr aShape = *anIt; + std::shared_ptr anEdge(new GeomAPI_Edge(aShape)); + if (anEdge.get()) { + std::shared_ptr anEdgeFirstPoint = anEdge->firstPoint(); + std::shared_ptr anEdgeLastPoint = anEdge->lastPoint(); + if (anEdgeFirstPoint->isEqual(aFirstPoint) && + anEdgeLastPoint->isEqual(aLastPoint)) + aResultShape = aShape; + } + } + } return aResultShape; } + +//================================================================================================== +std::shared_ptr GeomAlgoAPI_ShapeTools::buildDirFromAxisAndShape( + const std::shared_ptr theBaseShape, + const std::shared_ptr theAxis) +{ + gp_Pnt aCentreOfMassPoint = + GeomAlgoAPI_ShapeTools::centreOfMass(theBaseShape)->impl(); + Handle(Geom_Line) aLine = new Geom_Line(theAxis->impl()); + GeomAPI_ProjectPointOnCurve aPrjTool(aCentreOfMassPoint, aLine); + gp_Pnt aPoint = aPrjTool.NearestPoint(); + + std::shared_ptr aDir(new GeomAPI_Dir(aCentreOfMassPoint.X()-aPoint.X(), + aCentreOfMassPoint.Y()-aPoint.Y(), + aCentreOfMassPoint.Z()-aPoint.Z())); + return aDir; +} + +//================================================================================================== +static TopoDS_Wire fixParametricGaps(const TopoDS_Wire& theWire) +{ + TopoDS_Wire aFixedWire; + Handle(Geom_Curve) aPrevCurve; + double aPrevLastParam = 0.0; + + 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) { + // 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(); + // 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); + TopoDS_Edge aNewEdge = BRepAlgo::ConcatenateWireC0(aWire); + 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; +} \ No newline at end of file