mirror of
https://git.dev.opencascade.org/repos/occt.git
synced 2025-04-10 18:51:21 +03:00
0025529: ShapeProcessAPI: introduce DropSmallSolids operator
Implemented DropSmallSolids operator Source code corrected and optimized; tests added tests improved
This commit is contained in:
parent
f05f2e3430
commit
8422b578d7
@ -60,6 +60,8 @@ is
|
|||||||
|
|
||||||
class FixSmallFace;
|
class FixSmallFace;
|
||||||
|
|
||||||
|
class FixSmallSolid;
|
||||||
|
|
||||||
class WireVertex;
|
class WireVertex;
|
||||||
|
|
||||||
class Wireframe;
|
class Wireframe;
|
||||||
|
51
src/ShapeFix/ShapeFix_FixSmallSolid.cdl
Normal file
51
src/ShapeFix/ShapeFix_FixSmallSolid.cdl
Normal file
@ -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;
|
522
src/ShapeFix/ShapeFix_FixSmallSolid.cxx
Normal file
522
src/ShapeFix/ShapeFix_FixSmallSolid.cxx
Normal file
@ -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;
|
||||||
|
}
|
@ -52,6 +52,7 @@
|
|||||||
#include <ShapeFix_Face.hxx>
|
#include <ShapeFix_Face.hxx>
|
||||||
#include <ShapeFix_Wire.hxx>
|
#include <ShapeFix_Wire.hxx>
|
||||||
#include <ShapeFix_FixSmallFace.hxx>
|
#include <ShapeFix_FixSmallFace.hxx>
|
||||||
|
#include <ShapeFix_FixSmallSolid.hxx>
|
||||||
#include <ShapeFix_Wireframe.hxx>
|
#include <ShapeFix_Wireframe.hxx>
|
||||||
#include <ShapeFix.hxx>
|
#include <ShapeFix.hxx>
|
||||||
#include <ShapeFix_SplitCommonVertex.hxx>
|
#include <ShapeFix_SplitCommonVertex.hxx>
|
||||||
@ -512,6 +513,45 @@ static Standard_Boolean fixwgaps (const Handle(ShapeProcess_Context)& context)
|
|||||||
return Standard_True;
|
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 :
|
//function :
|
||||||
@ -735,6 +775,7 @@ void ShapeProcess_OperLibrary::Init ()
|
|||||||
ShapeProcess::RegisterOperator ( "SplitClosedFaces", new ShapeProcess_UOperator ( splitclosedfaces ) );
|
ShapeProcess::RegisterOperator ( "SplitClosedFaces", new ShapeProcess_UOperator ( splitclosedfaces ) );
|
||||||
ShapeProcess::RegisterOperator ( "FixWireGaps", new ShapeProcess_UOperator ( fixwgaps ) );
|
ShapeProcess::RegisterOperator ( "FixWireGaps", new ShapeProcess_UOperator ( fixwgaps ) );
|
||||||
ShapeProcess::RegisterOperator ( "FixFaceSize", new ShapeProcess_UOperator ( fixfacesize ) );
|
ShapeProcess::RegisterOperator ( "FixFaceSize", new ShapeProcess_UOperator ( fixfacesize ) );
|
||||||
|
ShapeProcess::RegisterOperator ( "DropSmallSolids", new ShapeProcess_UOperator ( dropsmallsolids ) );
|
||||||
ShapeProcess::RegisterOperator ( "DropSmallEdges", new ShapeProcess_UOperator ( mergesmalledges ) );
|
ShapeProcess::RegisterOperator ( "DropSmallEdges", new ShapeProcess_UOperator ( mergesmalledges ) );
|
||||||
ShapeProcess::RegisterOperator ( "FixShape", new ShapeProcess_UOperator ( fixshape ) );
|
ShapeProcess::RegisterOperator ( "FixShape", new ShapeProcess_UOperator ( fixshape ) );
|
||||||
ShapeProcess::RegisterOperator ( "SplitClosedEdges", new ShapeProcess_UOperator ( spltclosededges ) );
|
ShapeProcess::RegisterOperator ( "SplitClosedEdges", new ShapeProcess_UOperator ( spltclosededges ) );
|
||||||
|
2
tests/heal/drop_small_solids/M1
Normal file
2
tests/heal/drop_small_solids/M1
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd merge0v
|
||||||
|
set ref test
|
2
tests/heal/drop_small_solids/M2
Normal file
2
tests/heal/drop_small_solids/M2
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd merge1v
|
||||||
|
set ref merge1
|
2
tests/heal/drop_small_solids/M3
Normal file
2
tests/heal/drop_small_solids/M3
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd merge2v
|
||||||
|
set ref merge2
|
2
tests/heal/drop_small_solids/R1
Normal file
2
tests/heal/drop_small_solids/R1
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd remove0v
|
||||||
|
set ref test
|
2
tests/heal/drop_small_solids/R2
Normal file
2
tests/heal/drop_small_solids/R2
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd remove1v
|
||||||
|
set ref remove1
|
2
tests/heal/drop_small_solids/R3
Normal file
2
tests/heal/drop_small_solids/R3
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd remove2v
|
||||||
|
set ref remove2
|
2
tests/heal/drop_small_solids/R4
Normal file
2
tests/heal/drop_small_solids/R4
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd remove0w
|
||||||
|
set ref test
|
2
tests/heal/drop_small_solids/R5
Normal file
2
tests/heal/drop_small_solids/R5
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd remove1w
|
||||||
|
set ref remove1
|
2
tests/heal/drop_small_solids/R6
Normal file
2
tests/heal/drop_small_solids/R6
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd remove2w
|
||||||
|
set ref remove2
|
2
tests/heal/drop_small_solids/R7
Normal file
2
tests/heal/drop_small_solids/R7
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd remove1vw
|
||||||
|
set ref remove1
|
2
tests/heal/drop_small_solids/R8
Normal file
2
tests/heal/drop_small_solids/R8
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
set cmd remove1wv
|
||||||
|
set ref remove1
|
31
tests/heal/drop_small_solids/end
Normal file
31
tests/heal/drop_small_solids/end
Normal file
@ -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"}
|
||||||
|
|
@ -16,3 +16,4 @@
|
|||||||
016 split_continuity_standard
|
016 split_continuity_standard
|
||||||
017 surface_to_revolution_advanced
|
017 surface_to_revolution_advanced
|
||||||
018 surface_to_revolution_standard
|
018 surface_to_revolution_standard
|
||||||
|
019 drop_small_solids
|
||||||
|
Loading…
x
Reference in New Issue
Block a user