diff --git a/src/ShapeFix/ShapeFix.cdl b/src/ShapeFix/ShapeFix.cdl index fa75eb1e5a..759fd41521 100644 --- a/src/ShapeFix/ShapeFix.cdl +++ b/src/ShapeFix/ShapeFix.cdl @@ -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 index 0000000000..6905446079 --- /dev/null +++ b/src/ShapeFix/ShapeFix_FixSmallSolid.cdl @@ -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 index 0000000000..f2b2e25768 --- /dev/null +++ b/src/ShapeFix/ShapeFix_FixSmallSolid.cxx @@ -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 + +#include + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +//======================================================================= +//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; +} diff --git a/src/ShapeProcess/ShapeProcess_OperLibrary.cxx b/src/ShapeProcess/ShapeProcess_OperLibrary.cxx index bf51b35fc0..5fad0ed529 100644 --- a/src/ShapeProcess/ShapeProcess_OperLibrary.cxx +++ b/src/ShapeProcess/ShapeProcess_OperLibrary.cxx @@ -52,6 +52,7 @@ #include #include #include +#include #include #include #include @@ -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 index 0000000000..f37f499efd --- /dev/null +++ b/tests/heal/drop_small_solids/M1 @@ -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 index 0000000000..03835247e4 --- /dev/null +++ b/tests/heal/drop_small_solids/M2 @@ -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 index 0000000000..3cc2c7bea7 --- /dev/null +++ b/tests/heal/drop_small_solids/M3 @@ -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 index 0000000000..178bc1e479 --- /dev/null +++ b/tests/heal/drop_small_solids/R1 @@ -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 index 0000000000..224792141a --- /dev/null +++ b/tests/heal/drop_small_solids/R2 @@ -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 index 0000000000..5d804731e3 --- /dev/null +++ b/tests/heal/drop_small_solids/R3 @@ -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 index 0000000000..5e5a1021ed --- /dev/null +++ b/tests/heal/drop_small_solids/R4 @@ -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 index 0000000000..880b8a4ef0 --- /dev/null +++ b/tests/heal/drop_small_solids/R5 @@ -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 index 0000000000..bc8132d4d7 --- /dev/null +++ b/tests/heal/drop_small_solids/R6 @@ -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 index 0000000000..6751ef033b --- /dev/null +++ b/tests/heal/drop_small_solids/R7 @@ -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 index 0000000000..765c3bf98f --- /dev/null +++ b/tests/heal/drop_small_solids/R8 @@ -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 index 0000000000..0ffa046a00 --- /dev/null +++ b/tests/heal/drop_small_solids/end @@ -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"} + diff --git a/tests/heal/grids.list b/tests/heal/grids.list index c1dbe5f567..280a03fea2 100644 --- a/tests/heal/grids.list +++ b/tests/heal/grids.list @@ -16,3 +16,4 @@ 016 split_continuity_standard 017 surface_to_revolution_advanced 018 surface_to_revolution_standard +019 drop_small_solids