]> OCCT Git - occt-copy.git/commitdiff
Improve the algorithm of computation of the exposed area. CR0_710_Mtrs
authoremv <emv@opencascade.com>
Fri, 22 Sep 2017 11:09:25 +0000 (14:09 +0300)
committeremv <emv@opencascade.com>
Fri, 29 Sep 2017 13:56:19 +0000 (16:56 +0300)
The algorithm OCCTools_ComputeExposedArea has been improved by switching to working with compounds of Faces instead of Solids in the Gluing mode.
In the Gluing mode there is no need to work with solids, as the arguments are expected to be touching only and should not have any common volume. Working with faces helps to avoid errors while constructing the solids.
In this mode the result of the operation will be just the compound of faces.

src/OCCTools/OCCTools_ComputeExposedArea.cxx
src/OCCTools/OCCTools_ComputeExposedArea.hxx

index 5754abcc5f5a58194d5c2954fe2c317a070a6ff3..536da21521a426fd6b01dc909bebfd1f52997b9d 100644 (file)
@@ -3,11 +3,16 @@
 // Author: Mikhail Sazonov
 
 #include "OCCTools_ComputeExposedArea.hxx"
+
+#include <BRep_Builder.hxx>
+#include <BRepAlgoAPI_BuilderAlgo.hxx>
 #include <BRepAlgoAPI_Fuse.hxx>
 #include <BRepGProp.hxx>
 #include <BOPAlgo_MakerVolume.hxx>
-#include <TopExp_Explorer.hxx>
 #include <GProp_GProps.hxx>
+#include <TopExp_Explorer.hxx>
+#include <TopoDS_Compound.hxx>
+#include <TopTools_MapOfShape.hxx>
 
 #pragma comment(lib,"TKernel")
 #pragma comment(lib,"TKMath")
 #pragma comment(lib,"TKTopAlgo")
 #pragma comment(lib,"TKBO")
 
+static
+  void MakeCompound(const TopoDS_Shape& theShape,
+                    TopoDS_Shape& theComp,
+                    const TopAbs_ShapeEnum theType = TopAbs_FACE);
+
 //=======================================================================
 //function : Constructor
 //purpose  : 
@@ -46,8 +56,8 @@ OCCTools_ComputeExposedArea::OCCTools_ComputeExposedArea(const TopTools_ListOfSh
 }
 
 //=======================================================================
