0025529: ShapeProcessAPI: introduce DropSmallSolids operator
authormyn <myn@opencascade.com>
Thu, 11 Dec 2014 14:31:28 +0000 (17:31 +0300)
committerbugmaster <bugmaster@opencascade.com>
Thu, 11 Dec 2014 14:35:41 +0000 (17:35 +0300)
Implemented DropSmallSolids operator

Source code corrected and optimized; tests added

tests improved

17 files changed:
src/ShapeFix/ShapeFix.cdl
src/ShapeFix/ShapeFix_FixSmallSolid.cdl [new file with mode: 0644]
src/ShapeFix/ShapeFix_FixSmallSolid.cxx [new file with mode: 0644]
src/ShapeProcess/ShapeProcess_OperLibrary.cxx
tests/heal/drop_small_solids/M1 [new file with mode: 0644]
tests/heal/drop_small_solids/M2 [new file with mode: 0644]
tests/heal/drop_small_solids/M3 [new file with mode: 0644]
tests/heal/drop_small_solids/R1 [new file with mode: 0644]
tests/heal/drop_small_solids/R2 [new file with mode: 0644]
tests/heal/drop_small_solids/R3 [new file with mode: 0644]
tests/heal/drop_small_solids/R4 [new file with mode: 0644]
tests/heal/drop_small_solids/R5 [new file with mode: 0644]
tests/heal/drop_small_solids/R6 [new file with mode: 0644]
tests/heal/drop_small_solids/R7 [new file with mode: 0644]
tests/heal/drop_small_solids/R8 [new file with mode: 0644]
tests/heal/drop_small_solids/end [new file with mode: 0644]
tests/heal/grids.list

index fa75eb1..759fd41 100644 (file)
@@ -60,6 +60,8 @@ is
 
     class FixSmallFace;
 
+    class FixSmallSolid;
+
     class WireVertex;
 
     class Wireframe;
