Salome HOME
Implement 'make dist' and 'make distcheck' steps support
[modules/geom.git] / src / GEOMImpl / GEOMImpl_BooleanDriver.cxx
index ca0812c39f40cff939d4a222462e06c3ad6e188e..39d625d5460c172e043c58f744d06d0d68079f57 100644 (file)
@@ -30,6 +30,7 @@
 #include <BRepAlgoAPI_Cut.hxx>
 #include <BRepAlgoAPI_Fuse.hxx>
 #include <BRepAlgoAPI_Section.hxx>
+#include <TopExp_Explorer.hxx>
 #include <TopoDS_Shape.hxx>
 #include <TopoDS_Compound.hxx>
 #include <TopoDS_Iterator.hxx>
@@ -37,6 +38,9 @@
 #include <TopTools_ListOfShape.hxx>
 #include <TopTools_ListIteratorOfListOfShape.hxx>
 #include <Precision.hxx>
+#include <BRepCheck_Analyzer.hxx>
+#include <ShapeFix_ShapeTolerance.hxx>
+#include <ShapeFix_Shape.hxx>
 
 #include <Standard_ConstructionError.hxx>
 #include <StdFail_NotDone.hxx>
@@ -127,15 +131,53 @@ Standard_Integer GEOMImpl_BooleanDriver::Execute(TFunction_Logbook& log) const
           if (!BO.IsDone()) {
             StdFail_NotDone::Raise("Common operation can not be performed on the given shapes");
           }
-          if (isCompound)
-            B.Add(C, BO.Shape());
+          if (isCompound) {
+            TopoDS_Shape aStepResult = BO.Shape();
+
+            // check result of this step: if it is a compound (boolean operations
+            // allways return a compound), we add all sub-shapes of it.
+            // This allows to avoid adding empty compounds,
+            // resulting from COMMON on two non-intersecting shapes.
+            if (aStepResult.ShapeType() == TopAbs_COMPOUND) {
+              TopoDS_Iterator aCompIter (aStepResult);
+              for (; aCompIter.More(); aCompIter.Next()) {
+                // add shape in a result
+                B.Add(C, aCompIter.Value());
+              }
+            }
+            else {
+              // add shape in a result
+              B.Add(C, aStepResult);
+            }
+          }
           else
             aShape = BO.Shape();
         }
       }
 
-      if (isCompound)
-        aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion());
+      if (isCompound) {
+        /*
+        TopTools_ListOfShape listShapeC;
+        AddSimpleShapes(C, listShapeC);
+        TopTools_ListIteratorOfListOfShape itSubC (listShapeC);
+        bool isOnlySolids = true;
+        for (; itSubC.More(); itSubC.Next()) {
+          TopoDS_Shape aValueC = itSubC.Value();
+          if (aValueC.ShapeType() != TopAbs_SOLID) isOnlySolids = false;
+        }
+        if (isOnlySolids)
+          aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion());
+        else
+          aShape = C;
+        */
+
+        // As GlueFaces has been improved to keep all kind of shapes
+        TopExp_Explorer anExp (C, TopAbs_VERTEX);
+        if (anExp.More())
+          aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
+        else
+          aShape = C;
+      }
     }
 
     // perform CUT operation
@@ -163,33 +205,136 @@ Standard_Integer GEOMImpl_BooleanDriver::Execute(TFunction_Logbook& log) const
           }
           aCut = BO.Shape();
         }
-        if (isCompound)
-          B.Add(C, aCut);
+        if (isCompound) {
+          // check result of this step: if it is a compound (boolean operations
+          // allways return a compound), we add all sub-shapes of it.
+          // This allows to avoid adding empty compounds,
+          // resulting from CUT of parts
+          if (aCut.ShapeType() == TopAbs_COMPOUND) {
+            TopoDS_Iterator aCompIter (aCut);
+            for (; aCompIter.More(); aCompIter.Next()) {
+              // add shape in a result
+              B.Add(C, aCompIter.Value());
+            }
+          }
+          else {
+            // add shape in a result
+            B.Add(C, aCut);
+          }
+        }
         else
           aShape = aCut;
       }
 
