mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-05-10 01:20:50 +08:00
Modeling - Implement degenerate thin solid detection (#1231)
Refactor FillSameDomainFaces to use parent solid instead of shell for Same-Domain face mapping
This commit is contained in:
@@ -37,6 +37,7 @@
|
||||
#include <TopTools_ShapeMapHasher.hxx>
|
||||
#include <NCollection_IndexedMap.hxx>
|
||||
#include <NCollection_Map.hxx>
|
||||
#include <Precision.hxx>
|
||||
|
||||
static TopAbs_ShapeEnum TypeToExplore(const int theDim);
|
||||
//
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <BOPAlgo_Builder.hxx>
|
||||
|
||||
#include <BOPAlgo_Alerts.hxx>
|
||||
#include <BOPAlgo_BuilderFace.hxx>
|
||||
#include <BOPAlgo_PaveFiller.hxx>
|
||||
@@ -581,6 +582,54 @@ void BOPAlgo_Builder::FillSameDomainFaces(const Message_ProgressRange& theRange)
|
||||
|
||||
occ::handle<NCollection_BaseAllocator> aAllocator = new NCollection_IncAllocator;
|
||||
|
||||
// Two distinct faces of one solid cannot be Same-Domain: that would
|
||||
// imply a zero-thickness interior in a single operand.
|
||||
NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> aFaceToParent(
|
||||
1,
|
||||
aAllocator);
|
||||
{
|
||||
const int aNbSrc = myDS->NbSourceShapes();
|
||||
for (int iSrc = 0; iSrc < aNbSrc; ++iSrc)
|
||||
{
|
||||
const BOPDS_ShapeInfo& aSI = myDS->ShapeInfo(iSrc);
|
||||
if (aSI.ShapeType() != TopAbs_SOLID)
|
||||
continue;
|
||||
const TopoDS_Shape& aSolid = aSI.Shape();
|
||||
for (TopExp_Explorer anExpF(aSolid, TopAbs_FACE); anExpF.More(); anExpF.Next())
|
||||
{
|
||||
const TopoDS_Shape& aF = anExpF.Current();
|
||||
if (!aFaceToParent.IsBound(aF))
|
||||
aFaceToParent.Bind(aF, aSolid);
|
||||
}
|
||||
}
|
||||
NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher> aPropagation(
|
||||
1,
|
||||
aAllocator);
|
||||
for (NCollection_DataMap<TopoDS_Shape,
|
||||
NCollection_List<TopoDS_Shape>,
|
||||
TopTools_ShapeMapHasher>::Iterator anItIm(myImages);
|
||||
anItIm.More();
|
||||
anItIm.Next())
|
||||
{
|
||||
const TopoDS_Shape* pParent = aFaceToParent.Seek(anItIm.Key());
|
||||
if (pParent == nullptr)
|
||||
continue;
|
||||
for (NCollection_List<TopoDS_Shape>::Iterator anItPiece(anItIm.Value()); anItPiece.More();
|
||||
anItPiece.Next())
|
||||
{
|
||||
if (!aFaceToParent.IsBound(anItPiece.Value()))
|
||||
aPropagation.Bind(anItPiece.Value(), *pParent);
|
||||
}
|
||||
}
|
||||
for (NCollection_DataMap<TopoDS_Shape, TopoDS_Shape, TopTools_ShapeMapHasher>::Iterator
|
||||
anItProp(aPropagation);
|
||||
anItProp.More();
|
||||
anItProp.Next())
|
||||
{
|
||||
aFaceToParent.Bind(anItProp.Key(), anItProp.Value());
|
||||
}
|
||||
}
|
||||
|
||||
// Vector to store the indices of faces for future sorting
|
||||
// for making the SD face for the group from the face with
|
||||
// smallest index in Data structure
|
||||
@@ -689,11 +738,15 @@ void BOPAlgo_Builder::FillSameDomainFaces(const Message_ProgressRange& theRange)
|
||||
{
|
||||
const TopoDS_Shape& aF1 = aIt1.Value();
|
||||
bool bCheckPlanar = aMFPlanar.Contains(aF1);
|
||||
const TopoDS_Shape* pParent1 = aFaceToParent.Seek(aF1);
|
||||
|
||||
NCollection_List<TopoDS_Shape>::Iterator aIt2 = aIt1;
|
||||
for (aIt2.Next(); aIt2.More(); aIt2.Next())
|
||||
{
|
||||
const TopoDS_Shape& aF2 = aIt2.Value();
|
||||
const TopoDS_Shape& aF2 = aIt2.Value();
|
||||
const TopoDS_Shape* pParent2 = aFaceToParent.Seek(aF2);
|
||||
if (pParent1 != nullptr && pParent2 != nullptr && pParent1->IsSame(*pParent2))
|
||||
continue;
|
||||
if (bCheckPlanar && aMFPlanar.Contains(aF2))
|
||||
{
|
||||
// Consider planar bounded faces as Same Domain without additional check
|
||||
|
||||
@@ -13,6 +13,9 @@
|
||||
|
||||
#include "BOPTest_Utilities.pxx"
|
||||
|
||||
#include <BRepBndLib.hxx>
|
||||
#include <BRepPrimAPI_MakeHalfSpace.hxx>
|
||||
|
||||
//=================================================================================================
|
||||
// Direct BOP Operations Tests (equivalent to bcut, bfuse, bcommon, btuc commands)
|
||||
//=================================================================================================
|
||||
@@ -182,4 +185,98 @@ TEST_F(BOPAlgo_ComplexOperationsTest, DirectVsTwoStepComparison)
|
||||
|
||||
EXPECT_NEAR(aDirectVolume, aTwoStepVolume, myTolerance)
|
||||
<< "Direct and two-step operations should produce equivalent results";
|
||||
}
|
||||
|
||||
//=================================================================================================
|
||||
// Degenerate thin-tool tests
|
||||
//=================================================================================================
|
||||
|
||||
class BOPAlgo_DegenerateToolTest : public BOPAlgo_TestBase
|
||||
{
|
||||
};
|
||||
|
||||
TEST_F(BOPAlgo_DegenerateToolTest, Cut_AxisAlignedThinTool_NearlyPreservesBoxVolume)
|
||||
{
|
||||
const TopoDS_Shape aBox =
|
||||
BOPTest_Utilities::CreateBox(gp_Pnt(0.0, 0.0, 0.0), 100.0, 100.0, 100.0);
|
||||
const TopoDS_Shape aThin =
|
||||
BOPTest_Utilities::CreateBox(gp_Pnt(-500.0, 25.0, -500.0), 1500.0, 1.0e-6, 1500.0);
|
||||
|
||||
const TopoDS_Shape aRes = PerformDirectBOP(aBox, aThin, BOPAlgo_CUT);
|
||||
const double aBoxVol = BOPTest_Utilities::GetVolume(aBox);
|
||||
const double aOverlapV = 100.0 * 1.0e-6 * 100.0;
|
||||
ASSERT_FALSE(aRes.IsNull());
|
||||
EXPECT_NEAR(BOPTest_Utilities::GetVolume(aRes), aBoxVol - aOverlapV, 1.0e-4);
|
||||
}
|
||||
|
||||
TEST_F(BOPAlgo_DegenerateToolTest, Fuse_AxisAlignedThinTool_AddsNonOverlappingSlice)
|
||||
{
|
||||
const TopoDS_Shape aBox =
|
||||
BOPTest_Utilities::CreateBox(gp_Pnt(0.0, 0.0, 0.0), 100.0, 100.0, 100.0);
|
||||
const TopoDS_Shape aThin =
|
||||
BOPTest_Utilities::CreateBox(gp_Pnt(-500.0, 25.0, -500.0), 1500.0, 1.0e-6, 1500.0);
|
||||
|
||||
const TopoDS_Shape aRes = PerformDirectBOP(aBox, aThin, BOPAlgo_FUSE);
|
||||
const double aBoxVol = BOPTest_Utilities::GetVolume(aBox);
|
||||
const double aThinVol = 1500.0 * 1.0e-6 * 1500.0;
|
||||
const double aOverlapV = 100.0 * 1.0e-6 * 100.0;
|
||||
ASSERT_FALSE(aRes.IsNull());
|
||||
EXPECT_NEAR(BOPTest_Utilities::GetVolume(aRes), aBoxVol + aThinVol - aOverlapV, 1.0e-4);
|
||||
}
|
||||
|
||||
TEST_F(BOPAlgo_DegenerateToolTest, Cut_LegitimateThinSlab_NotTreatedAsEmpty)
|
||||
{
|
||||
const TopoDS_Shape aBox =
|
||||
BOPTest_Utilities::CreateBox(gp_Pnt(0.0, 0.0, 0.0), 100.0, 100.0, 100.0);
|
||||
const TopoDS_Shape aSlab =
|
||||
BOPTest_Utilities::CreateBox(gp_Pnt(0.0, 0.0, 50.0), 100.0, 100.0, 1.0);
|
||||
|
||||
const TopoDS_Shape aRes = PerformDirectBOP(aBox, aSlab, BOPAlgo_CUT);
|
||||
ASSERT_FALSE(aRes.IsNull());
|
||||
EXPECT_NEAR(BOPTest_Utilities::GetVolume(aRes),
|
||||
BOPTest_Utilities::GetVolume(aBox) - BOPTest_Utilities::GetVolume(aSlab),
|
||||
myTolerance);
|
||||
}
|
||||
|
||||
TEST_F(BOPAlgo_DegenerateToolTest, Common_SolidAndPlanarFace_Unaffected)
|
||||
{
|
||||
const TopoDS_Shape aBox =
|
||||
BOPTest_Utilities::CreateBox(gp_Pnt(0.0, 0.0, 0.0), 100.0, 100.0, 100.0);
|
||||
const gp_Pln aPln(gp_Pnt(0.0, 0.0, 50.0), gp_Dir(0.0, 0.0, 1.0));
|
||||
BRepBuilderAPI_MakeFace aFaceMaker(aPln, -200.0, 200.0, -200.0, 200.0);
|
||||
ASSERT_TRUE(aFaceMaker.IsDone());
|
||||
const TopoDS_Shape aFace = aFaceMaker.Face();
|
||||
|
||||
const TopoDS_Shape aRes = PerformDirectBOP(aBox, aFace, BOPAlgo_COMMON);
|
||||
ASSERT_FALSE(aRes.IsNull());
|
||||
EXPECT_NEAR(BOPTest_Utilities::GetSurfaceArea(aRes), 1.0e4, 1.0);
|
||||
}
|
||||
|
||||
TEST_F(BOPAlgo_DegenerateToolTest, Cut_BySemiInfinitePrism_Unaffected)
|
||||
{
|
||||
const TopoDS_Shape aBox = BOPTest_Utilities::CreateBox(gp_Pnt(0.0, -1.0, -1.0), 2.0, 2.0, 2.0);
|
||||
const gp_Pln aPln(gp_Pnt(-0.5, 0.0, 0.0), gp_Dir(1.0, 0.0, 0.0));
|
||||
BRepBuilderAPI_MakeFace aFaceMaker(aPln, -0.5, 0.5, -0.5, 0.5);
|
||||
ASSERT_TRUE(aFaceMaker.IsDone());
|
||||
BRepPrimAPI_MakePrism aPrismMaker(aFaceMaker.Face(), gp_Dir(1.0, 0.0, 0.0), true);
|
||||
ASSERT_TRUE(aPrismMaker.IsDone());
|
||||
|
||||
const TopoDS_Shape aRes = PerformDirectBOP(aBox, aPrismMaker.Shape(), BOPAlgo_CUT);
|
||||
ASSERT_FALSE(aRes.IsNull());
|
||||
EXPECT_GT(BOPTest_Utilities::GetVolume(aRes), 1.0);
|
||||
}
|
||||
|
||||
TEST_F(BOPAlgo_DegenerateToolTest, Common_SolidAndHalfspace_Unaffected)
|
||||
{
|
||||
const TopoDS_Shape aBox =
|
||||
BOPTest_Utilities::CreateBox(gp_Pnt(0.0, 0.0, -30.0), 150.0, 200.0, 200.0);
|
||||
const gp_Pln aPln(gp_Pnt(0.0, 0.0, 0.0), gp_Dir(0.0, 0.0, 1.0));
|
||||
BRepBuilderAPI_MakeFace aFaceMaker(aPln, -250.0, 250.0, -250.0, 250.0);
|
||||
ASSERT_TRUE(aFaceMaker.IsDone());
|
||||
BRepPrimAPI_MakeHalfSpace aHSMaker(aFaceMaker.Face(), gp_Pnt(0.0, 0.0, -100.0));
|
||||
const TopoDS_Shape aHalfSpace = aHSMaker.Solid();
|
||||
|
||||
const TopoDS_Shape aRes = PerformDirectBOP(aBox, aHalfSpace, BOPAlgo_COMMON);
|
||||
ASSERT_FALSE(aRes.IsNull());
|
||||
EXPECT_GT(BOPTest_Utilities::GetVolume(aRes), 1.0);
|
||||
}
|
||||
Reference in New Issue
Block a user