diff --git a/src/ShapeFix/ShapeFix_FixSmallSolid.cdl b/src/ShapeFix/ShapeFix_FixSmallSolid.cdl
new file mode 100644 (file)
index 0000000..6905446
--- /dev/null
@@ -0,0 +1,51 @@
+-- Created on: 2014-11-13
+-- Created by: Maxim YAKUNIN
+-- 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 FixSmallSolid from ShapeFix
+
+       ---Purpose: Fixing solids with small size
+
+uses
+    Shape   from TopoDS,
+    ReShape from ShapeBuild
+    
+is
+    Create returns FixSmallSolid;
+    ---Purpose: Construct
+
+    SetVolumeThreshold (me: in out; theThreshold: Real = -1.0);
+    ---Purpose: Set or clear volume threshold for small solids
+
+    SetWidthFactorThreshold (me: in out; theThreshold: Real = -1.0);
+    ---Purpose: Set or clear width factor threshold for small solids
+
+    Remove(me; theShape: Shape from TopoDS; theContext: ReShape from ShapeBuild)
+    returns Shape from TopoDS;
+    ---Purpose: Remove small solids from the given shape
+    
+    Merge (me; theShape: Shape from TopoDS; theContext: ReShape from ShapeBuild)
+    returns Shape from TopoDS;
+    ---Purpose: Merge small solids in the given shape to adjacent non-small ones
+
+    IsThresholdsSet (me) returns Boolean is private;
+
+    IsSmall (me; theSolid: Shape from TopoDS) returns Boolean is private;
+
+fields
+
+    myVolumeThreshold      : Real;
+    myWidthFactorThreshold : Real;
+
+end FixSmallSolid;
diff --git a/src/ShapeFix/ShapeFix_FixSmallSolid.cxx b/src/ShapeFix/ShapeFix_FixSmallSolid.cxx
new file mode 100644 (file)
index 0000000..f2b2e25
--- /dev/null
@@ -0,0 +1,522 @@
+// 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 <ShapeFix_FixSmallSolid.ixx>
+
+#include <Precision.hxx>
+
+#include <TopoDS_Builder.hxx>
+#include <TopoDS_Compound.hxx>
+#include <TopoDS_Iterator.hxx>
+#include <TopExp_Explorer.hxx>
+
+#include <TopTools_ListOfShape.hxx>
+#include <TopTools_ListIteratorOfListOfShape.hxx>
+#include <TopTools_MapOfShape.hxx>
+#include <TopTools_MapIteratorOfMapOfShape.hxx>
+#include <TopTools_DataMapOfShapeReal.hxx>
+#include <TopTools_DataMapOfShapeShape.hxx>
+#include <TopTools_DataMapOfShapeListOfShape.hxx>
+#include <TopTools_DataMapIteratorOfDataMapOfShapeListOfShape.hxx>
+
+#include <GProp_GProps.hxx>
+#include <BRepGProp.hxx>
+#include <BRep_Builder.hxx>
+#include <ShapeBuild_ReShape.hxx>
+
+//=======================================================================
+//function : ShapeFix_FixSmallSolid
+//purpose  : Construct
+//=======================================================================
+ShapeFix_FixSmallSolid::ShapeFix_FixSmallSolid()
+  : myVolumeThreshold      (Precision::Infinite())
+  , myWidthFactorThreshold (Precision::Infinite()) {}
+
+//=======================================================================
+//function : SetVolumeThreshold
+//purpose  : Set or clear volume threshold for small solids
+//=======================================================================
+void ShapeFix_FixSmallSolid::SetVolumeThreshold (
+  const Standard_Real theThreshold)
+{
+  myVolumeThreshold =
+    theThreshold >= 0.0 ? theThreshold : Precision::Infinite();
+}
+
+//=======================================================================
+//function : SetWidthFactorThreshold
+//purpose  : Set or clear width factor threshold for small solids
+//=======================================================================
+void ShapeFix_FixSmallSolid::SetWidthFactorThreshold (
+  const Standard_Real theThreshold)
+{
+  myWidthFactorThreshold =
+    theThreshold >= 0.0 ? theThreshold : Precision::Infinite();
+}
+
+//=======================================================================
+//function : IsValidInput
+//purpose  : auxiliary
+//=======================================================================
+// Check if an input shape is valid
+static Standard_Boolean IsValidInput (const TopoDS_Shape& theShape)
+{
+  if (theShape.IsNull())
+    return Standard_False;
+
+  switch (theShape.ShapeType())
+  {
+  case TopAbs_COMPOUND:
+  case TopAbs_COMPSOLID:
+  case TopAbs_SOLID:
+    return Standard_True;
+  default:
+    return Standard_False;
+  }
+}
+
+//=======================================================================
+//function : Remove
+//purpose  : Remove small solids from the given shape
+//=======================================================================
+TopoDS_Shape ShapeFix_FixSmallSolid::Remove (
+  const TopoDS_Shape& theShape,
+  const Handle(ShapeBuild_ReShape)& theContext) const
+{
+  // Check if at least one smallness criterion is set and the shape is valid
+  if (!IsThresholdsSet() || !IsValidInput (theShape)) return theShape;
+
+  // Find and remove all small solids
+  TopExp_Explorer aSolidIter (theShape, TopAbs_SOLID);
+  for (; aSolidIter.More(); aSolidIter.Next())
+  {
+    const TopoDS_Shape& aSolid = aSolidIter.Current();
+    if (IsSmall (aSolid))
+      theContext->Remove (aSolid);
+  }
+
+  // Return updated shape
+  return theContext->Apply (theShape);
+}
+
+//=======================================================================
+//function : ShapeArea
+//purpose  : auxiliary
+//=======================================================================
+// Calculate surface area of a shape
+static Standard_Real ShapeArea (const TopoDS_Shape& theShape)
+{
+  GProp_GProps aProps;
+  BRepGProp::SurfaceProperties (theShape, aProps);
+  return aProps.Mass();
+}
+
+//=======================================================================
+//function : ShapeVolume
+//purpose  : auxiliary
+//=======================================================================
+// Calculate volume of a shape
+static Standard_Real ShapeVolume (const TopoDS_Shape& theShape)
+{
+  GProp_GProps aProps;
+  BRepGProp::VolumeProperties (theShape, aProps);
+  return aProps.Mass();
+}
+
+//=======================================================================
+//function : AddToMap
+//purpose  : auxiliary
+//=======================================================================
+// Append an item to a list of shapes mapped to a shape
+static void AddToMap (TopTools_DataMapOfShapeListOfShape& theMap,
+                      const TopoDS_Shape& theKey,
+                      const TopoDS_Shape& theItem)
+{
+  Standard_Address aListPtr = theMap.ChangeFind1 (theKey);
+  if (aListPtr == NULL)
+  {
+    TopTools_ListOfShape aList;
+    aList.Append (theItem);
+    theMap.Bind (theKey, aList);
+  }
+  else
+    ((TopTools_ListOfShape*)aListPtr)->Append (theItem);
+}
+
+//=======================================================================
+//function : AddToMap
+//purpose  : auxiliary
+//=======================================================================
+// Append items to a list of shapes mapped to a shape
+static void AddToMap (TopTools_DataMapOfShapeListOfShape& theMap,
+                      const TopoDS_Shape& theKey,
+                      TopTools_ListOfShape& theItems)
+{
+  if (theItems.IsEmpty()) return;
+
+  Standard_Address aListPtr = theMap.ChangeFind1 (theKey);
+  if (aListPtr == NULL)
+    theMap.Bind (theKey, theItems);
+  else
+    ((TopTools_ListOfShape*)aListPtr)->Append (theItems);
+}
+
+//=======================================================================
+//function : MapFacesToShells
+//purpose  : auxiliary
+//=======================================================================
+// Map faces from a solid with their shells;
+// unmap faces shared between two shells
+static void MapFacesToShells (const TopoDS_Shape& theSolid,
+                              TopTools_DataMapOfShapeShape& theMap)
+{
+  TopoDS_Iterator aShellIter (theSolid);
+  for (; aShellIter.More(); aShellIter.Next())
+  {
+    const TopoDS_Shape& aShell = aShellIter.Value();
+    if (aShell.ShapeType() != TopAbs_SHELL) continue;
+
+    TopoDS_Iterator aFaceIter (aShell);
+    for (; aFaceIter.More(); aFaceIter.Next())
+    {
+      const TopoDS_Shape& aFace = aFaceIter.Value();
+      if (aFace.ShapeType() != TopAbs_FACE) continue;
+
+      if (!theMap.Bind (aFace, aShell))
+        theMap.UnBind (aFace);
+    }
+  }
+}
+
+//=======================================================================
+//function : FindMostSharedShell
+//purpose  : auxiliary
+//=======================================================================
+// Find an outer shell having greatest sum area of
+// all faces shared with the solid
+static Standard_Boolean FindMostSharedShell (
+  const TopoDS_Shape& theSolid,
+  const TopTools_DataMapOfShapeShape& theMapFacesToOuterShells,
+  TopoDS_Shape& theMostSharedOuterShell,
+  TopoDS_Shape& theMostSharedSolidShell,
+  TopTools_ListOfShape& theOtherSolidShells)
+{
+  TopTools_DataMapOfShapeReal aSharedAreas;
+  Standard_Real aMaxSharedArea = 0.0;
+  const TopoDS_Shape* aMostSharedOuterShellPtr = NULL;
+  const TopoDS_Shape* aMostSharedSolidShellPtr = NULL;
+
+  // check every shell in the solid for faces shared with outer shells
+  TopoDS_Iterator aShellIter (theSolid);
+  for (; aShellIter.More(); aShellIter.Next())
+  {
+    const TopoDS_Shape& aSolidShell = aShellIter.Value();
+    if (aSolidShell.ShapeType() != TopAbs_SHELL) continue;
+
+    theOtherSolidShells.Append (aSolidShell);
+
+    TopoDS_Iterator aFaceIter (aSolidShell);
+    for (; aFaceIter.More(); aFaceIter.Next())
+    {
+      const TopoDS_Shape& aFace = aFaceIter.Value();
+      if (aFace.ShapeType() != TopAbs_FACE) continue;
+    
+      // find an outer shell that shares the current face
+      Standard_Address anOuterShellPtr = theMapFacesToOuterShells.Find1 (aFace);
+      if (anOuterShellPtr == NULL) continue;
+      const TopoDS_Shape& anOuterShell = *(TopoDS_Shape*)anOuterShellPtr;
+    
+      // add the face area to the sum shared area for the outer shell
+      Standard_Real anArea = ShapeArea (aFace);
+      Standard_Address aSharedAreaPtr = aSharedAreas.ChangeFind1 (anOuterShell);
+      if (aSharedAreaPtr == NULL)
+        aSharedAreas.Bind (anOuterShell, anArea);
+      else
+        anArea = *(Standard_Real*)aSharedAreaPtr += anArea;
+    
+      // if this outer shell currently has maximum shared area,
+      // remember it and the current solid's shell
+      if (aMaxSharedArea < anArea)
+      {
+        aMaxSharedArea           = anArea;
+        aMostSharedOuterShellPtr = &anOuterShell;
+        aMostSharedSolidShellPtr = &aSolidShell;
+      }
+    }
+  }
+
+  // return nothing if no adjanced outer shells were found
+  if (aMostSharedSolidShellPtr == NULL)
+    return Standard_False;
+
+  // compose return values
+  theMostSharedOuterShell = *aMostSharedOuterShellPtr;
+  theMostSharedSolidShell = *aMostSharedSolidShellPtr;
+
+  // remove the most shared solid's shell from the returned list of its other shells
+  TopTools_ListIteratorOfListOfShape anOtherShellIter (theOtherSolidShells);
+  while (!anOtherShellIter.Value().IsSame (theMostSharedSolidShell))
+    anOtherShellIter.Next();
+  theOtherSolidShells.Remove (anOtherShellIter);
+
+  return Standard_True;
+}
+
+//=======================================================================
+//function : MergeShells
+//purpose  : auxiliary
+//=======================================================================
+// Merge some shells to a base shell
+static TopoDS_Shape MergeShells (
+  const TopoDS_Shape& theBaseShell,
+  TopTools_ListOfShape& theShellsToMerge,
+  const TopTools_DataMapOfShapeShape& theMapFacesToOuterShells,
+  TopTools_DataMapOfShapeShape& theMapNewFreeFacesToShells)
+{
+  // Create a new shell
+  BRep_Builder aBuilder;
+  TopoDS_Shape aNewShell = theBaseShell.EmptyCopied();
+
+  // Sort the faces belogning to the merged shells:
+  // - faces shared with the base shell:
+  //     keep to remove from the base shell;
+  // - faces shared with other outer shells, non-face elements:
+  //     add to the new shell;
+  // - faces not shared with any outer or any merged shell:
+  //     keep to add to the new shell and to the new map.
+  TopTools_MapOfShape aRemoveFaces;
+  TopTools_MapOfShape aNewFreeFaces;
+
+  TopTools_ListIteratorOfListOfShape aShellIter (theShellsToMerge);
+  for (; aShellIter.More(); aShellIter.Next())
+  {
+    TopoDS_Iterator aFaceIter (aShellIter.Value());
+    for (; aFaceIter.More(); aFaceIter.Next())
+    {
+      const TopoDS_Shape& aFace = aFaceIter.Value();
+
+      // non-face element in a shell - just add it to the new shell
+      if (aFace.ShapeType() != TopAbs_FACE)
+      {
+        aBuilder.Add (aNewShell, aFace);
+        continue;
+      }
+
+      // classify the face
+      Standard_Address anOuterShellPtr = theMapFacesToOuterShells.Find1 (aFace);
+      if (anOuterShellPtr != NULL)
+      {
+        if (((TopoDS_Shape*)anOuterShellPtr)->IsSame (theBaseShell))
+          aRemoveFaces.Add (aFace);        // face shared with the base shell
+        else
+          aBuilder.Add (aNewShell, aFace); // face shared with another outer shell
+      }
+      else
+      {
+        if (aNewFreeFaces.Contains (aFace))
+          aNewFreeFaces.Remove (aFace);    // face shared with another merged shell
+        else
+          aNewFreeFaces.Add (aFace);       // face not shared
+      }
+    }
+  }
+  theShellsToMerge.Clear();
+
+  // Add the kept faces from the merged shells to the new shell
+  TopTools_MapIteratorOfMapOfShape aNewFaceIter (aNewFreeFaces);
+  for (; aNewFaceIter.More(); aNewFaceIter.Next())
+  {
+    const TopoDS_Shape& aFace = aNewFaceIter.Key();
+    aBuilder.Add (aNewShell, aFace);
+    theMapNewFreeFacesToShells.Bind (aFace, aNewShell);
+  }
+  aNewFreeFaces.Clear();
+
+  // Add needed faces from the base shell to the new shell
+  TopoDS_Iterator aBaseFaceIter (theBaseShell);
+  for (; aBaseFaceIter.More(); aBaseFaceIter.Next())
+  {
+    const TopoDS_Shape& aFace = aBaseFaceIter.Value();
+    if (!aRemoveFaces.Contains (aFace))
+      aBuilder.Add (aNewShell, aFace);
+  }
+  
+  // If there are no elements in the new shell, return null shape
+  if (!TopoDS_Iterator (aNewShell).More())
+    return TopoDS_Shape();
+
+  return aNewShell;
+}
+
+//=======================================================================
+//function : AddShells
+//purpose  : auxiliary
+//=======================================================================
+// Add some shells to a base shell
+static TopoDS_Compound AddShells (
+  const TopoDS_Shape& theBaseShell,
+  TopTools_ListOfShape& theShellsToAdd)
+{
+  // Create a compound
+  BRep_Builder aBuilder;
+  TopoDS_Compound aCompound;
+  aBuilder.MakeCompound (aCompound);
+
+  // Add the base shell to the compound
+  if (!theBaseShell.IsNull())
+    aBuilder.Add (aCompound, theBaseShell);
+
+  // Add other shells to the compound
+  TopTools_ListIteratorOfListOfShape aShellIter (theShellsToAdd);
+  for (; aShellIter.More(); aShellIter.Next())
+    aBuilder.Add (aCompound, aShellIter.Value());
+
+  theShellsToAdd.Clear();
+
+  return aCompound;
+}
+
+TopoDS_Shape ShapeFix_FixSmallSolid::Merge (
+  const TopoDS_Shape& theShape,
+  const Handle(ShapeBuild_ReShape)& theContext) const
+{
+  // Check if at least one smallness criterion is set and the shape is valid
+  if (!IsThresholdsSet() || !IsValidInput (theShape)) return theShape;
+
+  // Find all small solids and put them in a list;
+  // Build a map of faces belonging to non-small solids
+  // but not shared between two non-small solids
+  TopTools_ListOfShape aSmallSolids;
+  TopTools_DataMapOfShapeShape aMapFacesToShells;
+
+  TopExp_Explorer aSolidIter (theShape, TopAbs_SOLID);
+  for (; aSolidIter.More(); aSolidIter.Next())
+  {
+    const TopoDS_Shape& aSolid = aSolidIter.Current();
+    if (IsSmall (aSolid))
+      aSmallSolids.Append (aSolid);
+    else
+      MapFacesToShells (aSolid, aMapFacesToShells);
+  }
+
+  // Merge all small solids adjacent to at least one non-small one;
+  // repeat this until no small solids remain or no new solids can be merged
+  TopTools_DataMapOfShapeShape aNewMapFacesToShells;
+  TopTools_DataMapOfShapeShape* aMapFacesToShellsPtr    = &aMapFacesToShells;
+  TopTools_DataMapOfShapeShape* aNewMapFacesToShellsPtr = &aNewMapFacesToShells;
+  while (!aSmallSolids.IsEmpty())
+  {
+    // find small solids that may be merged on the current iteration;
+    // compose their shells in lists associated with non-small solids' shells
+    // which they should be merged to
+    TopTools_DataMapOfShapeListOfShape aShellsToMerge, aShellsToAdd;
+    TopTools_ListIteratorOfListOfShape aSolidIter (aSmallSolids);
+    while (aSolidIter.More())
+    {
+      const TopoDS_Shape& aSmallSolid = aSolidIter.Value();
+
+      // find a non-small solid's shell having greatest sum area of
+      // all faces shared with the current small solid
+      TopoDS_Shape         aNonSmallSolidShell;
+      TopoDS_Shape         anAdjacentShell;
+      TopTools_ListOfShape aNotAdjacentShells;
+      if (FindMostSharedShell (aSmallSolid, *aMapFacesToShellsPtr,
+          aNonSmallSolidShell, anAdjacentShell, aNotAdjacentShells))
+      {
+        // add the small solid's shells to appropriate lists
+        // associated with the selected non-small solid's shell
+        AddToMap (aShellsToMerge, aNonSmallSolidShell, anAdjacentShell);
+        AddToMap (aShellsToAdd  , aNonSmallSolidShell, aNotAdjacentShells);
+
+        // remove the small solid
+        theContext->Remove (aSmallSolid);
+        aSmallSolids.Remove (aSolidIter);
+      }
+      else
+        aSolidIter.Next();
+    }
+
+    // stop if no solids can be merged
+    if (aShellsToMerge.IsEmpty()) break;
+
+    // update needed non-small solids' shells by
+    // merging and adding the listed small solids' shells to them
+    TopTools_DataMapIteratorOfDataMapOfShapeListOfShape
+      aShellIter (aShellsToMerge);
+    for (; aShellIter.More(); aShellIter.Next())
+    {
+      // get the current non-small solid's shell
+      // and corresponding small solids' shells
+      const TopoDS_Shape& aBaseShell = aShellIter.Key();
+      TopTools_ListOfShape& aShellsToBeMerged =
+        (TopTools_ListOfShape&)aShellIter.Value();
+      TopTools_ListOfShape* aShellsToBeAddedPtr =
+        (TopTools_ListOfShape*)aShellsToAdd.ChangeFind1 (aBaseShell);
+
+      // merge needed shells
+      TopoDS_Shape aNewShell = MergeShells (aBaseShell, aShellsToBeMerged,
+                               *aMapFacesToShellsPtr, *aNewMapFacesToShellsPtr);
+
+      // add new shells if needed
+      if (aShellsToBeAddedPtr != NULL)
+        aNewShell = AddShells (aNewShell, *aShellsToBeAddedPtr);
+
+      // replace the current non-small solid's shell with the new one(s)
+      theContext->Replace (aBaseShell, aNewShell);
+    }
+
+    // clear the old faces map and start using the new one
+    aMapFacesToShellsPtr->Clear();
+    std::swap (aMapFacesToShellsPtr, aNewMapFacesToShellsPtr);
+  }
+
+  // Return updated shape
+  return theContext->Apply (theShape);
+}
+
+//=======================================================================
+//function : IsThresholdsSet
+//purpose  : Check if at least one smallness criterion is set
+//=======================================================================
+Standard_Boolean ShapeFix_FixSmallSolid::IsThresholdsSet() const
+{
+  return myVolumeThreshold      < Precision::Infinite()
+      || myWidthFactorThreshold < Precision::Infinite();
+}
+
+//=======================================================================
+//function : IsSmall
+//purpose  : Check if a solid meets the smallness criteria
+//=======================================================================
+Standard_Boolean ShapeFix_FixSmallSolid::IsSmall (const TopoDS_Shape& theSolid)
+  const
+{
+  // If the volume threshold is set and the solid's volume exceeds it,
+  // consider the solid as not small
+  Standard_Real aVolume = ShapeVolume (theSolid);
+  if (aVolume > myVolumeThreshold)
+    return Standard_False;
+
+  // If the width factor threshold is set
+  // and the solid's width factor exceeds it
+  // consider the solid as not small
+  if (myWidthFactorThreshold < Precision::Infinite())
+  {
+    Standard_Real anArea = ShapeArea (theSolid);
+    if (aVolume > myWidthFactorThreshold * anArea * 0.5)
+      return Standard_False;
+  }
+
+  // Both thresholds are met - consider the solid as small
+  return Standard_True;
+}
index bf51b35..5fad0ed 100644 (file)
@@ -52,6 +52,7 @@
 #include <ShapeFix_Face.hxx>
 #include <ShapeFix_Wire.hxx>
 #include <ShapeFix_FixSmallFace.hxx>
