X-Git-Url: http://git.salome-platform.org/gitweb/?a=blobdiff_plain;f=src%2FGeomAPI%2FGeomAPI_Shape.cpp;h=3fb717b753f7e05d5b41f579de458b58c91e367f;hb=HEAD;hp=fd1d6adeb9fc13d4430149af8e9b0ef1b65b8a29;hpb=87b6a30a3afb8fb32e7e43ade8d9c947d9eb1684;p=modules%2Fshaper.git diff --git a/src/GeomAPI/GeomAPI_Shape.cpp b/src/GeomAPI/GeomAPI_Shape.cpp index fd1d6adeb..3fb717b75 100644 --- a/src/GeomAPI/GeomAPI_Shape.cpp +++ b/src/GeomAPI/GeomAPI_Shape.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,18 +12,29 @@ // // 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 "GeomAPI_Shape.h" +#include + +#include +#include +#include +#include +#include +#include +#include +#include + #include #include #include #include +#include #include #include #include @@ -37,17 +48,20 @@ #include #include #include +#include #include #include #include #include #include +#include +#include +#include + #include #include // for std::transform -#include - #define MY_SHAPE implPtr() GeomAPI_Shape::GeomAPI_Shape() @@ -81,16 +95,24 @@ bool GeomAPI_Shape::isEqual(const std::shared_ptr theShape) const bool GeomAPI_Shape::isSame(const std::shared_ptr theShape) const { - if (!theShape.get()) - return false; + bool isNullShape = !theShape.get() || theShape->isNull();; if (isNull()) - return theShape->isNull(); - if (theShape->isNull()) + return isNullShape; + if (isNullShape) return false; return MY_SHAPE->IsSame(theShape->impl()) == Standard_True; } +bool GeomAPI_Shape::isSameGeometry(const std::shared_ptr theShape) const +{ + if (isFace()) + return face()->isSameGeometry(theShape); + else if (isEdge()) + return edge()->isSameGeometry(theShape); + return false; +} + bool GeomAPI_Shape::isVertex() const { const TopoDS_Shape& aShape = const_cast(this)->impl(); @@ -103,18 +125,56 @@ bool GeomAPI_Shape::isEdge() const return !aShape.IsNull() && aShape.ShapeType() == TopAbs_EDGE; } +bool GeomAPI_Shape::isWire() const +{ + const TopoDS_Shape& aShape = const_cast(this)->impl(); + return !aShape.IsNull() && aShape.ShapeType() == TopAbs_WIRE; +} + bool GeomAPI_Shape::isFace() const { const TopoDS_Shape& aShape = const_cast(this)->impl(); return !aShape.IsNull() && aShape.ShapeType() == TopAbs_FACE; } +bool GeomAPI_Shape::isShell() const +{ + const TopoDS_Shape& aShape = const_cast(this)->impl(); + return !aShape.IsNull() && aShape.ShapeType() == TopAbs_SHELL; +} + bool GeomAPI_Shape::isCompound() const { const TopoDS_Shape& aShape = const_cast(this)->impl(); return !aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPOUND; } +bool GeomAPI_Shape::isCollectionOfSolids() const +{ + const TopoDS_Shape& aShape = const_cast(this)->impl(); + if (aShape.IsNull()) + return false; + + if (aShape.ShapeType() == TopAbs_SOLID || + aShape.ShapeType() == TopAbs_COMPSOLID) + return true; + + if (aShape.ShapeType() != TopAbs_COMPOUND) + return false; + + TopTools_ListOfShape aLS; + TopTools_MapOfShape aMFence; + BOPTools_AlgoTools::TreatCompound(aShape, aLS, &aMFence); + TopTools_ListOfShape::Iterator it(aLS); + for (; it.More(); it.Next()) { + const TopoDS_Shape& aSx = it.Value(); + if (aSx.ShapeType() != TopAbs_SOLID && + aSx.ShapeType() != TopAbs_COMPSOLID) + return false; + } + return true; +} + bool GeomAPI_Shape::isCompoundOfSolids() const { const TopoDS_Shape& aShape = const_cast(this)->impl(); @@ -129,6 +189,25 @@ bool GeomAPI_Shape::isCompoundOfSolids() const return isAtLeastOne; } +// LCOV_EXCL_START +GeomAPI_Shape::ShapeType GeomAPI_Shape::typeOfCompoundShapes() const +{ + const TopoDS_Shape& aShape = const_cast(this)->impl(); + if (aShape.IsNull() || aShape.ShapeType() != TopAbs_COMPOUND) + return SHAPE; + int aType = -1; + for(TopoDS_Iterator aSubs(aShape); aSubs.More(); aSubs.Next()) { + if (!aSubs.Value().IsNull()) { + if (aType == -1) + aType = aSubs.Value().ShapeType(); + else if (aSubs.Value().ShapeType() != aType) + return SHAPE; + } + } + return (GeomAPI_Shape::ShapeType) aType; +} +// LCOV_EXCL_STOP + // adds the nopt-compound elements recursively to the list static void addSimpleToList(const TopoDS_Shape& theShape, NCollection_List& theList) { @@ -176,9 +255,9 @@ bool GeomAPI_Shape::isConnectedTopology() const // (if shapes are connected, vertices are connected for sure) TopExp_Explorer anExp2(aNewIter.Value(), TopAbs_VERTEX); for(; !aConnected && anExp2.More(); anExp2.Next()) { - NCollection_List::Iterator aNotIter(aNotVertices); - for(; aNotIter.More(); aNotIter.Next()) { - if (aNotIter.Value().IsSame(anExp2.Current())) { + NCollection_List::Iterator aNotVIter(aNotVertices); + for(; aNotVIter.More(); aNotVIter.Next()) { + if (aNotVIter.Value().IsSame(anExp2.Current())) { aConnected = true; break; } @@ -236,36 +315,61 @@ bool GeomAPI_Shape::isPlanar() const if(aShapeType == TopAbs_VERTEX) { return true; } else if(aShapeType == TopAbs_FACE) { - const Handle(Geom_Surface)& aSurface = BRep_Tool::Surface(TopoDS::Face(aShape)); - Handle(Standard_Type) aType = aSurface->DynamicType(); - - if(aType == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) { + Handle(Geom_Surface) aSurface = BRep_Tool::Surface(TopoDS::Face(aShape)); + if(aSurface->DynamicType() == STANDARD_TYPE(Geom_RectangularTrimmedSurface)) { Handle(Geom_RectangularTrimmedSurface) aTrimSurface = - Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface); - aType = aTrimSurface->BasisSurface()->DynamicType(); + Handle(Geom_RectangularTrimmedSurface)::DownCast(aSurface); + aSurface = aTrimSurface->BasisSurface(); } - return (aType == STANDARD_TYPE(Geom_Plane)) == Standard_True; + return GeomLib_IsPlanarSurface(aSurface).IsPlanar(); } else { BRepBuilderAPI_FindPlane aFindPlane(aShape); bool isFound = aFindPlane.Found() == Standard_True; - if(!isFound && aShapeType == TopAbs_EDGE) { - Standard_Real aFirst, aLast; - Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(aShape), aFirst, aLast); - Handle(Standard_Type) aType = aCurve->DynamicType(); + if(!isFound) { - if(aType == STANDARD_TYPE(Geom_TrimmedCurve)) { - Handle(Geom_TrimmedCurve) aTrimCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve); - aType = aTrimCurve->BasisCurve()->DynamicType(); - } + auto checkEdge = [](const TopoDS_Shape& theShape){ + if(theShape.ShapeType()!= TopAbs_EDGE) + return false; + + Standard_Real aFirst, aLast; + Handle(Geom_Curve) aCurve = BRep_Tool::Curve(TopoDS::Edge(theShape), aFirst, aLast); + Handle(Standard_Type) aType = aCurve->DynamicType(); + if(aType == STANDARD_TYPE(Geom_TrimmedCurve)) { + Handle(Geom_TrimmedCurve) aTrimCurve = Handle(Geom_TrimmedCurve)::DownCast(aCurve); + aType = aTrimCurve->BasisCurve()->DynamicType(); + } - if(aType == STANDARD_TYPE(Geom_Line) - || aType == STANDARD_TYPE(Geom_Conic) - || aType == STANDARD_TYPE(Geom_Circle) - || aType == STANDARD_TYPE(Geom_Ellipse) - || aType == STANDARD_TYPE(Geom_Hyperbola) - || aType == STANDARD_TYPE(Geom_Parabola)) { - isFound = true; + if(aType == STANDARD_TYPE(Geom_Line) + || aType == STANDARD_TYPE(Geom_Conic) + || aType == STANDARD_TYPE(Geom_Circle) + || aType == STANDARD_TYPE(Geom_Ellipse) + || aType == STANDARD_TYPE(Geom_Hyperbola) + || aType == STANDARD_TYPE(Geom_Parabola)) { + return true; + } + return false; + }; + + if(aShapeType == TopAbs_WIRE){ + //check if wire consist of only one edge + int aNbEdges = 0; + TopExp_Explorer anExp(aShape, TopAbs_EDGE); + for (TopExp_Explorer anExp(aShape, TopAbs_EDGE); anExp.More(); anExp.Next()) { + aNbEdges++; + if(aNbEdges == 1){ + const TopoDS_Edge& anEdge = TopoDS::Edge(anExp.Current()); + isFound = checkEdge(anEdge); + } + else{ + //if more than one edge, check is not valid + isFound = false; + break; + } + } + } + else if(aShapeType == TopAbs_EDGE){ + isFound = checkEdge(aShape); } } @@ -275,9 +379,117 @@ bool GeomAPI_Shape::isPlanar() const return false; } +std::shared_ptr GeomAPI_Shape::vertex() const +{ + GeomVertexPtr aVertex; + if (isVertex()) { + const TopoDS_Shape& aShape = const_cast(this)->impl(); + aVertex = GeomVertexPtr(new GeomAPI_Vertex); + aVertex->setImpl(new TopoDS_Shape(aShape)); + } + return aVertex; +} + +std::shared_ptr GeomAPI_Shape::edge() const +{ + GeomEdgePtr anEdge; + if (isEdge()) { + const TopoDS_Shape& aShape = const_cast(this)->impl(); + anEdge = GeomEdgePtr(new GeomAPI_Edge); + anEdge->setImpl(new TopoDS_Shape(aShape)); + } + return anEdge; +} + +std::shared_ptr GeomAPI_Shape::wire() const +{ + GeomWirePtr aWire; + if (isWire()) { + const TopoDS_Shape& aShape = const_cast(this)->impl(); + aWire = GeomWirePtr(new GeomAPI_Wire); + aWire->setImpl(new TopoDS_Shape(aShape)); + } + return aWire; +} + +std::shared_ptr GeomAPI_Shape::face() const +{ + GeomFacePtr aFace; + if (isFace()) { + const TopoDS_Shape& aShape = const_cast(this)->impl(); + aFace = GeomFacePtr(new GeomAPI_Face); + aFace->setImpl(new TopoDS_Shape(aShape)); + } + return aFace; +} + +std::shared_ptr GeomAPI_Shape::shell() const +{ + GeomShellPtr aShell; + if (isShell()) { + const TopoDS_Shape& aShape = const_cast(this)->impl(); + aShell = GeomShellPtr(new GeomAPI_Shell); + aShell->setImpl(new TopoDS_Shape(aShape)); + } + return aShell; +} + +std::shared_ptr GeomAPI_Shape::solid() const +{ + GeomSolidPtr aSolid; + if (isSolid()) { + const TopoDS_Shape& aShape = const_cast(this)->impl(); + aSolid = GeomSolidPtr(new GeomAPI_Solid); + aSolid->setImpl(new TopoDS_Shape(aShape)); + } + return aSolid; +} + +std::list > +GeomAPI_Shape::subShapes(const ShapeType theSubShapeType, const bool theOnlyUnique) const +{ + ListOfShape aSubs; + const TopoDS_Shape& aShape = impl(); + if (aShape.IsNull()) + return aSubs; + + TopTools_MapOfShape alreadyThere; + + // process multi-level compounds + if (shapeType() == COMPOUND && theSubShapeType == COMPOUND) { + for (TopoDS_Iterator anIt(aShape); anIt.More(); anIt.Next()) { + const TopoDS_Shape& aCurrent = anIt.Value(); + if (aCurrent.ShapeType() == TopAbs_COMPOUND) { + if (!theOnlyUnique || alreadyThere.Add(aCurrent)) { + GeomShapePtr aSub(new GeomAPI_Shape); + aSub->setImpl(new TopoDS_Shape(aCurrent)); + aSubs.push_back(aSub); + } + } + } + // add self + GeomShapePtr aSub(new GeomAPI_Shape); + aSub->setImpl(new TopoDS_Shape(aShape)); + aSubs.push_back(aSub); + } + else { + for (TopExp_Explorer anExp(aShape, (TopAbs_ShapeEnum)theSubShapeType); + anExp.More(); anExp.Next()) { + if (!theOnlyUnique || alreadyThere.Add(anExp.Current())) { + GeomShapePtr aSub(new GeomAPI_Shape); + aSub->setImpl(new TopoDS_Shape(anExp.Current())); + aSubs.push_back(aSub); + } + } + } + return aSubs; +} + GeomAPI_Shape::ShapeType GeomAPI_Shape::shapeType() const { const TopoDS_Shape& aShape = impl(); + if (aShape.IsNull()) + return GeomAPI_Shape::SHAPE; ShapeType aST = GeomAPI_Shape::SHAPE; @@ -316,22 +528,23 @@ GeomAPI_Shape::ShapeType GeomAPI_Shape::shapeType() const GeomAPI_Shape::ShapeType GeomAPI_Shape::shapeTypeByStr(std::string theType) { - std::transform(theType.begin(), theType.end(), theType.begin(), ::toupper); - if (theType == "COMPOUND") + std::transform(theType.begin(), theType.end(), theType.begin(), + [](char c) { return static_cast(::toupper(c)); }); + if (theType == "COMPOUND" || theType == "COMPOUNDS") return COMPOUND; - if (theType == "COMPSOLID") + if (theType == "COMPSOLID" || theType == "COMPSOLIDS") return COMPSOLID; - if (theType == "SOLID") + if (theType == "SOLID" || theType == "SOLIDS") return SOLID; - if (theType == "SHELL") + if (theType == "SHELL" || theType == "SHELLS") return SHELL; - if (theType == "FACE") + if (theType == "FACE" || theType == "FACES") return FACE; - if (theType == "WIRE") + if (theType == "WIRE" || theType == "WIRES") return WIRE; - if (theType == "EDGE") + if (theType == "EDGE" || theType == "EDGES") return EDGE; - if (theType == "VERTEX") + if (theType == "VERTEX" || theType == "VERTICES") return VERTEX; return SHAPE; // default } @@ -398,8 +611,6 @@ GeomAPI_Shape::Orientation GeomAPI_Shape::orientation() const void GeomAPI_Shape::setOrientation(const GeomAPI_Shape::Orientation theOrientation) { - TopAbs_Orientation anOrientation = MY_SHAPE->Orientation(); - switch(theOrientation) { case FORWARD: MY_SHAPE->Orientation(TopAbs_FORWARD); break; case REVERSED: MY_SHAPE->Orientation(TopAbs_REVERSED); break; @@ -408,7 +619,13 @@ void GeomAPI_Shape::setOrientation(const GeomAPI_Shape::Orientation theOrientati } } -bool GeomAPI_Shape::isSubShape(const std::shared_ptr theShape) const +void GeomAPI_Shape::reverse() +{ + MY_SHAPE->Reverse(); +} + +bool GeomAPI_Shape::isSubShape(const std::shared_ptr theShape, + const bool theCheckOrientation) const { if(!theShape.get()) { return false; @@ -420,7 +637,8 @@ bool GeomAPI_Shape::isSubShape(const std::shared_ptr theShape) co } for(TopExp_Explorer anExp(*MY_SHAPE, aShapeToSearch.ShapeType()); anExp.More(); anExp.Next()) { - if(aShapeToSearch.IsEqual(anExp.Current())) { + if(theCheckOrientation ? + aShapeToSearch.IsEqual(anExp.Current()) : aShapeToSearch.IsSame(anExp.Current())) { return true; } } @@ -435,18 +653,80 @@ bool GeomAPI_Shape::computeSize(double& theXmin, double& theYmin, double& theZmi if (aShape.IsNull()) return false; Bnd_Box aBndBox; - BRepBndLib::Add(aShape, aBndBox); + // Workaround: compute optimal bounding box for the compounds of edges/vertices, because sometimes + // the bounding box of sketch is calculated if the transformation is applied twice (issue #20167). + bool isShape1D = false; + if (aShape.ShapeType() == TopAbs_COMPOUND) { + isShape1D = true; + for (TopoDS_Iterator anIt(aShape); anIt.More() && isShape1D; anIt.Next()) + if (anIt.Value().ShapeType() < TopAbs_WIRE) + isShape1D = false; + } + if (isShape1D) + BRepBndLib::AddOptimal(aShape, aBndBox, false, true); + else + BRepBndLib::Add(aShape, aBndBox, false); + if (aBndBox.IsVoid()) + return false; aBndBox.Get(theXmin, theYmin, theZmin, theXmax, theYmax, theZmax); return true; } -std::string GeomAPI_Shape::getShapeStream() const +GeomPointPtr GeomAPI_Shape::middlePoint() const +{ + GeomPointPtr aMiddlePoint; + + switch (shapeType()) { + case VERTEX: + aMiddlePoint = vertex()->point(); + break; + case EDGE: + aMiddlePoint = edge()->middlePoint(); + break; + case WIRE: + aMiddlePoint = wire()->middlePoint(); + break; + case FACE: + aMiddlePoint = face()->middlePoint(); + break; + case SHELL: + aMiddlePoint = shell()->middlePoint(); + break; + case SOLID: + aMiddlePoint = solid()->middlePoint(); + break; + default: { + // get middle point as center of the bounding box + double aMinX, aMinY, aMinZ, aMaxX, aMaxY, aMaxZ; + computeSize(aMinX, aMinY, aMinZ, aMaxX, aMaxY, aMaxZ); + aMiddlePoint = GeomPointPtr(new GeomAPI_Pnt( + (aMinX + aMaxX) * 0.5, (aMinY + aMaxY) * 0.5, (aMinZ + aMaxZ) * 0.5)); + } + } + + return aMiddlePoint; +} + +// LCOV_EXCL_START +std::string GeomAPI_Shape::getShapeStream(const bool theWithTriangulation) const { std::ostringstream aStream; const TopoDS_Shape& aShape = const_cast(this)->impl(); - BRepTools::Write(aShape, aStream); + if (!theWithTriangulation) { // make a copy of shape without triangulation + BRepBuilderAPI_Copy aCopy(aShape, Standard_False, Standard_False); + const TopoDS_Shape& aCopyShape = aCopy.Shape(); + // make all faces unchecked to make the stream of shapes the same + TopExp_Explorer aFaceExp(aCopyShape, TopAbs_FACE); + for(; aFaceExp.More(); aFaceExp.Next()) { + aFaceExp.Current().TShape()->Checked(Standard_False); + } + BRepTools::Write(aCopyShape, aStream); + } else { + BRepTools::Write(aShape, aStream); + } return aStream.str(); } +// LCOV_EXCL_STOP GeomShapePtr GeomAPI_Shape::intersect(const GeomShapePtr theShape) const { @@ -490,3 +770,102 @@ bool GeomAPI_Shape::isIntersect(const GeomShapePtr theShape) const return false; } + +void GeomAPI_Shape::translate(const std::shared_ptr theDir, const double theOffset) +{ + gp_Dir aDir = theDir->impl(); + gp_Vec aTrsfVec(aDir.XYZ() * theOffset); + gp_Trsf aTranslation; + aTranslation.SetTranslation(aTrsfVec); + TopoDS_Shape aResult = MY_SHAPE->Moved(aTranslation); + setImpl(new TopoDS_Shape(aResult)); +} + +void GeomAPI_Shape::move(const std::shared_ptr theTransformation) +{ + TopoDS_Shape aResult = MY_SHAPE->Moved(theTransformation->impl()); + setImpl(new TopoDS_Shape(aResult)); +} + +bool GeomAPI_Shape::isSelfIntersected(const int theLevelOfCheck) const +{ + BOPAlgo_CheckerSI aCSI; // checker of self-interferences + aCSI.SetLevelOfCheck(theLevelOfCheck); + TopTools_ListOfShape aList; + const TopoDS_Shape& aThisShape = const_cast(this)->impl(); + aList.Append(aThisShape); + aCSI.SetArguments(aList); + aCSI.Perform(); + if (aCSI.HasErrors() || aCSI.DS().Interferences().Extent() > 0) { + return true; + } + + return false; +} + +bool GeomAPI_Shape::Comparator::operator()(const std::shared_ptr& theShape1, + const std::shared_ptr& theShape2) const +{ + const TopoDS_Shape& aShape1 = theShape1->impl(); + const TopoDS_Shape& aShape2 = theShape2->impl(); + bool isLess = aShape1.TShape() < aShape2.TShape(); + if (aShape1.TShape() == aShape2.TShape()) { +#if OCC_VERSION_LARGE < 0x07080000 + Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast()); + Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast()); +#else + Standard_Integer aHash1 = aShape1.Location().HashCode(); + Standard_Integer aHash2 = aShape2.Location().HashCode(); +#endif + isLess = aHash1 < aHash2; + } + return isLess; +} + +bool GeomAPI_Shape::ComparatorWithOri::operator()( + const std::shared_ptr& theShape1, + const std::shared_ptr& theShape2) const +{ + const TopoDS_Shape& aShape1 = theShape1->impl(); + const TopoDS_Shape& aShape2 = theShape2->impl(); + bool isLess = aShape1.TShape() < aShape2.TShape(); + if (aShape1.TShape() == aShape2.TShape()) { +#if OCC_VERSION_LARGE < 0x07080000 + Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast()); + Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast()); +#else + Standard_Integer aHash1 = aShape1.Location().HashCode(); + Standard_Integer aHash2 = aShape2.Location().HashCode(); +#endif + isLess = (aHash1 < aHash2) || + (aHash1 == aHash2 && aShape1.Orientation() < aShape2.Orientation()); + } + return isLess; +} + +int GeomAPI_Shape::Hash::operator()(const std::shared_ptr& theShape) const +{ + const TopoDS_Shape& aShape = theShape->impl(); +#if OCC_VERSION_LARGE < 0x07080000 + return aShape.HashCode(IntegerLast()); +#else + return std::hash{}(aShape); +#endif +} + +bool GeomAPI_Shape::Equal::operator()(const std::shared_ptr& theShape1, + const std::shared_ptr& theShape2) const +{ + const TopoDS_Shape& aShape1 = theShape1->impl(); + const TopoDS_Shape& aShape2 = theShape2->impl(); + +#if OCC_VERSION_LARGE < 0x07080000 + Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast()); + Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast()); +#else + Standard_Integer aHash1 = aShape1.Location().HashCode(); + Standard_Integer aHash2 = aShape2.Location().HashCode(); +#endif + + return aShape1.TShape() == aShape2.TShape() && aHash1 == aHash2; +}