-//function : Constructor
-//purpose  : 
+//function : AddShape
+//purpose  :
 //=======================================================================
 Standard_Boolean OCCTools_ComputeExposedArea::AddShape(const TopoDS_Shape& theShape)
 {
@@ -101,31 +111,100 @@ Standard_Integer OCCTools_ComputeExposedArea::Perform(const Handle(Message_Progr
   }
   else
   {
-    // create fuse algorithm
-    BRepAlgoAPI_Fuse aBOP;
-    aBOP.SetProgressIndicator(theProgress);
-    aBOP.SetRunParallel(Standard_True);
-    aBOP.SetFuzzyValue(myFuzzyValue);
-    //aBOP.SetNonDestructive(Standard_True);
-    if (myIsGluing)
-      aBOP.SetGlue(BOPAlgo_GlueShift);
+    // For the case of gluing there is no need to perform operation on
+    // the solids, it is enough to fuse only the faces, and remove all
+    // coinciding splits from the result.
+    // Without gluing we need to perform real Boolean Fuse operation
+    // to avoid common part in the result
 
-    // prepare arguments for fusion
-    TopTools_ListOfShape anArgs, aTools;
-    anArgs = myShapes;
-    anArgs.RemoveFirst();
-    aTools.Append(myShapes.First());
-    aBOP.SetArguments(anArgs);
-    aBOP.SetTools(aTools);
+    BRepAlgoAPI_BuilderAlgo *pBuilder = myIsGluing ?
+      new BRepAlgoAPI_BuilderAlgo() : new BRepAlgoAPI_Fuse();
+    pBuilder->SetProgressIndicator(theProgress);
+    pBuilder->SetRunParallel(Standard_True);
+    pBuilder->SetFuzzyValue(myFuzzyValue);
+    if (myIsGluing)
+    {
+      pBuilder->SetGlue(BOPAlgo_GlueShift);
+      // prepare arguments - remove solids and make compound of faces
+      TopTools_ListOfShape aLFaces;
+      TopTools_ListIteratorOfListOfShape aItLS(myShapes);
+      for (; aItLS.More(); aItLS.Next())
+      {
+        TopoDS_Shape aFaces;
+        MakeCompound(aItLS.Value(), aFaces);
+        aLFaces.Append(aFaces);
+      }
+      pBuilder->SetArguments(aLFaces);
+    }
+    else
+    {
+      // For the fuse one of the shapes should be an object
+      // and other the tools
+      TopTools_ListOfShape anObjects, aTools;
+      anObjects = myShapes;
+      anObjects.RemoveFirst();
+      aTools.Append(myShapes.First());
+      pBuilder->SetArguments(anObjects);
+      ((BRepAlgoAPI_Fuse*)pBuilder)->SetTools(aTools);
+    }
 
     // perform fusion
-    aBOP.Build();
-    if (!aBOP.IsDone())
+    pBuilder->Build();
+    if (!pBuilder->IsDone())
     {
       return Status_FuseError;
     }
 
-    myFusedShape = aBOP.Shape();
+    myFusedShape = pBuilder->Shape();
+
+    if (myIsGluing)
+    {
+      // Analyze the result of fuse - the fused result should contain only unique faces
+
+      // Result compound
+      TopoDS_Compound aResult;
+      BRep_Builder().MakeCompound(aResult);
+
+      // Make a map from the result faces to original ones
+      BOPCol_IndexedDataMapOfShapeListOfShape aFaceLOrigins;
+
+      TopTools_ListIteratorOfListOfShape aItLS(myShapes);
+      for (; aItLS.More(); aItLS.Next())
+      {
+        const TopoDS_Shape& aS = aItLS.Value();
+        TopExp_Explorer anExp(aS, TopAbs_FACE);
+        for (; anExp.More(); anExp.Next())
+        {
+          const TopoDS_Shape& aF = anExp.Current();
+          const TopTools_ListOfShape& aLFIm = pBuilder->Modified(aF);
+          if (aLFIm.IsEmpty())
+          {
+            // the face has not been even touched
+            BRep_Builder().Add(aResult, aF);
+            continue;
+          }
+
+          TopTools_ListIteratorOfListOfShape aItLFIm(aLFIm);
+          for (; aItLFIm.More(); aItLFIm.Next()) 
+          {
+            const TopoDS_Shape& aFIm = aItLFIm.Value();
+            TopTools_ListOfShape *pLOrigins = aFaceLOrigins.ChangeSeek(aFIm);
+            if (!pLOrigins)
+              pLOrigins = &aFaceLOrigins(aFaceLOrigins.Add(aFIm, TopTools_ListOfShape()));
+            pLOrigins->Append(aF);
+          }
+        }
+      }
+
+      Standard_Integer i, aNb = aFaceLOrigins.Extent();
+      for (i = 1; i <= aNb; ++i)
+      {
+        if (aFaceLOrigins(i).Extent() == 1)
+          BRep_Builder().Add(aResult, aFaceLOrigins.FindKey(i));
+      }
+
+      myFusedShape = aResult;
+    }
   }
 
   // compute area of fused shape
@@ -134,3 +213,19 @@ Standard_Integer OCCTools_ComputeExposedArea::Perform(const Handle(Message_Progr
   myArea = aProps.Mass();
   return Status_OK;
 }
+
+//=======================================================================
+//function : MakeCompound
+//purpose  : 
+//=======================================================================
+void MakeCompound(const TopoDS_Shape& theShape,
+                  TopoDS_Shape& theComp,
+                  const TopAbs_ShapeEnum theType)
+{
+  TopoDS_Compound aComp;
+  BRep_Builder().MakeCompound(aComp);
+  TopExp_Explorer anExp(theShape, theType);
+  for (; anExp.More(); anExp.Next())
+    BRep_Builder().Add(aComp, anExp.Current());
+  theComp = aComp;
+}
index 301f155b82c7855f24062902e925f81527086131..0e15077d4cf4ffc5944c28cb29112a9ad1446c55 100644 (file)
@@ -14,6 +14,15 @@ class Message_ProgressIndicator;
 //! and calculates the area of the result (exposed area).
 //! It looks only for solid shapes in input arguments. If there are no solids
 //! it looks for faces and tries to create closed shells and then solids of them.
+//! The class has the following options:
+//! - *Gluing mode* - allows speeding up the calculation on the touching arguments;
+//!                   In this mode the area computation will be performed on the faces,
+//!                   forming the closed shells, not on the solids. It will help to avoid
+//!                   extra computations and, most importantly, possible errors while
+//!                   constructing the solids;
+//! - *Fuzzy mode* - additional tolerance for the operation to make the arguments
+//!                  interfere when its appropriate.
+//!
 class OCCTools_ComputeExposedArea
 {
 public:
@@ -85,6 +94,7 @@ public:
   }
 
 private:
+
   TopTools_ListOfShape myShapes;
   TopoDS_Shape myFusedShape;
   Standard_Real myFuzzyValue;