+#include <ShapeFix_FixSmallSolid.hxx>
 #include <ShapeFix_Wireframe.hxx>
 #include <ShapeFix.hxx>
 #include <ShapeFix_SplitCommonVertex.hxx>
@@ -512,6 +513,45 @@ static Standard_Boolean fixwgaps (const Handle(ShapeProcess_Context)& context)
   return Standard_True;
 }
 
+//=======================================================================
+//function : dropsmallsolids
+//purpose  : 
+//=======================================================================
+
+static Standard_Boolean dropsmallsolids (const Handle(ShapeProcess_Context)& context)
+{
+  Handle(ShapeProcess_ShapeContext) ctx =
+    Handle(ShapeProcess_ShapeContext)::DownCast (context);
+  if (ctx.IsNull()) return Standard_False;
+
+  ShapeFix_FixSmallSolid FSS;
+
+  Standard_Real aThreshold;
+  if (ctx->GetReal ("VolumeThreshold", aThreshold))
+    FSS.SetVolumeThreshold (aThreshold);
+  if (ctx->GetReal ("WidthFactorThreshold", aThreshold))
+    FSS.SetWidthFactorThreshold (aThreshold);
+
+  Standard_Boolean aMerge = Standard_False;
+  ctx->GetBoolean ("MergeSolids", aMerge);
+
+  Handle(ShapeBuild_ReShape) aReShape = new ShapeBuild_ReShape;
+
+  TopoDS_Shape aResult;
+  if (aMerge)
+    aResult = FSS.Merge  (ctx->Result(), aReShape);
+  else
+    aResult = FSS.Remove (ctx->Result(), aReShape);
+
+  if (aResult != ctx->Result())
+  {
+    ctx->RecordModification (aReShape);
+    ctx->SetResult (aResult);
+  }
+
+  return Standard_True;
+}
+
 /*
 //=======================================================================
 //function :
@@ -735,6 +775,7 @@ void ShapeProcess_OperLibrary::Init ()
   ShapeProcess::RegisterOperator ( "SplitClosedFaces",      new ShapeProcess_UOperator ( splitclosedfaces ) );
   ShapeProcess::RegisterOperator ( "FixWireGaps",           new ShapeProcess_UOperator ( fixwgaps ) );
   ShapeProcess::RegisterOperator ( "FixFaceSize",           new ShapeProcess_UOperator ( fixfacesize ) );
+  ShapeProcess::RegisterOperator ( "DropSmallSolids",       new ShapeProcess_UOperator ( dropsmallsolids ) );
   ShapeProcess::RegisterOperator ( "DropSmallEdges",        new ShapeProcess_UOperator ( mergesmalledges ) );
   ShapeProcess::RegisterOperator ( "FixShape",              new ShapeProcess_UOperator ( fixshape ) );
   ShapeProcess::RegisterOperator ( "SplitClosedEdges",      new ShapeProcess_UOperator ( spltclosededges ) );
diff --git a/tests/heal/drop_small_solids/M1 b/tests/heal/drop_small_solids/M1
new file mode 100644 (file)
index 0000000..f37f499
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd merge0v
+set ref test
diff --git a/tests/heal/drop_small_solids/M2 b/tests/heal/drop_small_solids/M2
new file mode 100644 (file)
index 0000000..0383524
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd merge1v
+set ref merge1
diff --git a/tests/heal/drop_small_solids/M3 b/tests/heal/drop_small_solids/M3
new file mode 100644 (file)
index 0000000..3cc2c7b
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd merge2v
+set ref merge2
diff --git a/tests/heal/drop_small_solids/R1 b/tests/heal/drop_small_solids/R1
new file mode 100644 (file)
index 0000000..178bc1e
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd remove0v
+set ref test
diff --git a/tests/heal/drop_small_solids/R2 b/tests/heal/drop_small_solids/R2
new file mode 100644 (file)
index 0000000..2247921
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd remove1v
+set ref remove1
diff --git a/tests/heal/drop_small_solids/R3 b/tests/heal/drop_small_solids/R3
new file mode 100644 (file)
index 0000000..5d80473
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd remove2v
+set ref remove2
diff --git a/tests/heal/drop_small_solids/R4 b/tests/heal/drop_small_solids/R4
new file mode 100644 (file)
index 0000000..5e5a102
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd remove0w
+set ref test
diff --git a/tests/heal/drop_small_solids/R5 b/tests/heal/drop_small_solids/R5
new file mode 100644 (file)
index 0000000..880b8a4
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd remove1w
+set ref remove1
diff --git a/tests/heal/drop_small_solids/R6 b/tests/heal/drop_small_solids/R6
new file mode 100644 (file)
index 0000000..bc8132d
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd remove2w
+set ref remove2
diff --git a/tests/heal/drop_small_solids/R7 b/tests/heal/drop_small_solids/R7
new file mode 100644 (file)
index 0000000..6751ef0
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd remove1vw
+set ref remove1
diff --git a/tests/heal/drop_small_solids/R8 b/tests/heal/drop_small_solids/R8
new file mode 100644 (file)
index 0000000..765c3bf
--- /dev/null
@@ -0,0 +1,2 @@
+set cmd remove1wv
+set ref remove1
diff --git a/tests/heal/drop_small_solids/end b/tests/heal/drop_small_solids/end
new file mode 100644 (file)
index 0000000..0ffa046
--- /dev/null
@@ -0,0 +1,31 @@
+proc parseprops a {
+  return [regexp -inline {Center of gravity :[
+    ]+X = +([-0-9.+eE]+)[
+    ]+Y = +([-0-9.+eE]+)[
+    ]+Z = +([-0-9.+eE]+)[
+    ]+Matrix of Inertia :[
+    ]+([-0-9.+eE]+)[\t ]+([-0-9.+eE]+)[\t ]+([-0-9.+eE]+)[
+    ]+([-0-9.+eE]+)[\t ]+([-0-9.+eE]+)[\t ]+([-0-9.+eE]+)[
+    ]+([-0-9.+eE]+)[\t ]+([-0-9.+eE]+)[\t ]+([-0-9.+eE]+)} $a]
+}
+
+proc cmpprops {cmd a b} {
+  set aa [parseprops [$cmd $a]]
+  set bb [parseprops [$cmd $b]]
+  for {set i 1} {$i < [llength $aa]} {incr i} {
+    if {[expr abs([lindex $aa $i] - [lindex $bb $i])] > 1e-8} {return 0}
+  }
+  return 1
+}
+
+set env(CSF_resDefaults) [file dirname [locate_data_file res]]
+restore [locate_data_file test.brep] a
+DT_ApplySeq result a res $cmd
+restore [locate_data_file $ref.brep] r
+
+puts [checkshape result]
+if {[statshape result] != [statshape r]} {puts "Error: STATSHAPE"}
+if {![cmpprops vprops result r]} {puts "Error: VPROPS"}
+if {![cmpprops sprops result r]} {puts "Error: SPROPS"}
+if {![cmpprops lprops result r]} {puts "Error: LPROPS"}
+
index c1dbe5f..280a03f 100644 (file)
@@ -16,3 +16,4 @@
 016 split_continuity_standard
 017 surface_to_revolution_advanced
 018 surface_to_revolution_standard
+019 drop_small_solids