0025232: Functionality to create solids from set of shapes
authoremv <emv@opencascade.com>
Fri, 26 Sep 2014 12:41:20 +0000 (16:41 +0400)
committerbugmaster <bugmaster@opencascade.com>
Fri, 26 Sep 2014 13:12:29 +0000 (17:12 +0400)
Purpose:
The algorithm is to build solids from set of shapes.
It uses the BOPAlgo_Builder algorithm to intersect the given shapes and build the images
of faces (if needed) and BOPAlgo_BuilderSolid algorithm to build the solids.
Steps of the algorithm:
1. Collect all faces: intersect the shapes if necessary and collect  the images of faces,
   otherwise just collect the faces to the <myFaces> list.
   All faces on this step added twice, with orientation FORWARD and REVERSED;
2. Create bounding box covering all the faces from <myFaces> and create solid box from corner points
   of that bounding box (myBBox, mySBox). Add faces from that box to <myFaces>;
3. Build solids using faces from <myFaces> using BOPAlgo_BuilderSolid algorithm;
4. Treat the result: Eliminate solid containig faces from <mySBox>;
5. Fill internal shapes: add internal vertices and edges into created solids;
6. Prepare the history.

Fix for regression.
class BOPAlgo_BuilderSolid:
The tolerance value used in BRepClass3d_SolidClassifier has been increased.

Test cases for issue CR25232

Small correction to eliminate the warning.

22 files changed:
src/BOPAlgo/BOPAlgo.cdl
src/BOPAlgo/BOPAlgo_Builder.cdl
src/BOPAlgo/BOPAlgo_Builder.cxx
src/BOPAlgo/BOPAlgo_BuilderSolid.cxx
src/BOPAlgo/BOPAlgo_Builder_3.cxx
src/BOPAlgo/BOPAlgo_MakerVolume.cdl [new file with mode: 0644]
src/BOPAlgo/BOPAlgo_MakerVolume.cxx [new file with mode: 0644]
src/BOPAlgo/BOPAlgo_MakerVolume.lxx [new file with mode: 0644]
src/BOPTest/BOPTest_BOPCommands.cxx
src/TKBO/EXTERNLIB
tests/bugs/modalg_5/bug25232_1 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_10 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_11 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_12 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_2 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_3 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_4 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_5 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_6 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_7 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_8 [new file with mode: 0644]
tests/bugs/modalg_5/bug25232_9 [new file with mode: 0644]

index bc42d9b..15a6c03 100644 (file)
@@ -75,6 +75,7 @@ is
     class CheckerSI; 
     class ArgumentAnalyzer; 
     class CheckResult; 
+    class MakerVolume;
     --
     --  pointers
     --
index a5b46bf..f310c7c 100644 (file)
@@ -61,7 +61,11 @@ is
     AddArgument (me:out;  
         theShape: Shape from TopoDS) 
     is virtual; 
-     
+    SetArguments (me:out;
+        theShapes: ListOfShape from BOPCol)
+    is virtual;
+
     Arguments(me) 
     returns ListOfShape from BOPCol; 
     ---C++: return const & 
index d587c7d..ca6c22a 100644 (file)
@@ -101,6 +101,20 @@ void BOPAlgo_Builder::AddArgument(const TopoDS_Shape& theShape)
   }
 }
 //=======================================================================
+//function : SetArguments
+//purpose  : 
+//=======================================================================
+void BOPAlgo_Builder::SetArguments(const BOPCol_ListOfShape& theShapes)
+{
+  BOPCol_ListIteratorOfListOfShape aIt;
+  //
+  aIt.Initialize(theShapes);
+  for (; aIt.More(); aIt.Next()) {
+    const TopoDS_Shape& aS = aIt.Value();
+    AddArgument(aS);
+  }
+}
+//=======================================================================
 //function : Arguments
 //purpose  : 
 //=======================================================================
@@ -221,6 +235,7 @@ void BOPAlgo_Builder::Perform()
   BOPAlgo_PaveFiller* pPF=new BOPAlgo_PaveFiller(aAllocator);
   //
   pPF->SetArguments(myArguments);
+  pPF->SetRunParallel(myRunParallel);
   //
   pPF->Perform();
   //
index ce0ca26..c285298 100644 (file)
@@ -229,8 +229,9 @@ class BOPAlgo_FaceSolid : public BOPAlgo_Algo {
     //
     BOPAlgo_Algo::UserBreak();
     //
-    aState=BOPTools_AlgoTools::ComputeState(myPnt, mySolid, 
-                                            1.e-14, myContext);
+    aState=BOPTools_AlgoTools::ComputeState(myPnt, mySolid,
+                                            Precision::Confusion(),
+                                            myContext);
     //
     myIsInternalFace=(aState==TopAbs_IN);
   }
