Salome HOME
Updated copyright comment
[modules/shaper.git] / src / GeomAPI / GeomAPI_Shape.cpp
index 6d5649a75cf3b9bfc367e3e982634ee3ad82b8cd..e114d961c424f65983dd49dd54d98fb09ac0c045 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2014-2019  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
@@ -46,6 +46,7 @@
 #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>
@@ -54,6 +55,7 @@
 
 #include <BOPAlgo_CheckerSI.hxx>
 #include <BOPDS_DS.hxx>
+#include <BOPTools_AlgoTools.hxx>
 
 #include <sstream>
 #include <algorithm> // for std::transform
@@ -147,6 +149,32 @@ bool GeomAPI_Shape::isCompound() const
   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>();
@@ -227,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<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;
             }
@@ -287,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);
       }
     }
 
@@ -393,21 +446,25 @@ std::shared_ptr<GeomAPI_Solid> GeomAPI_Shape::solid() const
 }
 
 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;
 
+  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) {
-        GeomShapePtr aSub(new GeomAPI_Shape);
-        aSub->setImpl(new TopoDS_Shape(aCurrent));
-        aSubs.push_back(aSub);
+        if (!theOnlyUnique || alreadyThere.Add(aCurrent)) {
+          GeomShapePtr aSub(new GeomAPI_Shape);
+          aSub->setImpl(new TopoDS_Shape(aCurrent));
+          aSubs.push_back(aSub);
+        }
       }
     }
     // add self
@@ -418,9 +475,11 @@ GeomAPI_Shape::subShapes(ShapeType theSubShapeType) const
   else {
     for (TopExp_Explorer anExp(aShape, (TopAbs_ShapeEnum)theSubShapeType);
          anExp.More(); anExp.Next()) {
-      GeomShapePtr aSub(new GeomAPI_Shape);
-      aSub->setImpl(new TopoDS_Shape(anExp.Current()));
-      aSubs.push_back(aSub);
+      if (!theOnlyUnique || alreadyThere.Add(anExp.Current())) {
+        GeomShapePtr aSub(new GeomAPI_Shape);
+        aSub->setImpl(new TopoDS_Shape(anExp.Current()));
+        aSubs.push_back(aSub);
+      }
     }
   }
   return aSubs;
@@ -469,7 +528,8 @@ 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);
+  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" || theType == "COMPSOLIDS")
@@ -551,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;
@@ -595,7 +653,19 @@ bool GeomAPI_Shape::computeSize(double& theXmin, double& theYmin, double& theZmi
   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);
@@ -645,6 +715,11 @@ std::string GeomAPI_Shape::getShapeStream(const bool theWithTriangulation) const
   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);