-      if (isCompound)
-        aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion());
+      if (isCompound) {
+        /*
+        TopTools_ListOfShape listShapeC;
+        AddSimpleShapes(C, listShapeC);
+        TopTools_ListIteratorOfListOfShape itSubC (listShapeC);
+        bool isOnlySolids = true;
+        for (; itSubC.More(); itSubC.Next()) {
+          TopoDS_Shape aValueC = itSubC.Value();
+          if (aValueC.ShapeType() != TopAbs_SOLID) isOnlySolids = false;
+        }
+        if (isOnlySolids)
+          aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion());
+        else
+          aShape = C;
+        */
+
+        // As GlueFaces has been improved to keep all kind of shapes
+        TopExp_Explorer anExp (C, TopAbs_VERTEX);
+        if (anExp.More())
+          aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
+        else
+          aShape = C;
+      }
     }
 
     // perform FUSE operation
     else if (aType == BOOLEAN_FUSE) {
-      // check shapes to provide special processing for compounds and compsolids
-      if (aShape1.ShapeType() == TopAbs_COMPOUND ||
-          aShape1.ShapeType() == TopAbs_COMPSOLID ||
-          aShape2.ShapeType() == TopAbs_COMPOUND ||
-          aShape2.ShapeType() == TopAbs_COMPSOLID) {
-        // at least one of arguments is complex
-        StdFail_NotDone::Raise("Fuse operation aborted: one of arguments is a complex shape");
-      } else {
-        // simple arguments
-        BRepAlgoAPI_Fuse BO (aShape1, aShape2);
-        if (!BO.IsDone()) {
-          StdFail_NotDone::Raise("Fuse operation can not be performed on the given shapes");
+      /* Fix for NPAL15379: refused
+      // Check arguments
+      TopTools_ListOfShape listShape1, listShape2;
+      AddSimpleShapes(aShape1, listShape1);
+      AddSimpleShapes(aShape2, listShape2);
+
+      Standard_Boolean isIntersect = Standard_False;
+
+      if (listShape1.Extent() > 1 && !isIntersect) {
+        // check intersections inside the first compound
+        TopTools_ListIteratorOfListOfShape it1 (listShape1);
+        for (; it1.More() && !isIntersect; it1.Next()) {
+          TopoDS_Shape aValue1 = it1.Value();
+          TopTools_ListIteratorOfListOfShape it2 (listShape1);
+          for (; it2.More() && !isIntersect; it2.Next()) {
+            TopoDS_Shape aValue2 = it2.Value();
+            if (aValue2 != aValue1) {
+              BRepAlgoAPI_Section BO (aValue1, aValue2);
+              if (BO.IsDone()) {
+                TopoDS_Shape aSect = BO.Shape();
+                TopExp_Explorer anExp (aSect, TopAbs_EDGE);
+                if (anExp.More()) {
+                  isIntersect = Standard_True;
+                }
+              }
+            }
+          }
         }
-        aShape = BO.Shape();
       }
+
+      if (listShape2.Extent() > 1 && !isIntersect) {
+        // check intersections inside the second compound
+        TopTools_ListIteratorOfListOfShape it1 (listShape2);
+        for (; it1.More() && !isIntersect; it1.Next()) {
+          TopoDS_Shape aValue1 = it1.Value();
+          TopTools_ListIteratorOfListOfShape it2 (listShape2);
+          for (; it2.More() && !isIntersect; it2.Next()) {
+            TopoDS_Shape aValue2 = it2.Value();
+            if (aValue2 != aValue1) {
+              BRepAlgoAPI_Section BO (aValue1, aValue2);
+              if (BO.IsDone()) {
+                TopoDS_Shape aSect = BO.Shape();
+                TopExp_Explorer anExp (aSect, TopAbs_EDGE);
+                if (anExp.More()) {
+                  isIntersect = Standard_True;
+                }
+              }
+            }
+          }
+        }
+      }
+
+      if (isIntersect) {
+        // have intersections inside compounds
+        // check intersections between compounds
+        TopTools_ListIteratorOfListOfShape it1 (listShape1);
+        for (; it1.More(); it1.Next()) {
+          TopoDS_Shape aValue1 = it1.Value();
+          TopTools_ListIteratorOfListOfShape it2 (listShape2);
+          for (; it2.More(); it2.Next()) {
+            TopoDS_Shape aValue2 = it2.Value();
+            if (aValue2 != aValue1) {
+              BRepAlgoAPI_Section BO (aValue1, aValue2);
+              if (BO.IsDone()) {
+                TopoDS_Shape aSect = BO.Shape();
+                TopExp_Explorer anExp (aSect, TopAbs_EDGE);
+                if (anExp.More()) {
+                  StdFail_NotDone::Raise("Bad argument for Fuse: compound with intersecting sub-shapes");
+                }
+              }
+            }
+          }
+        }
+      }
+      */
+
+      // Perform
+      BRepAlgoAPI_Fuse BO (aShape1, aShape2);
+      if (!BO.IsDone()) {
+        StdFail_NotDone::Raise("Fuse operation can not be performed on the given shapes");
+      }
+      aShape = BO.Shape();
     }
 
     // perform SECTION operation
@@ -211,19 +356,50 @@ Standard_Integer GEOMImpl_BooleanDriver::Execute(TFunction_Logbook& log) const
         TopTools_ListIteratorOfListOfShape itSub2 (listShape2);
         for (; itSub2.More(); itSub2.Next()) {
           TopoDS_Shape aValue2 = itSub2.Value();
-          BRepAlgoAPI_Section BO (aValue1, aValue2);
+          BRepAlgoAPI_Section BO (aValue1, aValue2, Standard_False);
+          // Set approximation to have an attached 3D BSpline geometry to each edge,
+          // where analytic curve is not possible. Without this flag in some cases
+          // we obtain BSpline curve of degree 1 (C0), which is slowly
+          // processed by some algorithms (Partition for example).
+          BO.Approximation(Standard_True);
+          BO.Build();
           if (!BO.IsDone()) {
             StdFail_NotDone::Raise("Section operation can not be performed on the given shapes");
           }
-          if (isCompound)
-            B.Add(C, BO.Shape());
+          if (isCompound) {
+            TopoDS_Shape aStepResult = BO.Shape();
+
+            // check result of this step: if it is a compound (boolean operations
+            // allways return a compound), we add all sub-shapes of it.
+            // This allows to avoid adding empty compounds,
+            // resulting from SECTION on two non-intersecting shapes.
+            if (aStepResult.ShapeType() == TopAbs_COMPOUND) {
+              TopoDS_Iterator aCompIter (aStepResult);
+              for (; aCompIter.More(); aCompIter.Next()) {
+                // add shape in a result
+                B.Add(C, aCompIter.Value());
+              }
+            }
+            else {
+              // add shape in a result
+              B.Add(C, aStepResult);
+            }
+          }
           else
             aShape = BO.Shape();
         }
       }
 
-      if (isCompound)
-        aShape = C;
+      if (isCompound) {
+        //aShape = C;
+
+        // As GlueFaces has been improved to keep all kind of shapes
+        TopExp_Explorer anExp (C, TopAbs_VERTEX);
+        if (anExp.More())
+          aShape = GEOMImpl_GlueDriver::GlueFaces(C, Precision::Confusion(), Standard_True);
+        else
+          aShape = C;
+      }
     }
 
     // UNKNOWN operation
@@ -232,9 +408,24 @@ Standard_Integer GEOMImpl_BooleanDriver::Execute(TFunction_Logbook& log) const
   }
 
   if (aShape.IsNull()) return 0;
-  if (!BRepAlgo::IsValid(aShape)) {
-    Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
+
+  // 08.07.2008 skl for bug 19761 from Mantis
+  BRepCheck_Analyzer ana (aShape, Standard_True);
+  ana.Init(aShape);
+  if (!ana.IsValid()) {
+    ShapeFix_ShapeTolerance aSFT;
+    aSFT.LimitTolerance(aShape, Precision::Confusion(),
+                        Precision::Confusion(), TopAbs_SHAPE);
+    Handle(ShapeFix_Shape) aSfs = new ShapeFix_Shape(aShape);
+    aSfs->Perform();
+    aShape = aSfs->Shape();
+    ana.Init(aShape);
+    if (!ana.IsValid())
+      Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
   }
+  //if (!BRepAlgo::IsValid(aShape)) {
+  //  Standard_ConstructionError::Raise("Boolean operation aborted : non valid shape result");
+  //}
 
   aFunction->SetValue(aShape);