@@ -1057,7 +1058,8 @@ Standard_Boolean IsInside(const TopoDS_Shape& theS1,
     BOPCol_IndexedMapOfShape aBounds;
     BOPTools::MapShapes(*pS2, TopAbs_EDGE, aBounds);
     const TopoDS_Face& aF = (*(TopoDS_Face*)(&aExp.Current()));
-    aState=BOPTools_AlgoTools::ComputeState(aF, *pS2, 1.e-14, 
+    aState=BOPTools_AlgoTools::ComputeState(aF, *pS2,
+                                            Precision::Confusion(),
                                             aBounds, theContext);
   }
   return (aState==TopAbs_IN);
index f43ab82..d729ef8 100644 (file)
@@ -17,6 +17,8 @@
 //
 #include <BOPAlgo_Builder.hxx>
 //
+#include <Precision.hxx>
+//
 #include <NCollection_IncAllocator.hxx>
 #include <NCollection_UBTreeFiller.hxx>
 //
@@ -334,7 +336,9 @@ void BOPAlgo_Builder::FillIn3DParts
       //
       aMFDone.Add(aFP);
       //
-      iIsIN=BOPTools_AlgoTools::IsInternalFace(aFP, aSD, aMEF, 1.e-14, myContext);
+      iIsIN=BOPTools_AlgoTools::IsInternalFace(aFP, aSD, aMEF,
+                                               Precision::Confusion(),
+                                               myContext);
       //
       aLFP.Clear();
       aLFP.Append(aFP);
diff --git a/src/BOPAlgo/BOPAlgo_MakerVolume.cdl b/src/BOPAlgo/BOPAlgo_MakerVolume.cdl
new file mode 100644 (file)
index 0000000..6f5e559
--- /dev/null
@@ -0,0 +1,218 @@
+-- Created by: Eugeny MALTCHIKOV
+-- Copyright (c) 2014 OPEN CASCADE SAS
+--
+-- This file is part of Open CASCADE Technology software library.
+--
+-- This library is free software; you can redistribute it and/or modify it under
+-- the terms of the GNU Lesser General Public License version 2.1 as published
+-- by the Free Software Foundation, with special exception defined in the file
+-- OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+-- distribution for complete text of the license and disclaimer of any warranty.
+--
+-- Alternatively, this file may be used under the terms of Open CASCADE
+-- commercial license or contractual agreement.
+
+class MakerVolume from BOPAlgo
+    inherits Builder from BOPAlgo
+    ---Purpose: 
+    -- The algorithm is to build solids from set of shapes.
+    -- It uses the BOPAlgo_Builder algorithm to intersect the given shapes
+    -- and build the images of faces (if needed) and BOPAlgo_BuilderSolid
+    -- algorithm to build the solids.
+    --
+    -- Steps of the algorithm:
+    --  1. Collect all faces: intersect the shapes if necessary and collect
+    --     the images of faces, otherwise just collect the faces to the
+    --     <myFaces> list;
+    --     All faces on this step added twice, with orientation FORWARD
+    --     and REVERSED;
+    --
+    --  2. Create bounding box covering all the faces from <myFaces> and
+    --     create solid box from corner points of that bounding box
+    --     (myBBox, mySBox). Add faces from that box to <myFaces>;
+    --
+    --  3. Build solids from <myFaces> using BOPAlgo_BuilderSolid algorithm;
+    --
+    --  4. Treat the result: Eliminate solid containig faces from <mySBox>;
+    --
+    --  5. Fill internal shapes: add internal vertices and edges into
+    --     created solids;
+    --
+    --  6. Prepare the history.
+    --
+    -- Fields:
+    --  <myIntersect> - boolean flag. It defines whether intersect shapes
+    --                  from <myArguments> (if set to TRUE) or not (FALSE).
+    --                  The default value is TRUE. By setting it to FALSE
+    --                  the user should guarantee that shapes in <myArguments>
+    --                  do not interfere with each other, otherwise the result
+    --                  is unpredictable.
+    --
+    --  <myBBox>      - bounding box, covering all faces from <myFaces>.
+    --
+    --  <mySBox>      - Solid box created from the corner points of <myBBox>.
+    --
+    --  <myFaces>     - the list is to keep the "final" faces, that will be
+    --                  given to the BOPAlgo_BuilderSolid algorithm.
+    --                  If the shapes have been interfered it should contain
+    --                  the images of the source shapes, otherwise its just
+    --                  the original faces.
+    --                  It also contains the faces from <mySBox>.
+    --
+    --
+    -- Fields inherited from BOPAlgo_Builder:
+    --
+    --  <myArguments> - list of the source shapes. The source shapes can have
+    --                  any type, but each shape must not be self-interfered.
+    --
+    --  <myShape>     - Result shape:
+    --                  - empty compound - if no solids were created;
+    --                  - solid - if created only one solid;
+    --                  - compound of solids - if created more than one solid.
+    --
+    --
+    -- Fields inherited from BOPAlgo_Algo:
+    --
+    -- <myRunParallel> - Defines whether the parallel processing is
+    --                   switched on or not.
+    -- <myErrorStatus> - Error status of the operation:
+    --                   0   - operation successful;
+    --                   100 - no shapes to process;
+    --                   102 - BOPAlgo_PaveFiller algorithm has failed;
+    --                   103 - BOPAlgo_BuilderSolid algorithm has failed.
+    --
+    -- Example:
+    --
+    --  BOPAlgo_MakerVolume aMV;
+    --  //
+    --  aMV.SetArguments(aLS); //source shapes
+    --  aMV.SetRunParallel(bRunParallel); //parallel or single mode
+    --  aMV.SetIntersect(bIntersect); //intersect or not the shapes from <aLS>
+    --  //
+    --  aMV.Perform(); //perform the operation
+    --  if (aMV.ErrorStatus()) { //check error status
+    --    return;
+    --  }
+    --  //
+    --  const TopoDS_Shape& aResult = aMV.Shape();  //result of the operation
+    --
+
+uses
+    Shape from TopoDS,
+    BaseAllocator from BOPCol,
+    ListOfShape from BOPCol,
+    MapOfShape from BOPCol,
+    Box from Bnd,
+    Solid from TopoDS,
+    PaveFiller from BOPAlgo
+
+is
+
+    Create
+    returns MakerVolume from BOPAlgo;
+    ---C++: alias "virtual ~BOPAlgo_MakerVolume();"
+    ---C++: inline 
+    ---Purpose:  
+    -- Empty contructor.
+
+    Create(theAllocator: BaseAllocator from BOPCol)
+    returns MakerVolume from BOPAlgo;
+    ---C++: inline
+    ---Purpose:
+    -- Empty contructor.
+
+    Clear(me:out)
+    is redefined;
+    ---C++: inline
+    ---Purpose:
+    -- Clears the data.
+
+    SetIntersect(me:out;
+        bIntersect : Boolean from Standard);
+    ---C++: inline
+    ---Purpose:
+    -- Sets the flag myIntersect:
+    -- if <bIntersect> is TRUE the shapes from <myArguments> will be intersected.
+    -- if <bIntersect> is FALSE no intersection will be done.
+
+    IsIntersect(me)
+    returns Boolean from Standard;
+    ---C++: inline
+    ---Purpose:
+    -- Returns the flag <myIntersect>.
+
+    Box(me)
+    returns Solid from TopoDS;
+    ---C++: return  const&
+    ---C++: inline
+    ---Purpose:
+    -- Returns the solid box <mySBox>.
+
+    Faces(me)
+    returns ListOfShape from BOPCol;
+    ---C++: return  const&
+    ---C++: inline
+    ---Purpose:
+    -- Returns the processed faces <myFaces>.
+
+    CheckData(me:out)
+    is redefined protected;
+    ---Purpose:
+    -- Checks the data.
+
+    Perform(me:out)
+    is redefined;
+    ---Purpose:
+    -- Performs the operation.
+
+    PerformInternal1(me:out;
+        thePF: PaveFiller from BOPAlgo)
+    is redefined protected;
+    ---Purpose:
+    -- Performs the operation.
+
+    CollectFaces(me:out)
+    is protected;
+    ---Purpose:
+    -- Collects all faces.
+
+    MakeBox(me:out;
+        theBoxFaces : out MapOfShape from BOPCol)
+    is protected;
+    ---Purpose:
+    -- Makes solid box.
+
+    BuildSolids(me:out;
+        theLSR  : out ListOfShape from BOPCol)
+    is protected;
+    ---Purpose:
+    -- Builds solids.
+
+    RemoveBox(me:out;
+        theLSR      : out ListOfShape from BOPCol;
+        theBoxFaces : MapOfShape from BOPCol)
+    is protected;
+    ---Purpose:
+    -- Removes the covering box.
+
+    FillInternalShapes(me:out;
+        theLSR : ListOfShape from BOPCol)
+    is protected;
+    ---Purpose:
+    -- Fills the solids with internal shapes.
+
+    BuildShape(me:out;
+        theLSR : ListOfShape from BOPCol)
+    is protected;
+    ---Purpose:
+    -- Builds the result.
+
+fields
+
+    myIntersect : Boolean from Standard is protected;
+    myBBox      : Box from Bnd is protected;
+    mySBox      : Solid from TopoDS is protected;
+    myFaces     : ListOfShape from BOPCol is protected;
+
+end MakerVolume;
+
diff --git a/src/BOPAlgo/BOPAlgo_MakerVolume.cxx b/src/BOPAlgo/BOPAlgo_MakerVolume.cxx
new file mode 100644 (file)
index 0000000..b602d21
--- /dev/null
@@ -0,0 +1,449 @@
+// Created by: Eugeny MALTCHIKOV
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+#include <BOPAlgo_MakerVolume.ixx>
+
+#include <NCollection_IncAllocator.hxx>
+
+#include <Bnd_Box.hxx>
+
+#include <TopoDS_Solid.hxx>
+
+#include <TopExp_Explorer.hxx>
+
+#include <BRepPrimAPI_MakeBox.hxx>
+
+#include <BOPCol_ListOfShape.hxx>
+#include <BOPCol_DataMapOfShapeListOfShape.hxx>
+
+#include <BOPDS_DS.hxx>
+
+#include <BOPAlgo_PaveFiller.hxx>
+#include <BOPAlgo_BuilderSolid.hxx>
+
+#include <BOPTools.hxx>
+#include <BOPTools_AlgoTools.hxx>
+
+static
+  void AddFace(const TopoDS_Shape& theF,
+               BOPCol_ListOfShape& theLF);
+static
+  void TreatCompound(const TopoDS_Shape& theS,
+                     BOPCol_MapOfShape& aMFence,
+                     BOPCol_ListOfShape& theLS);
+
+//=======================================================================
+//function : Perform
+//purpose  : 
+//=======================================================================
+void BOPAlgo_MakerVolume::Perform()
+{
+  myErrorStatus = 0;
+  //
+  if (myEntryPoint == 1) {
+    if (myPaveFiller) {
+      delete myPaveFiller;
+      myPaveFiller = NULL;
+    }
+  }
+  //
+  Handle(NCollection_BaseAllocator) aAllocator = new NCollection_IncAllocator;
+  BOPAlgo_PaveFiller* pPF = new BOPAlgo_PaveFiller(aAllocator);
+  //
+  if (!myIntersect) {
+    //if there is no need to intersect the arguments, then it is necessary
+    //to create the compound of them and use it as one argument
+    TopoDS_Compound anArgs;
+    BRep_Builder aBB;
+    BOPCol_ListIteratorOfListOfShape aIt;
+    BOPCol_ListOfShape aLS;
+    //
+    aBB.MakeCompound(anArgs);
+    aIt.Initialize(myArguments);
+    for (; aIt.More(); aIt.Next()) {
+      const TopoDS_Shape& aS = aIt.Value();
+      aBB.Add(anArgs, aS);
+    }
+    aLS.Append(anArgs);
+    //
+    pPF->SetArguments(aLS);
+  }
+  else {
+    pPF->SetArguments(myArguments);
+  }
+  //
+  pPF->SetRunParallel(myRunParallel);
+  pPF->Perform();
+  //
+  myEntryPoint = 1;
+  PerformInternal(*pPF);
+}
+
+//=======================================================================
+//function : PerformInternal1
+//purpose  : 
+//=======================================================================
+void BOPAlgo_MakerVolume::PerformInternal1
+  (const BOPAlgo_PaveFiller& theFiller)
+{
+  myErrorStatus=0;
+  //
+  myPaveFiller = (BOPAlgo_PaveFiller*)&theFiller;
+  myDS = myPaveFiller->PDS();
+  myContext = myPaveFiller->Context();
+  //
+  // 1. CheckData
+  CheckData();
+  if (myErrorStatus) {
+    return;
+  }
+  //
+  // 2. Prepare
+  Prepare();
+  if (myErrorStatus) {
+    return;
+  }
+  //
+  // 3. Fill Images
+  // 3.1. Vertice
+  if (myIntersect) {
+    FillImagesVertices();
+    if (myErrorStatus) {
+      return;
+    }
+    // 3.2. Edges
+    FillImagesEdges();
+    if (myErrorStatus) {
+      return;
+    }
+    // 3.3. Wires
+    FillImagesContainers(TopAbs_WIRE);
+    if (myErrorStatus) {
+      return;
+    }
+    // 3.4. Faces
+    FillImagesFaces();
+    if (myErrorStatus) {
+      return;
+    }
+  }
+  //
+  // 4. Collect faces
+  CollectFaces();
+  if (myErrorStatus) {
+    return;
+  }
+  //
+  BOPCol_MapOfShape aBoxFaces;
+  BOPCol_ListOfShape aLSR;
+  //
+  // 5. Create bounding box
+  MakeBox(aBoxFaces);
+  //
+  // 6. Make volumes
+  BuildSolids(aLSR);
+  if (myErrorStatus) {
+    return;
+  }
+  //
+  // 7. Treat the result
+  RemoveBox(aLSR, aBoxFaces);
+  //
+  // 8. Fill internal shapes
+  FillInternalShapes(aLSR);
+  //
+  // 9. Build Result
+  BuildShape(aLSR);
+  //
+  // 10. History
+  PrepareHistory();
+  //
+  // 11. Post-treatment 
+  PostTreat();  
+}
+
+//=======================================================================
+//function : CollectFaces
+//purpose  : 
+//=======================================================================
+void BOPAlgo_MakerVolume::CollectFaces()
+{
+  UserBreak();
+  //
+  Standard_Integer i, aNbShapes;
+  BOPCol_ListIteratorOfListOfShape aIt;
+  //
+  aNbShapes = myDS->NbSourceShapes();
+  for (i = 0; i < aNbShapes; ++i) {
+    const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(i);
+    if (aSI.ShapeType() != TopAbs_FACE) {
+      continue;
+    }
+    //
+    const Bnd_Box& aB = aSI.Box();
+    myBBox.Add(aB);
+    //
+    const TopoDS_Shape& aF = aSI.Shape();
+    if (myImages.IsBound(aF)) {
+      const BOPCol_ListOfShape& aLFIm = myImages.Find(aF);
+      aIt.Initialize(aLFIm);
+      for (; aIt.More(); aIt.Next()) {
+        const TopoDS_Shape& aFIm = aIt.Value();
+        AddFace(aFIm, myFaces);
+      }
+    }
+    else {
+      AddFace(aF, myFaces);
+    }
+  }
+}
+
+//=======================================================================
+//function : MakeBox
+//purpose  : 
+//=======================================================================
+void BOPAlgo_MakerVolume::MakeBox(BOPCol_MapOfShape& theBoxFaces)
+{
+  UserBreak();
+  //
+  Standard_Real aXmin, aYmin, aZmin, aXmax, aYmax, aZmax, anExt;
+  //
+  anExt = myBBox.SquareExtent() * 0.5;
+  myBBox.Enlarge(anExt);
+  myBBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
+  //
+  gp_Pnt aPMin(aXmin, aYmin, aZmin), 
+         aPMax(aXmax, aYmax, aZmax);
+  //
+  mySBox = BRepPrimAPI_MakeBox(aPMin, aPMax).Solid();
+  //
+  TopExp_Explorer aExp(mySBox, TopAbs_FACE);
+  for (; aExp.More(); aExp.Next()) {
+    const TopoDS_Shape& aF = aExp.Current();
+    myFaces.Append(aF);
+    theBoxFaces.Add(aF);
+  }
+}
+
+//=======================================================================
+//function : BuildSolids
+//purpose  : 
+//=======================================================================
+void BOPAlgo_MakerVolume::BuildSolids(BOPCol_ListOfShape& theLSR)
+{
+  UserBreak();
+  //
+  BOPAlgo_BuilderSolid aBS;
+  //
+  aBS.SetSolid(mySBox);
+  aBS.SetShapes(myFaces);
+  aBS.SetRunParallel(myRunParallel);
+  aBS.Perform();
+  if (aBS.ErrorStatus()) {
+    myErrorStatus = 103;
+    return;
+  }
+  //
+  theLSR = aBS.Areas();
+}
+
+//=======================================================================
+//function : TreatResult
+//purpose  : 
+//=======================================================================
+void BOPAlgo_MakerVolume::RemoveBox(BOPCol_ListOfShape&      theLSR,
+                                    const BOPCol_MapOfShape& theBoxFaces)
+{
+  UserBreak();
+  //
+  BOPCol_ListIteratorOfListOfShape aIt;
+  TopExp_Explorer aExp;
+  Standard_Boolean bFound;
+  //
+  bFound = Standard_False;
+  aIt.Initialize(theLSR);
+  for (; aIt.More(); aIt.Next()) {
+    const TopoDS_Shape& aSR = aIt.Value();
+    //
+    aExp.Init(aSR, TopAbs_FACE);
+    for (; aExp.More(); aExp.Next()) {
+      const TopoDS_Shape& aF = aExp.Current();
+      if (theBoxFaces.Contains(aF)) {
+        bFound = Standard_True;
+        theLSR.Remove(aIt);
+        break;
+      }
+    }
+    if (bFound) {
+      break;
+    }
+  }
+}
+
+//=======================================================================
+//function : BuildShape
+//purpose  : 
+//=======================================================================
+void BOPAlgo_MakerVolume::BuildShape(const BOPCol_ListOfShape& theLSR)
+{ 
+  if (theLSR.Extent() == 1) {
+    myShape = theLSR.First();
+  }
+  else {
+    BRep_Builder aBB;
+    BOPCol_ListIteratorOfListOfShape aIt;
+    //
+    aIt.Initialize(theLSR);
+    for (; aIt.More(); aIt.Next()) {
+      const TopoDS_Shape& aSol = aIt.Value();
+      aBB.Add(myShape, aSol);
+    }
+  }
+}
+
+//=======================================================================
+//function : FillInternalShapes 
+//purpose  : 
+//=======================================================================
+void BOPAlgo_MakerVolume::FillInternalShapes(const BOPCol_ListOfShape& theLSR)
+{
+  UserBreak();
+  //
+  Standard_Integer aNbSI;
+  TopAbs_ShapeEnum aType;
+  TopAbs_State aState; 
+  TopoDS_Iterator aItS;
+  BRep_Builder aBB;
+  BOPCol_MapOfShape aMFence;
+  BOPCol_IndexedMapOfShape aMSS;
+  BOPCol_ListOfShape aLVE, aLSC, aLSIn;
+  BOPCol_ListIteratorOfListOfShape aIt, aIt1;
+  //
+  // 1. Collect shapes to process: vertices, edges, wires
+  const BOPCol_ListOfShape& anArguments = myDS->Arguments();
+  aIt.Initialize(anArguments);
+  for (; aIt.More(); aIt.Next()) {
+    const TopoDS_Shape& aS = aIt.Value();
+    TreatCompound(aS, aMFence, aLSC);
+  }
+  //
+  aIt.Initialize(aLSC);
+  for (; aIt.More(); aIt.Next()) {
+    const TopoDS_Shape& aS = aIt.Value();
+    aType = aS.ShapeType();
+    if (aType == TopAbs_WIRE) {
+      aItS.Initialize(aS);
+      for(; aItS.More(); aItS.Next()) {
+        const TopoDS_Shape& aE = aItS.Value();
+        if (aMFence.Add(aE)) {
+          aLVE.Append(aE);
+        }
+      }
+    }
+    else if (aType == TopAbs_VERTEX || aType == TopAbs_EDGE) {
+      aLVE.Append(aS);
+    } 
+  }
+  //
+  aIt.Initialize(theLSR);
+  for (; aIt.More(); aIt.Next()) {
+    const TopoDS_Shape& aS = aIt.Value();
+    BOPTools::MapShapes(aS, TopAbs_EDGE, aMSS);
+    BOPTools::MapShapes(aS, TopAbs_VERTEX, aMSS);
+  }
+  //
+  aIt.Initialize(aLVE);
+  for (; aIt.More(); aIt.Next()) {
+    const TopoDS_Shape& aS = aIt.Value();
+    if (myImages.IsBound(aS)) {
+      const BOPCol_ListOfShape &aLSp = myImages.Find(aS);
+      aIt1.Initialize(aLSp);
+      for (; aIt1.More(); aIt1.Next()) {
+        const TopoDS_Shape& aSp = aIt1.Value();
+        if (aMSS.Add(aSp)) {
+          aLSIn.Append(aSp);
+        }
+      }
+    }
+    else {
+      if (aMSS.Add(aS)) {
+        aLSIn.Append(aS);
+      }
+    }
+  }
+  //
+  aNbSI = aLSIn.Extent();
+  if (!aNbSI) {
+    return;
+  }
+  //
+  // 2. Settle internal vertices and edges into solids
+  aIt.Initialize(theLSR);
+  for (; aIt.More(); aIt.Next()) {
+    TopoDS_Solid aSd = *(TopoDS_Solid*)&aIt.Value();
+    //
+    aIt1.Initialize(aLSIn);
+    for (; aIt1.More(); ) {
+      TopoDS_Shape aSI = aIt1.Value();
+      aSI.Orientation(TopAbs_INTERNAL);
+      //
+      aState = BOPTools_AlgoTools::ComputeStateByOnePoint(aSI, aSd, 1.e-11, myContext);
+      if (aState == TopAbs_IN) {
+        aBB.Add(aSd, aSI);
+        aLSIn.Remove(aIt1);
+      }
+      else {
+        aIt1.Next();
+      }
+    }
+  }
+}
+
+//=======================================================================
+//function : AddFace
+//purpose  : 
+//=======================================================================
+void AddFace(const TopoDS_Shape& theF,
+             BOPCol_ListOfShape& theLF)
+{
+  TopoDS_Shape aFF = theF;
+  aFF.Orientation(TopAbs_FORWARD);
+  theLF.Append(aFF);
+  aFF.Orientation(TopAbs_REVERSED);
+  theLF.Append(aFF);
+}
+
+//=======================================================================
+//function : TreatCompound
+//purpose  : 
+//=======================================================================
+void TreatCompound(const TopoDS_Shape& theS,
+                   BOPCol_MapOfShape& aMFence,
+                   BOPCol_ListOfShape& theLS)
+{
+  TopAbs_ShapeEnum aType = theS.ShapeType();
+  if (aType != TopAbs_COMPOUND) {
+    if (aMFence.Add(theS)) {
+      theLS.Append(theS);
+    }
+    return;
+  }
+  //
+  TopoDS_Iterator aIt(theS);
+  for (; aIt.More(); aIt.Next()) {
+    const TopoDS_Shape& aS = aIt.Value();
+    TreatCompound(aS, aMFence, theLS);
+  }
+}
+
diff --git a/src/BOPAlgo/BOPAlgo_MakerVolume.lxx b/src/BOPAlgo/BOPAlgo_MakerVolume.lxx
new file mode 100644 (file)
index 0000000..d5b3ece
--- /dev/null
@@ -0,0 +1,117 @@
+// Created by: Eugeny MALTCHIKOV
+// Copyright (c) 2014 OPEN CASCADE SAS
+//
+// This file is part of Open CASCADE Technology software library.
+//
+// This library is free software; you can redistribute it and/or modify it under
+// the terms of the GNU Lesser General Public License version 2.1 as published
+// by the Free Software Foundation, with special exception defined in the file
+// OCCT_LGPL_EXCEPTION.txt. Consult the file LICENSE_LGPL_21.txt included in OCCT
+// distribution for complete text of the license and disclaimer of any warranty.
+//
+// Alternatively, this file may be used under the terms of Open CASCADE
+// commercial license or contractual agreement.
+
+//=======================================================================
+//function : BOPAlgo_MakerVolume
+//purpose  : 
+//=======================================================================
+inline BOPAlgo_MakerVolume::BOPAlgo_MakerVolume()
+:
+  BOPAlgo_Builder(),
+  myIntersect(Standard_True)
+{
+}
+
+//=======================================================================
+//function : BOPAlgo_MakerVolume
+//purpose  : 
+//=======================================================================
+inline BOPAlgo_MakerVolume::BOPAlgo_MakerVolume
+  (const Handle(NCollection_BaseAllocator)& theAllocator)
+:
+  BOPAlgo_Builder(theAllocator),
+  myIntersect(Standard_True)
+{
+}
+
+//=======================================================================
+//function : ~BOPAlgo_MakerVolume
+//purpose  : 
+//=======================================================================
+inline BOPAlgo_MakerVolume::~BOPAlgo_MakerVolume()
+{
+  Clear();
+}
+
+//=======================================================================
+//function : Clear
+//purpose  : 
+//=======================================================================
+inline void BOPAlgo_MakerVolume::Clear()
+{
+  BOPAlgo_Builder::Clear();
+  myIntersect = Standard_True;
+  myBBox = Bnd_Box();
+  mySBox.Nullify();
+  myFaces.Clear();
+}
+
+//=======================================================================
+//function : SetIntersect
+//purpose  : 
+//=======================================================================
+inline void BOPAlgo_MakerVolume::SetIntersect(const Standard_Boolean bIntersect)
+{
+  myIntersect = bIntersect;
+}
+
+//=======================================================================
+//function : IsIntersect
+//purpose  : 
+//=======================================================================
+inline Standard_Boolean BOPAlgo_MakerVolume::IsIntersect()const
+{
+  return myIntersect;
+}
+
+//=======================================================================
+//function : Box
+//purpose  : 
+//=======================================================================
+inline const TopoDS_Solid& BOPAlgo_MakerVolume::Box()const
+{
+  return mySBox;
+}
+
+//=======================================================================
+//function : Faces
+//purpose  : 
+//=======================================================================
+inline const BOPCol_ListOfShape& BOPAlgo_MakerVolume::Faces()const
+{
+  return myFaces;
+}
+
+//=======================================================================
+//function : CheckData
+//purpose  : 
+//=======================================================================
+inline void BOPAlgo_MakerVolume::CheckData()
+{
+  if (myArguments.IsEmpty()) {
+    myErrorStatus = 100; // no arguments to process
+    return;
+  }
+  // myPaveFiller
+  if (!myPaveFiller) {
+    myErrorStatus = 101; 
+    return;
+  }
+  //
+  myErrorStatus = myPaveFiller->ErrorStatus();
+  if (myErrorStatus) {
+    myErrorStatus = 102; // PaveFiller is failed
+    return;
+  }
+}
index 119bfc3..15cd258 100644 (file)
@@ -29,6 +29,7 @@
 #include <BOPAlgo_PaveFiller.hxx>
 #include <BOPAlgo_Operation.hxx>
 #include <BOPAlgo_BOP.hxx>
+#include <BOPAlgo_MakerVolume.hxx>
 #include <BOPDS_DS.hxx>
 #include <BOPTest_DrawableShape.hxx>
 #include <BOPCol_ListOfShape.hxx>
@@ -75,6 +76,8 @@ static Standard_Integer bcommon   (Draw_Interpretor&, Standard_Integer, const ch
 //
 static Standard_Integer bopcurves (Draw_Interpretor&, Standard_Integer, const char**);
 static Standard_Integer bopnews   (Draw_Interpretor&, Standard_Integer, const char**);
+//
+static Standard_Integer mkvolume   (Draw_Interpretor&, Standard_Integer, const char**);
 
 //=======================================================================
 //function : BOPCommands
@@ -105,6 +108,8 @@ static Standard_Integer bopnews   (Draw_Interpretor&, Standard_Integer, const ch
   //
   theCommands.Add("bopcurves", "use  bopcurves F1 F2 [-2d]", __FILE__, bopcurves, g);
   theCommands.Add("bopnews", "use  bopnews -v[e,f]"  , __FILE__, bopnews, g);
+  //
+  theCommands.Add("mkvolume", "make solids from set of shapes.\nmkvolume r b1 b2 ... [-ni (do not intersect)] [-s (run in non parallel mode)]", __FILE__, mkvolume , g);
 }
 
 //=======================================================================
@@ -686,3 +691,81 @@ Standard_Integer bopcurves (Draw_Interpretor& di,
   
   return 0;
 }
+
+//=======================================================================
+//function : mkvolume
+//purpose  : 
+//=======================================================================
+Standard_Integer mkvolume(Draw_Interpretor& di, Standard_Integer n, const char** a) 
+{
+  const char* usage = "Usage: mkvolume r b1 b2 ... [-ni (do not intersect)] [-s (run in non parallel mode)]\n";
+  if (n < 3) {
+    di << usage;
+    return 1;
+  }
+  //
+  Standard_Boolean bToIntersect, bRunParallel;
+  Standard_Integer i, aNb;
+  //
+  aNb = n;
+  bToIntersect = Standard_True;
+  bRunParallel = Standard_True;
+  //
+  if (!strcmp(a[n-1], "-ni")) {
+    bToIntersect = Standard_False;
+    aNb = n-1;
+  } 
+  else if (!strcmp(a[n-1], "-s")) {
+    bRunParallel = Standard_False;
+    aNb = n-1;
+  }
+  if (n > 3) {
+    if (!strcmp(a[n-2], "-ni")) {
+      bToIntersect = Standard_False;
+      aNb = n-2;
+    } 
+    else if (!strcmp(a[n-2], "-s")) {
+      bRunParallel = Standard_False;
+      aNb = n-2;
+    }
+  }
+  //
+  if (aNb < 3) {
+    di << "no shapes to process.\n";
+    di << usage;
+    return 1;
+  }
+  //
+  BOPCol_ListOfShape aLS;
+  TopoDS_Shape aS;
+  for (i = 2; i < aNb; ++i) {
+    aS = DBRep::Get(a[i]);
+    if (!aS.IsNull()) {
+      aLS.Append(aS);
+    }
+  }
+  //
+  if (aLS.IsEmpty()) {
+    di << "no shapes to process.\n";
+    di << usage;
+    return 1;
+  }
+  //
+  BOPAlgo_MakerVolume aMV;
+  aMV.SetArguments(aLS);
+  aMV.SetIntersect(bToIntersect);
+  aMV.SetRunParallel(bRunParallel);
+  //
+  aMV.Perform();
+  if (aMV.ErrorStatus()) {
+    di << "Error status: " << aMV.ErrorStatus();
+    return 1;
+  }
+  //
+  const TopoDS_Shape& aR = aMV.Shape();
+  //
+  DBRep::Set(a[1], aR);
+  //
+  return 0;
+}
+
index c24e5be..7e5ed36 100755 (executable)
@@ -6,3 +6,4 @@ TKG2d
 TKG3d
 TKGeomAlgo
 TKGeomBase
+TKPrim
\ No newline at end of file
diff --git a/tests/bugs/modalg_5/bug25232_1 b/tests/bugs/modalg_5/bug25232_1
new file mode 100644 (file)
index 0000000..a897221
--- /dev/null
@@ -0,0 +1,29 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+box b1 10 10 10
+box b2 4 9 4 2 2 2
+explode b2 w
+sphere s 5 5 5 5
+mkface f s
+mkvolume result b1 f b2_1
+# 2 solids created
+
+set square 1228.32
+
+set nb_v_good 20
+set nb_e_good 21
+set nb_w_good 7
+set nb_f_good 7
+set nb_sh_good 3
+set nb_sol_good 2
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 61
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_10 b/tests/bugs/modalg_5/bug25232_10
new file mode 100644 (file)
index 0000000..2cc04c1
--- /dev/null
@@ -0,0 +1,26 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+restore [locate_data_file bug25232_BUG_SPHERE_4_mc122-SCM-4-4.brep] b
+explode b f
+mkvolume result b_1 b_2 b_3
+# 3 solids created
+
+set square 5.46979e+06
+
+set nb_v_good 5
+set nb_e_good 7
+set nb_w_good 7
+set nb_f_good 5
+set nb_sh_good 3
+set nb_sol_good 3
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 31
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_11 b/tests/bugs/modalg_5/bug25232_11
new file mode 100644 (file)
index 0000000..994fe97
--- /dev/null
@@ -0,0 +1,26 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+restore [locate_data_file bug25232_BUG3_SPHERE_4_mc122-SCM-4-4.brep] b
+explode b f
+mkvolume result b_1 b_2 b_3 b_4 b_5
+# 16 solids created
+
+set square 1.5988e+07
+
+set nb_v_good 23
+set nb_e_good 54
+set nb_w_good 44
+set nb_f_good 44
+set nb_sh_good 16
+set nb_sol_good 16
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 198
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_12 b/tests/bugs/modalg_5/bug25232_12
new file mode 100644 (file)
index 0000000..601b2fd
--- /dev/null
@@ -0,0 +1,26 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+restore [locate_data_file bug25232_BUG3_SPHERE_4_mc122-SCM-4-4.brep] b
+explode b f
+mkvolume result b_3 b_4 b_2 b_5 -s
+# 8 solids created
+
+set square 1.41057e+07
+
+set nb_v_good 12
+set nb_e_good 25
+set nb_w_good 18
+set nb_f_good 18
+set nb_sh_good 8
+set nb_sol_good 8
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 90
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_2 b/tests/bugs/modalg_5/bug25232_2
new file mode 100644 (file)
index 0000000..f662c94
--- /dev/null
@@ -0,0 +1,28 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+box b1 10 10 10
+explode b1 f
+box b2 4 4 4 2 2 2
+explode b2 w
+mkvolume result b1_1 b1_2 b1_3 b1_4 b1_5 b1_6 b2_1 b2_2 b2_3 b2_4 b2_5 b2_6 -ni
+# 1 solid created
+
+set square 600
+
+set nb_v_good 16
+set nb_e_good 24
+set nb_w_good 6
+set nb_f_good 6
+set nb_sh_good 1
+set nb_sol_good 1
+set nb_compsol_good 0
+set nb_compound_good 0
+set nb_shape_good 54
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_3 b/tests/bugs/modalg_5/bug25232_3
new file mode 100644 (file)
index 0000000..687b7af
--- /dev/null
@@ -0,0 +1,28 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+box b1 10 10 10
+sphere s 5 5 5 3
+mkface b2 s
+vertex b3 5 5 5
+mkvolume result b1 b2 b3 -ni
+# 2 solids created
+
+set square 826.195
+
+set nb_v_good 11
+set nb_e_good 15
+set nb_w_good 7
+set nb_f_good 7
+set nb_sh_good 3
+set nb_sol_good 2
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 46
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_4 b/tests/bugs/modalg_5/bug25232_4
new file mode 100644 (file)
index 0000000..73901be
--- /dev/null
@@ -0,0 +1,37 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+cylinder cyl 10
+trimv cyl cyl -20 20
+mkface fcyl cyl
+cone con 45 0
+trimv con1 con 0 15
+trimv con2 con -15 0
+mkface fcon1 con1
+mkface fcon2 con2
+plane pl 0 0 15 0 0 1
+mkface fp pl -15 15 -15 15
+sphere sph 0 0 0 12
+mkface fsph sph
+
+mkvolume result fcyl fcon1 fcon2 fp fsph
+# 7 solids created
+
+set square 6725.11
+
+set nb_v_good 12
+set nb_e_good 26
+set nb_w_good 14
+set nb_f_good 14
+set nb_sh_good 7
+set nb_sol_good 7
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 81
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_5 b/tests/bugs/modalg_5/bug25232_5
new file mode 100644 (file)
index 0000000..5a34fa5
--- /dev/null
@@ -0,0 +1,37 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+cylinder cyl 10
+trimv cyl cyl -20 20
+mkface fcyl cyl
+cone con 45 0
+trimv con1 con 0 15
+trimv con2 con -15 0
+mkface fcon1 con1
+mkface fcon2 con2
+plane pl 0 0 15 0 0 1
+mkface fp pl -15 15 -15 15
+sphere sph 0 0 0 12
+mkface fsph sph
+
+mkvolume result fcyl fsph
+# 2 solids created
+
+set square 3476.67
+
+set nb_v_good 4
+set nb_e_good 8
+set nb_w_good 4
+set nb_f_good 4
+set nb_sh_good 2
+set nb_sol_good 2
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 25
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_6 b/tests/bugs/modalg_5/bug25232_6
new file mode 100644 (file)
index 0000000..0c01870
--- /dev/null
@@ -0,0 +1,37 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+cylinder cyl 10
+trimv cyl cyl -20 20
+mkface fcyl cyl
+cone con 45 0
+trimv con1 con 0 15
+trimv con2 con -15 0
+mkface fcon1 con1
+mkface fcon2 con2
+plane pl 0 0 15 0 0 1
+mkface fp pl -15 15 -15 15
+sphere sph 0 0 0 12
+mkface fsph sph
+
+mkvolume result fsph fcon1
+# 2 solids created
+
+set square 2449.33
+
+set nb_v_good 4
+set nb_e_good 7
+set nb_w_good 3
+set nb_f_good 3
+set nb_sh_good 2
+set nb_sol_good 2
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 22
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_7 b/tests/bugs/modalg_5/bug25232_7
new file mode 100644 (file)
index 0000000..a1504b4
--- /dev/null
@@ -0,0 +1,35 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+cylinder cyl 10
+trimv cyl cyl -20 20
+mkface fcyl cyl
+cone con 45 0
+trimv con1 con 0 15
+trimv con2 con -15 0
+mkface fcon1 con1
+mkface fcon2 con2
+plane pl 0 0 15 0 0 1
+mkface fp pl -15 15 -15 15
+sphere sph 0 0 0 12
+mkface fsph sph
+
+mkvolume result fcyl fp
+# 0 solids
+
+set nb_v_good 0
+set nb_e_good 0
+set nb_w_good 0
+set nb_f_good 0
+set nb_sh_good 0
+set nb_sol_good 0
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 1
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_8 b/tests/bugs/modalg_5/bug25232_8
new file mode 100644 (file)
index 0000000..1398966
--- /dev/null
@@ -0,0 +1,39 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+cylinder cyl 10
+trimv cyl cyl -20 20
+mkface fcyl cyl
+cone con 45 0
+trimv con1 con 0 15
+trimv con2 con -15 0
+mkface fcon1 con1
+mkface fcon2 con2
+plane pl 0 0 15 0 0 1
+mkface fp pl -15 15 -15 15
+sphere sph 0 0 0 12
+mkface fsph sph
+
+trimv con3 con 0 30
+mkface fcon3 con3
+mkvolume result fcon3 fp
+# 1 solid created
+
+set square 1706.51
+
+set nb_v_good 4
+set nb_e_good 5
+set nb_w_good 2
+set nb_f_good 2
+set nb_sh_good 1
+set nb_sol_good 1
+set nb_compsol_good 0
+set nb_compound_good 0
+set nb_shape_good 15
+
+set 2dviewer 1
diff --git a/tests/bugs/modalg_5/bug25232_9 b/tests/bugs/modalg_5/bug25232_9
new file mode 100644 (file)
index 0000000..1a14744
--- /dev/null
@@ -0,0 +1,36 @@
+puts "============"
+puts "OCC25232"
+puts "============"
+puts ""
+#########################################################################
+# Functionality to create solids from set of shapes
+#########################################################################
+
+compound b1
+compound b2
+compound b3
+set nbi 21
+set nbj 21
+set nbk 21
+for {set i 0} {$i < $nbi} {incr i} {plane p 0 0 [expr $i-10] 0 0 1; mkface f_$i p -10 10 -10 10; add f_$i b1;}
+for {set j 0} {$j < $nbj} {incr j} {plane p [expr $j-10] 0 0 1 0 0; mkface f_$j p -10 10 -10 10; add f_$j b2;}
+for {set k 0} {$k < $nbk} {incr k} {plane p 0 [expr $k-10] 0 0 1 0; mkface f_$k p -10 10 -10 10; add f_$k b3;}
+sphere s 0 0 0 10
+mkface f s
+
+mkvolume result b1 b2 b3 f
+# 9832 solids created
+
+set square 50513.3
+
+set nb_v_good 11037
+set nb_e_good 31880
+set nb_w_good 30668
+set nb_f_good 30668
+set nb_sh_good 9832
+set nb_sol_good 9832
+set nb_compsol_good 0
+set nb_compound_good 1
+set nb_shape_good 123918
+
+set 2dviewer 1