Salome HOME
3. Mixed topology: solids, faces, edges and vertices
[modules/shaper.git] / src / GeomAlgoAPI / GeomAlgoAPI_ShapeTools.cpp
index 338581782d9204e445b1efcfc91ea6e744cc6d87..852163df3df21b261cf67792238218d01d92946d 100644 (file)
@@ -8,18 +8,33 @@
 
 #include <GeomAlgoAPI_CompoundBuilder.h>
 
+#include <gp_Pln.hxx>
+
+#include <Bnd_Box.hxx>
 #include <BOPTools.hxx>
+#include <BRepBndLib.hxx>
+#include <BRepBuilderAPI_MakeFace.hxx>
 #include <BRepGProp.hxx>
 #include <BRepTools.hxx>
+#include <BRep_Tool.hxx>
+#include <Geom_Plane.hxx>
+#include <GeomLib_IsPlanarSurface.hxx>
+#include <GeomLib_Tool.hxx>
 #include <GProp_GProps.hxx>
+#include <IntAna_IntConicQuad.hxx>
+#include <IntAna_Quadric.hxx>
 #include <NCollection_Vector.hxx>
 #include <TCollection_AsciiString.hxx>
 #include <TopoDS_Builder.hxx>
+#include <TopoDS_Face.hxx>
 #include <TopoDS_Shape.hxx>
 #include <TopoDS_Shell.hxx>
+#include <TopoDS.hxx>
+#include <TopExp_Explorer.hxx>
+
 
 //=================================================================================================
