-// Copyright (C) 2014-2019 CEA/DEN, EDF R&D
+// Copyright (C) 2014-2023 CEA, EDF
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
#include <GeomAPI_Face.h>
#include <GeomAPI_Shell.h>
#include <GeomAPI_Solid.h>
+#include <GeomAPI_Trsf.h>
#include <BRep_Tool.hxx>
#include <BRepAlgoAPI_Section.hxx>
#include <BRepBndLib.hxx>
#include <BRepBuilderAPI_FindPlane.hxx>
+#include <BRepBuilderAPI_Copy.hxx>
#include <BRepExtrema_DistShapeShape.hxx>
#include <BRepTools.hxx>
#include <Bnd_Box.hxx>
#include <Geom_Plane.hxx>
#include <Geom_RectangularTrimmedSurface.hxx>
#include <Geom_TrimmedCurve.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
#include <TopoDS_Iterator.hxx>
#include <BOPAlgo_CheckerSI.hxx>
#include <BOPDS_DS.hxx>
+#include <BOPTools_AlgoTools.hxx>
#include <sstream>
#include <algorithm> // for std::transform
bool GeomAPI_Shape::isSame(const std::shared_ptr<GeomAPI_Shape> 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<TopoDS_Shape>()) == Standard_True;
}
+bool GeomAPI_Shape::isSameGeometry(const std::shared_ptr<GeomAPI_Shape> 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<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
return !aShape.IsNull() && aShape.ShapeType() == TopAbs_COMPOUND;
}
+bool GeomAPI_Shape::isCollectionOfSolids() const
+{
+ const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
+ 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<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
// (if shapes are connected, vertices are connected for sure)
TopExp_Explorer anExp2(aNewIter.Value(), TopAbs_VERTEX);
for(; !aConnected && anExp2.More(); anExp2.Next()) {
- NCollection_List<TopoDS_Shape>::Iterator aNotIter(aNotVertices);
- for(; aNotIter.More(); aNotIter.Next()) {
- if (aNotIter.Value().IsSame(anExp2.Current())) {
+ NCollection_List<TopoDS_Shape>::Iterator aNotVIter(aNotVertices);
+ for(; aNotVIter.More(); aNotVIter.Next()) {
+ if (aNotVIter.Value().IsSame(anExp2.Current())) {
aConnected = true;
break;
}
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;
}
std::list<std::shared_ptr<GeomAPI_Shape> >
-GeomAPI_Shape::subShapes(ShapeType theSubShapeType) const
+GeomAPI_Shape::subShapes(const ShapeType theSubShapeType, const bool theOnlyUnique) const
{
ListOfShape aSubs;
const TopoDS_Shape& aShape = impl<TopoDS_Shape>();
if (aShape.IsNull())
return aSubs;
- for (TopExp_Explorer anExp(aShape, (TopAbs_ShapeEnum)theSubShapeType);
- anExp.More(); anExp.Next()) {
+ 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(anExp.Current()));
+ 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::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<char>(::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
}
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;
if (aShape.IsNull())
return false;
Bnd_Box aBndBox;
- BRepBndLib::Add(aShape, aBndBox, false);
+ // 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);
}
// LCOV_EXCL_START
-std::string GeomAPI_Shape::getShapeStream() const
+std::string GeomAPI_Shape::getShapeStream(const bool theWithTriangulation) const
{
std::ostringstream aStream;
const TopoDS_Shape& aShape = const_cast<GeomAPI_Shape*>(this)->impl<TopoDS_Shape>();
- 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
setImpl(new TopoDS_Shape(aResult));
}
+void GeomAPI_Shape::move(const std::shared_ptr<GeomAPI_Trsf> theTransformation)
+{
+ TopoDS_Shape aResult = MY_SHAPE->Moved(theTransformation->impl<gp_Trsf>());
+ setImpl(new TopoDS_Shape(aResult));
+}
+
bool GeomAPI_Shape::isSelfIntersected(const int theLevelOfCheck) const
{
BOPAlgo_CheckerSI aCSI; // checker of self-interferences
bool GeomAPI_Shape::Comparator::operator()(const std::shared_ptr<GeomAPI_Shape>& theShape1,
const std::shared_ptr<GeomAPI_Shape>& theShape2) const
{
- return theShape1->impl<TopoDS_Shape>().TShape() < theShape2->impl<TopoDS_Shape>().TShape();
+ const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+ const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+ bool isLess = aShape1.TShape() < aShape2.TShape();
+ if (aShape1.TShape() == aShape2.TShape()) {
+ Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast());
+ Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast());
+ isLess = aHash1 < aHash2;
+ }
+ return isLess;
+}
+
+bool GeomAPI_Shape::ComparatorWithOri::operator()(
+ const std::shared_ptr<GeomAPI_Shape>& theShape1,
+ const std::shared_ptr<GeomAPI_Shape>& theShape2) const
+{
+ const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+ const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+ bool isLess = aShape1.TShape() < aShape2.TShape();
+ if (aShape1.TShape() == aShape2.TShape()) {
+ Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast());
+ Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast());
+ isLess = (aHash1 < aHash2) ||
+ (aHash1 == aHash2 && aShape1.Orientation() < aShape2.Orientation());
+ }
+ return isLess;
+}
+
+int GeomAPI_Shape::Hash::operator()(const std::shared_ptr<GeomAPI_Shape>& theShape) const
+{
+ const TopoDS_Shape& aShape = theShape->impl<TopoDS_Shape>();
+ return aShape.HashCode(IntegerLast());
+}
+
+bool GeomAPI_Shape::Equal::operator()(const std::shared_ptr<GeomAPI_Shape>& theShape1,
+ const std::shared_ptr<GeomAPI_Shape>& theShape2) const
+{
+ const TopoDS_Shape& aShape1 = theShape1->impl<TopoDS_Shape>();
+ const TopoDS_Shape& aShape2 = theShape2->impl<TopoDS_Shape>();
+
+ Standard_Integer aHash1 = aShape1.Location().HashCode(IntegerLast());
+ Standard_Integer aHash2 = aShape2.Location().HashCode(IntegerLast());
+
+ return aShape1.TShape() == aShape2.TShape() && aHash1 == aHash2;
}