-double GeomAlgoAPI_ShapeTools::volume(std::shared_ptr<GeomAPI_Shape> theShape)
+double GeomAlgoAPI_ShapeTools::volume(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
   GProp_GProps aGProps;
   if(!theShape) {
@@ -34,7 +49,7 @@ double GeomAlgoAPI_ShapeTools::volume(std::shared_ptr<GeomAPI_Shape> theShape)
 }
 
 //=================================================================================================
-std::shared_ptr<GeomAPI_Pnt> GeomAlgoAPI_ShapeTools::centreOfMass(std::shared_ptr<GeomAPI_Shape> theShape)
+std::shared_ptr<GeomAPI_Pnt> GeomAlgoAPI_ShapeTools::centreOfMass(const std::shared_ptr<GeomAPI_Shape> theShape)
 {
   GProp_GProps aGProps;
   if(!theShape) {
@@ -50,50 +65,72 @@ std::shared_ptr<GeomAPI_Pnt> GeomAlgoAPI_ShapeTools::centreOfMass(std::shared_pt
 }
 
 //=================================================================================================
-void GeomAlgoAPI_ShapeTools::combineFacesToShells(const ListOfShape& theFacesList,
-                                                  ListOfShape& theShells,
-                                                  ListOfShape& theFreeFaces)
+void GeomAlgoAPI_ShapeTools::combineShapes(const std::shared_ptr<GeomAPI_Shape> theCompound,
+                                           const GeomAPI_Shape::ShapeType theType,
+                                           ListOfShape& theCombinedShapes,
+                                           ListOfShape& theFreeShapes)
 {
-  if(theFacesList.empty()) {
+  if(!theCompound.get()) {
     return;
   }
 
-  // Adding all faces to compoud.
-  std::shared_ptr<GeomAPI_Shape> aFacesCompound = GeomAlgoAPI_CompoundBuilder::compound(theFacesList);
-  if(!aFacesCompound.get()) {
+  if(theType != GeomAPI_Shape::SHELL && theType != GeomAPI_Shape::COMPSOLID) {
     return;
   }
 
-  // Map edges and faces.
-  const TopoDS_Shape& aFacesComp = aFacesCompound->impl<TopoDS_Shape>();
-  BOPCol_IndexedDataMapOfShapeListOfShape aMapEF;
-  BOPTools::MapShapesAndAncestors(aFacesComp, TopAbs_EDGE, TopAbs_FACE, aMapEF);
-  if(aMapEF.IsEmpty()) {
+  TopAbs_ShapeEnum aTS = TopAbs_EDGE;
+  TopAbs_ShapeEnum aTA = TopAbs_FACE;
+  if(theType == GeomAPI_Shape::COMPSOLID) {
+    aTS = TopAbs_FACE;
+    aTA = TopAbs_SOLID;
+  }
+
+  // Get free shapes.
+  const TopoDS_Shape& aShapesComp = theCompound->impl<TopoDS_Shape>();
+  for(TopoDS_Iterator anIter(aShapesComp); anIter.More(); anIter.Next() ) {
+    const TopoDS_Shape& aShape = anIter.Value();
+    if(aShape.ShapeType() > aTA) {
+      std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
+      aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
+      theFreeShapes.push_back(aGeomShape);
+    }
+  }
+
+  // Map subshapes and shapes.
+  BOPCol_IndexedDataMapOfShapeListOfShape aMapSA;
+  BOPTools::MapShapesAndAncestors(aShapesComp, aTS, aTA, aMapSA);
+  if(aMapSA.IsEmpty()) {
     return;
   }
 
-  // Get all faces with common edges and free faces.
-  NCollection_Map<TopoDS_Shape> aFreeFaces;
-  NCollection_Vector<NCollection_Map<TopoDS_Shape>> aFacesWithCommonEdges;
-  for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator anIter(aMapEF); anIter.More(); anIter.Next()) {
+  // Get all shapes with common subshapes and free shapes.
+  NCollection_Map<TopoDS_Shape> aFreeShapes;
+  NCollection_Vector<NCollection_Map<TopoDS_Shape>> aShapesWithCommonSubshapes;
+  for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator anIter(aMapSA); anIter.More(); anIter.Next()) {
     const TopoDS_Shape& aShape = anIter.Key();
     BOPCol_ListOfShape& aListOfShape = anIter.ChangeValue();
     if(aListOfShape.IsEmpty()) {
       continue;
     }
     else if(aListOfShape.Size() == 1) {
-      aFreeFaces.Add(aListOfShape.First());
+      const TopoDS_Shape& aF = aListOfShape.First();
+      aFreeShapes.Add(aF);
       aListOfShape.Clear();
     } else {
+      NCollection_List<TopoDS_Shape> aTempList;
       NCollection_Map<TopoDS_Shape> aTempMap;
-      aTempMap.Add(aListOfShape.First());
-      aTempMap.Add(aListOfShape.Last());
-      aFreeFaces.Remove(aListOfShape.First());
-      aFreeFaces.Remove(aListOfShape.Last());
+      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);
       aListOfShape.Clear();
-      for(NCollection_Map<TopoDS_Shape>::Iterator aTempIter(aTempMap); aTempIter.More(); aTempIter.Next()) {
+      for(NCollection_List<TopoDS_Shape>::Iterator aTempIter(aTempList); aTempIter.More(); aTempIter.Next()) {
         const TopoDS_Shape& aTempShape = aTempIter.Value();
-        for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator anIter(aMapEF); anIter.More(); anIter.Next()) {
+        for(BOPCol_IndexedDataMapOfShapeListOfShape::Iterator anIter(aMapSA); anIter.More(); anIter.Next()) {
           BOPCol_ListOfShape& aTempListOfShape = anIter.ChangeValue();
           if(aTempListOfShape.IsEmpty()) {
             continue;
@@ -101,42 +138,163 @@ void GeomAlgoAPI_ShapeTools::combineFacesToShells(const ListOfShape& theFacesLis
             aTempListOfShape.Clear();
           } else if(aTempListOfShape.Size() > 1) {
             if(aTempListOfShape.First() == aTempShape) {
-              aTempMap.Add(aTempListOfShape.Last());
-              aFreeFaces.Remove(aTempListOfShape.Last());
+              const TopoDS_Shape& aTL = aTempListOfShape.Last();
+              if(aTempMap.Add(aTL)) {
+                aTempList.Append(aTL);
+                aFreeShapes.Remove(aTL);
+              }
               aTempListOfShape.Clear();
             } else if(aTempListOfShape.Last() == aTempShape) {
-              aTempMap.Add(aTempListOfShape.First());
-              aFreeFaces.Remove(aTempListOfShape.First());
+              const TopoDS_Shape& aTF = aTempListOfShape.First();
+              if(aTempMap.Add(aTF)) {
+                aTempList.Append(aTF);
+                aFreeShapes.Remove(aTF);
+              }
               aTempListOfShape.Clear();
             }
           }
         }
       }
-      aFacesWithCommonEdges.Append(aTempMap);
+      aShapesWithCommonSubshapes.Append(aTempMap);
     }
   }
 
-  // Make shells from faces with common edges.
-  NCollection_Vector<TopoDS_Shape> aShells;
-  for(NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator anIter(aFacesWithCommonEdges); anIter.More(); anIter.Next()) {
+  // Combine shapes with common subshapes.
+  for(NCollection_Vector<NCollection_Map<TopoDS_Shape>>::Iterator anIter(aShapesWithCommonSubshapes); anIter.More(); anIter.Next()) {
     TopoDS_Shell aShell;
+    TopoDS_CompSolid aCSolid;
     TopoDS_Builder aBuilder;
-    aBuilder.MakeShell(aShell);
-    const NCollection_Map<TopoDS_Shape>& aShapesMap = anIter.Value();
-    for(NCollection_Map<TopoDS_Shape>::Iterator aShIter(aShapesMap); aShIter.More(); aShIter.Next()) {
-      const TopoDS_Shape& aFace = aShIter.Value();
-      aBuilder.Add(aShell, aFace);
+    theType == GeomAPI_Shape::COMPSOLID ? aBuilder.MakeCompSolid(aCSolid) : aBuilder.MakeShell(aShell);
+    NCollection_Map<TopoDS_Shape>& 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);
+        aShapesMap.Remove(aShape);
+      }
+    }
+    std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
+    TopoDS_Shape* aSh = theType == GeomAPI_Shape::COMPSOLID ? new TopoDS_Shape(aCSolid) : new TopoDS_Shape(aShell);
+    aGeomShape->setImpl<TopoDS_Shape>(aSh);
+    theCombinedShapes.push_back(aGeomShape);
+  }
+
+  // Adding free shapes.
+  for(TopExp_Explorer anExp(aShapesComp, aTA); anExp.More(); anExp.Next()) {
+    const TopoDS_Shape& aShape = anExp.Current();
+    if(aFreeShapes.Contains(aShape)) {
+      std::shared_ptr<GeomAPI_Shape> aGeomShape(new GeomAPI_Shape);
+      aGeomShape->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShape));
+      theFreeShapes.push_back(aGeomShape);
     }
-    std::shared_ptr<GeomAPI_Shape> aGeomShell(new GeomAPI_Shape);
-    aGeomShell->setImpl<TopoDS_Shape>(new TopoDS_Shape(aShell));
-    theShells.push_back(aGeomShell);
+  }
+}
+
+//=================================================================================================
+std::list<std::shared_ptr<GeomAPI_Pnt> > 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++) {
+    const TopoDS_Shape& aShape = (*anObjectsIt)->impl<TopoDS_Shape>();
+    BRepBndLib::Add(aShape, aBndBox);
+  }
+
+  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);
   }
 
-  // Adding free faces.
-  for(NCollection_Map<TopoDS_Shape>::Iterator aShIter(aFreeFaces); aShIter.More(); aShIter.Next()) {
-    const TopoDS_Shape& aFace = aShIter.Value();
-    std::shared_ptr<GeomAPI_Shape> aGeomFace(new GeomAPI_Shape);
-    aGeomFace->setImpl<TopoDS_Shape>(new TopoDS_Shape(aFace));
-    theFreeFaces.push_back(aGeomFace);
+  Standard_Real aXArr[2] = {aBndBox.CornerMin().X(), aBndBox.CornerMax().X()};
+  Standard_Real aYArr[2] = {aBndBox.CornerMin().Y(), aBndBox.CornerMax().Y()};
+  Standard_Real aZArr[2] = {aBndBox.CornerMin().Z(), aBndBox.CornerMax().Z()};
+  std::list<std::shared_ptr<GeomAPI_Pnt> > 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++) {
+        std::shared_ptr<GeomAPI_Pnt> aPnt(new GeomAPI_Pnt(aXArr[i], aYArr[j], aZArr[k]));
+        aResultPoints.push_back(aPnt);
+      }
+    }
   }
+
+  return aResultPoints;
+}
+
+//=================================================================================================
+std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::faceToInfinitePlane(const std::shared_ptr<GeomAPI_Shape> theFace)
+{
+  if (!theFace.get())
+    return std::shared_ptr<GeomAPI_Shape>();
+
+  TopoDS_Face aPlaneFace = TopoDS::Face(theFace->impl<TopoDS_Shape>());
+  if (aPlaneFace.IsNull())
+    return std::shared_ptr<GeomAPI_Shape>();
+
+  Handle(Geom_Plane) aPlane = Handle(Geom_Plane)::DownCast(BRep_Tool::Surface(aPlaneFace));
+  if (aPlane.IsNull())
+    return std::shared_ptr<GeomAPI_Shape>();
+
+  // make an infinity face on the plane
+  TopoDS_Shape anInfiniteFace = BRepBuilderAPI_MakeFace(aPlane->Pln()).Shape();
+
+  std::shared_ptr<GeomAPI_Shape> aResult(new GeomAPI_Shape);
+  aResult->setImpl(new TopoDS_Shape(anInfiniteFace));
+  return aResult;
+}
+
+//=================================================================================================
+std::shared_ptr<GeomAPI_Shape> GeomAlgoAPI_ShapeTools::fitPlaneToBox(const std::shared_ptr<GeomAPI_Shape> thePlane,
+                                                                     const std::list<std::shared_ptr<GeomAPI_Pnt> >& thePoints)
+{
+  std::shared_ptr<GeomAPI_Shape> aResultShape;
+
+  if(!thePlane.get()) {
+    return aResultShape;
+  }
+
+  const TopoDS_Shape& aShape = thePlane->impl<TopoDS_Shape>();
+  if(aShape.ShapeType() != TopAbs_FACE) {
+    return aResultShape;
+  }
+
+  TopoDS_Face aFace = TopoDS::Face(aShape);
+  Handle(Geom_Surface) aSurf = BRep_Tool::Surface(aFace);
+  if(aSurf.IsNull()) {
+    return aResultShape;
+  }
+
+  GeomLib_IsPlanarSurface isPlanar(aSurf);
+  if(!isPlanar.IsPlanar()) {
+    return aResultShape;
+  }
+
+  if(thePoints.size() != 8) {
+    return aResultShape;
+  }
+
+  const gp_Pln& aFacePln = isPlanar.Plan();
+  Handle(Geom_Plane) aFacePlane = new Geom_Plane(aFacePln);
+  IntAna_Quadric aQuadric(aFacePln);
+  Standard_Real UMin, UMax, VMin, VMax;
+  UMin = UMax = VMin = VMax = 0;
+  for (std::list<std::shared_ptr<GeomAPI_Pnt> >::const_iterator aPointsIt = thePoints.begin(); aPointsIt != thePoints.end(); aPointsIt++) {
+    const gp_Pnt& aPnt = (*aPointsIt)->impl<gp_Pnt>();
+    gp_Lin aLin(aPnt, aFacePln.Axis().Direction());
+    IntAna_IntConicQuad anIntAna(aLin, aQuadric);
+    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;
+  }
+  aResultShape.reset(new GeomAPI_Shape);
+  aResultShape->setImpl(new TopoDS_Shape(BRepLib_MakeFace(aFacePln, UMin, UMax, VMin, VMax).Face()));
+
+  return aResultShape;
 }