mirror of
https://github.com/Open-Cascade-SAS/OCCT.git
synced 2026-05-10 09:30:48 +08:00
Modeling - Optimize interference detection in polyhedra (#924)
- Introduced `IntPatch_PolyhedronBVH` to wrap polyhedra as BVH primitive sets - Implemented `IntPatch_BVHTraversal` for efficient dual-tree traversal to find candidate triangle pairs - Refactored `IntPatch_InterferencePolyhedron::Interference()` to use BVH-based detection
This commit is contained in:
@@ -20,6 +20,7 @@ set(OCCT_TKGeomAlgo_GTests_FILES
|
||||
IntCurveSurface_ThePolygonOfHInter_Test.cxx
|
||||
Intf_Tool_Test.cxx
|
||||
IntPatch_Polyhedron_Test.cxx
|
||||
IntPatch_PolyhedronBVH_Test.cxx
|
||||
IntPolyh_Intersection_Test.cxx
|
||||
IntPolyh_Point_Test.cxx
|
||||
IntSurf_LineOn2S_Test.cxx
|
||||
|
||||
@@ -0,0 +1,239 @@
|
||||
// Copyright (c) 2024 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 <gtest/gtest.h>
|
||||
|
||||
#include <Adaptor3d_CurveOnSurface.hxx>
|
||||
#include <GeomAdaptor_Surface.hxx>
|
||||
#include <Geom_SphericalSurface.hxx>
|
||||
#include <Geom_CylindricalSurface.hxx>
|
||||
#include <Geom_Plane.hxx>
|
||||
#include <gp_Ax3.hxx>
|
||||
#include <gp_Sphere.hxx>
|
||||
#include <gp_Cylinder.hxx>
|
||||
#include <gp_Pln.hxx>
|
||||
#include <IntPatch_BVHTraversal.hxx>
|
||||
#include <IntPatch_InterferencePolyhedron.hxx>
|
||||
#include <IntPatch_Polyhedron.hxx>
|
||||
#include <IntPatch_PolyhedronBVH.hxx>
|
||||
#include <IntPatch_PolyhedronTool.hxx>
|
||||
|
||||
// Test fixture for IntPatch_PolyhedronBVH tests
|
||||
class IntPatch_PolyhedronBVHTest : public testing::Test
|
||||
{
|
||||
protected:
|
||||
void SetUp() override
|
||||
{
|
||||
// Create a sphere surface
|
||||
const gp_Sphere aSphere(gp_Ax3(gp_Pnt(0, 0, 0), gp_Dir(0, 0, 1)), 1.0);
|
||||
const occ::handle<Geom_SphericalSurface> aSphereSurf = new Geom_SphericalSurface(aSphere);
|
||||
mySphereAdaptor = new GeomAdaptor_Surface(aSphereSurf);
|
||||
|
||||
// Create a cylinder surface
|
||||
const gp_Cylinder aCyl(gp_Ax3(gp_Pnt(0.5, 0, 0), gp_Dir(0, 0, 1)), 0.8);
|
||||
const occ::handle<Geom_CylindricalSurface> aCylSurf = new Geom_CylindricalSurface(aCyl);
|
||||
myCylAdaptor = new GeomAdaptor_Surface(aCylSurf, 0, 2 * M_PI, -1, 1);
|
||||
}
|
||||
|
||||
occ::handle<GeomAdaptor_Surface> mySphereAdaptor;
|
||||
occ::handle<GeomAdaptor_Surface> myCylAdaptor;
|
||||
};
|
||||
|
||||
// Test that PolyhedronBVH can be constructed and has correct size
|
||||
TEST_F(IntPatch_PolyhedronBVHTest, Construction)
|
||||
{
|
||||
constexpr int aNbU = 10;
|
||||
constexpr int aNbV = 10;
|
||||
|
||||
const IntPatch_Polyhedron aPoly(mySphereAdaptor, aNbU, aNbV);
|
||||
const IntPatch_PolyhedronBVH aBVH(aPoly);
|
||||
|
||||
EXPECT_TRUE(aBVH.IsInitialized());
|
||||
EXPECT_GT(aBVH.Size(), 0);
|
||||
EXPECT_LE(aBVH.Size(), IntPatch_PolyhedronTool::NbTriangles(aPoly));
|
||||
}
|
||||
|
||||
// Test that Box() returns valid bounding boxes
|
||||
TEST_F(IntPatch_PolyhedronBVHTest, Box)
|
||||
{
|
||||
constexpr int aNbU = 5;
|
||||
constexpr int aNbV = 5;
|
||||
|
||||
const IntPatch_Polyhedron aPoly(mySphereAdaptor, aNbU, aNbV);
|
||||
const IntPatch_PolyhedronBVH aBVH(aPoly);
|
||||
|
||||
// Check that all boxes are valid
|
||||
for (int i = 0; i < aBVH.Size(); ++i)
|
||||
{
|
||||
const BVH_Box<double, 3> aBox = aBVH.Box(i);
|
||||
EXPECT_TRUE(aBox.IsValid()) << "Box " << i << " is not valid";
|
||||
}
|
||||
}
|
||||
|
||||
// Test that Center() returns valid centroid coordinates
|
||||
TEST_F(IntPatch_PolyhedronBVHTest, Center)
|
||||
{
|
||||
constexpr int aNbU = 5;
|
||||
const int aNbV = 5;
|
||||
|
||||
const IntPatch_Polyhedron aPoly(mySphereAdaptor, aNbU, aNbV);
|
||||
const IntPatch_PolyhedronBVH aBVH(aPoly);
|
||||
|
||||
// Check that centroids are within the overall bounding box
|
||||
const Bnd_Box& aBounding = IntPatch_PolyhedronTool::Bounding(aPoly);
|
||||
double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
|
||||
aBounding.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
|
||||
|
||||
for (int i = 0; i < aBVH.Size(); ++i)
|
||||
{
|
||||
const double aCx = aBVH.Center(i, 0);
|
||||
const double aCy = aBVH.Center(i, 1);
|
||||
const double aCz = aBVH.Center(i, 2);
|
||||
|
||||
EXPECT_GE(aCx, aXmin - 1e-10) << "Center X of triangle " << i << " is below min";
|
||||
EXPECT_LE(aCx, aXmax + 1e-10) << "Center X of triangle " << i << " is above max";
|
||||
EXPECT_GE(aCy, aYmin - 1e-10) << "Center Y of triangle " << i << " is below min";
|
||||
EXPECT_LE(aCy, aYmax + 1e-10) << "Center Y of triangle " << i << " is above max";
|
||||
EXPECT_GE(aCz, aZmin - 1e-10) << "Center Z of triangle " << i << " is below min";
|
||||
EXPECT_LE(aCz, aZmax + 1e-10) << "Center Z of triangle " << i << " is above max";
|
||||
}
|
||||
}
|
||||
|
||||
// Test that OriginalIndex() returns valid 1-based indices
|
||||
TEST_F(IntPatch_PolyhedronBVHTest, OriginalIndex)
|
||||
{
|
||||
constexpr int aNbU = 5;
|
||||
constexpr int aNbV = 5;
|
||||
|
||||
const IntPatch_Polyhedron aPoly(mySphereAdaptor, aNbU, aNbV);
|
||||
IntPatch_PolyhedronBVH aBVH(aPoly);
|
||||
|
||||
const int aNbTri = aBVH.Size();
|
||||
const int aNbPolyTri = IntPatch_PolyhedronTool::NbTriangles(aPoly);
|
||||
|
||||
// Before BVH build, indices should be sequential
|
||||
for (int i = 0; i < aNbTri; ++i)
|
||||
{
|
||||
const int anOrigIdx = aBVH.OriginalIndex(i);
|
||||
EXPECT_GE(anOrigIdx, 1) << "Original index should be >= 1";
|
||||
EXPECT_LE(anOrigIdx, aNbPolyTri) << "Original index should be <= NbTriangles";
|
||||
}
|
||||
|
||||
// Force BVH build
|
||||
aBVH.BVH();
|
||||
|
||||
// After BVH build, each original index should appear exactly once
|
||||
std::vector<bool> aUsed(aNbPolyTri + 1, false);
|
||||
for (int i = 0; i < aNbTri; ++i)
|
||||
{
|
||||
const int anOrigIdx = aBVH.OriginalIndex(i);
|
||||
EXPECT_FALSE(aUsed[anOrigIdx]) << "Original index " << anOrigIdx << " used more than once";
|
||||
aUsed[anOrigIdx] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Test BVH traversal finds overlapping triangles
|
||||
TEST_F(IntPatch_PolyhedronBVHTest, Traversal)
|
||||
{
|
||||
constexpr int aNbU = 10;
|
||||
constexpr int aNbV = 10;
|
||||
|
||||
const IntPatch_Polyhedron aPoly1(mySphereAdaptor, aNbU, aNbV);
|
||||
const IntPatch_Polyhedron aPoly2(myCylAdaptor, aNbU, aNbV);
|
||||
|
||||
IntPatch_PolyhedronBVH aSet1(aPoly1);
|
||||
IntPatch_PolyhedronBVH aSet2(aPoly2);
|
||||
|
||||
IntPatch_BVHTraversal aTraversal;
|
||||
const int aNbPairs = aTraversal.Perform(aSet1, aSet2, false);
|
||||
|
||||
// The sphere and cylinder should have some overlapping triangles
|
||||
EXPECT_GT(aNbPairs, 0) << "Expected some overlapping triangle pairs";
|
||||
EXPECT_EQ(aNbPairs, static_cast<int>(aTraversal.Pairs().Size()));
|
||||
|
||||
// Verify all pairs have valid indices
|
||||
for (const auto& aPair : aTraversal.Pairs())
|
||||
{
|
||||
EXPECT_GE(aPair.First, 1);
|
||||
EXPECT_LE(aPair.First, IntPatch_PolyhedronTool::NbTriangles(aPoly1));
|
||||
EXPECT_GE(aPair.Second, 1);
|
||||
EXPECT_LE(aPair.Second, IntPatch_PolyhedronTool::NbTriangles(aPoly2));
|
||||
}
|
||||
}
|
||||
|
||||
// Test self-interference mode
|
||||
TEST_F(IntPatch_PolyhedronBVHTest, SelfInterference)
|
||||
{
|
||||
constexpr int aNbU = 5;
|
||||
constexpr int aNbV = 5;
|
||||
|
||||
const IntPatch_Polyhedron aPoly(mySphereAdaptor, aNbU, aNbV);
|
||||
IntPatch_PolyhedronBVH aSet(aPoly);
|
||||
|
||||
IntPatch_BVHTraversal aTraversal;
|
||||
aTraversal.Perform(aSet, aSet, true); // self-interference mode
|
||||
|
||||
// In self-interference mode, First < Second for all pairs
|
||||
for (const auto& aPair : aTraversal.Pairs())
|
||||
{
|
||||
EXPECT_LT(aPair.First, aPair.Second) << "Self-interference should have First < Second";
|
||||
}
|
||||
}
|
||||
|
||||
// Test that IntPatch_InterferencePolyhedron works with BVH
|
||||
TEST_F(IntPatch_PolyhedronBVHTest, InterferencePolyhedron)
|
||||
{
|
||||
constexpr int aNbU = 10;
|
||||
constexpr int aNbV = 10;
|
||||
|
||||
const IntPatch_Polyhedron aPoly1(mySphereAdaptor, aNbU, aNbV);
|
||||
const IntPatch_Polyhedron aPoly2(myCylAdaptor, aNbU, aNbV);
|
||||
|
||||
// Create interference and check it completes without error
|
||||
const IntPatch_InterferencePolyhedron anInterf(aPoly1, aPoly2);
|
||||
|
||||
// The result should have some section points or lines
|
||||
// (exact number depends on geometry, just verify it runs)
|
||||
const int aNbPoints = anInterf.NbSectionPoints();
|
||||
const int aNbLines = anInterf.NbSectionLines();
|
||||
const int aNbZones = anInterf.NbTangentZones();
|
||||
|
||||
// At least some intersection should be found
|
||||
EXPECT_TRUE(aNbPoints > 0 || aNbLines > 0 || aNbZones > 0)
|
||||
<< "Expected some intersection results";
|
||||
}
|
||||
|
||||
// Test with non-overlapping surfaces
|
||||
TEST_F(IntPatch_PolyhedronBVHTest, NoOverlap)
|
||||
{
|
||||
// Create a plane far from the sphere
|
||||
const gp_Pln aPlane(gp_Pnt(10, 10, 10), gp_Dir(1, 0, 0));
|
||||
const occ::handle<Geom_Plane> aPlaneSurf = new Geom_Plane(aPlane);
|
||||
const occ::handle<GeomAdaptor_Surface> aPlaneAdaptor =
|
||||
new GeomAdaptor_Surface(aPlaneSurf, -1, 1, -1, 1);
|
||||
|
||||
const int aNbU = 5;
|
||||
const int aNbV = 5;
|
||||
|
||||
const IntPatch_Polyhedron aPoly1(mySphereAdaptor, aNbU, aNbV);
|
||||
const IntPatch_Polyhedron aPoly2(aPlaneAdaptor, aNbU, aNbV);
|
||||
|
||||
IntPatch_PolyhedronBVH aSet1(aPoly1);
|
||||
IntPatch_PolyhedronBVH aSet2(aPoly2);
|
||||
|
||||
IntPatch_BVHTraversal aTraversal;
|
||||
const int aNbPairs = aTraversal.Perform(aSet1, aSet2, false);
|
||||
|
||||
// Far-away surfaces should have no overlapping boxes
|
||||
EXPECT_EQ(aNbPairs, 0) << "Expected no overlapping triangle pairs for distant surfaces";
|
||||
}
|
||||
@@ -10,6 +10,8 @@ set(OCCT_IntPatch_FILES
|
||||
IntPatch_ArcFunction.cxx
|
||||
IntPatch_ArcFunction.hxx
|
||||
IntPatch_ArcFunction.lxx
|
||||
IntPatch_BVHTraversal.cxx
|
||||
IntPatch_BVHTraversal.hxx
|
||||
IntPatch_CSFunction.cxx
|
||||
IntPatch_CSFunction.hxx
|
||||
IntPatch_CurvIntSurf.hxx
|
||||
@@ -54,6 +56,8 @@ set(OCCT_IntPatch_FILES
|
||||
IntPatch_Polygo.lxx
|
||||
IntPatch_Polyhedron.cxx
|
||||
IntPatch_Polyhedron.hxx
|
||||
IntPatch_PolyhedronBVH.cxx
|
||||
IntPatch_PolyhedronBVH.hxx
|
||||
IntPatch_PolyhedronTool.hxx
|
||||
IntPatch_PolyhedronTool.lxx
|
||||
IntPatch_PrmPrmIntersection.cxx
|
||||
|
||||
@@ -0,0 +1,116 @@
|
||||
// Copyright (c) 2024 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 <IntPatch_BVHTraversal.hxx>
|
||||
|
||||
#include <IntPatch_PolyhedronBVH.hxx>
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
IntPatch_BVHTraversal::IntPatch_BVHTraversal()
|
||||
: BVH_PairTraverse<double, 3>(),
|
||||
mySet1(nullptr),
|
||||
mySet2(nullptr),
|
||||
mySelfInterference(false)
|
||||
{
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
IntPatch_BVHTraversal::~IntPatch_BVHTraversal() {}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
int IntPatch_BVHTraversal::Perform(IntPatch_PolyhedronBVH& theSet1,
|
||||
IntPatch_PolyhedronBVH& theSet2,
|
||||
bool theSelfInterference)
|
||||
{
|
||||
myPairs.Clear();
|
||||
mySet1 = &theSet1;
|
||||
mySet2 = &theSet2;
|
||||
mySelfInterference = theSelfInterference;
|
||||
|
||||
if (!theSet1.IsInitialized() || !theSet2.IsInitialized())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (theSet1.Size() == 0 || theSet2.Size() == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Get BVH trees (builds them if necessary)
|
||||
const opencascade::handle<BVH_Tree<double, 3>>& aBVH1 = theSet1.BVH();
|
||||
const opencascade::handle<BVH_Tree<double, 3>>& aBVH2 = theSet2.BVH();
|
||||
|
||||
if (aBVH1.IsNull() || aBVH2.IsNull())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Perform dual-tree traversal
|
||||
return Select(aBVH1, aBVH2);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
bool IntPatch_BVHTraversal::RejectNode(const BVH_Vec3d& theCMin1,
|
||||
const BVH_Vec3d& theCMax1,
|
||||
const BVH_Vec3d& theCMin2,
|
||||
const BVH_Vec3d& theCMax2,
|
||||
double& /*theMetric*/) const
|
||||
{
|
||||
// AABB overlap test: reject if boxes don't overlap
|
||||
// Two boxes overlap if and only if they overlap on all three axes
|
||||
if (theCMin1.x() > theCMax2.x() || theCMax1.x() < theCMin2.x())
|
||||
{
|
||||
return true; // No overlap on X axis
|
||||
}
|
||||
if (theCMin1.y() > theCMax2.y() || theCMax1.y() < theCMin2.y())
|
||||
{
|
||||
return true; // No overlap on Y axis
|
||||
}
|
||||
if (theCMin1.z() > theCMax2.z() || theCMax1.z() < theCMin2.z())
|
||||
{
|
||||
return true; // No overlap on Z axis
|
||||
}
|
||||
|
||||
return false; // Boxes overlap
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
bool IntPatch_BVHTraversal::Accept(const int theIndex1, const int theIndex2)
|
||||
{
|
||||
if (mySet1 == nullptr || mySet2 == nullptr)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get original 1-based triangle indices
|
||||
const int anOrigIdx1 = mySet1->OriginalIndex(theIndex1);
|
||||
const int anOrigIdx2 = mySet2->OriginalIndex(theIndex2);
|
||||
|
||||
// In self-interference mode, skip pairs where first index >= second index
|
||||
// to avoid testing the same pair twice (and to avoid self-intersection)
|
||||
if (mySelfInterference && anOrigIdx1 >= anOrigIdx2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the pair
|
||||
myPairs.Append(TrianglePair(anOrigIdx1, anOrigIdx2));
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
// Copyright (c) 2024 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.
|
||||
|
||||
#ifndef IntPatch_BVHTraversal_HeaderFile
|
||||
#define IntPatch_BVHTraversal_HeaderFile
|
||||
|
||||
#include <BVH_Traverse.hxx>
|
||||
#include <NCollection_Vector.hxx>
|
||||
|
||||
class IntPatch_PolyhedronBVH;
|
||||
|
||||
//! Performs BVH tree traversal of two polyhedra to find candidate triangle pairs
|
||||
//! for intersection testing. This class implements the BVH_PairTraverse interface
|
||||
//! to efficiently find potentially intersecting triangles using bounding box tests.
|
||||
//!
|
||||
//! The traversal collects pairs of original (1-based) triangle indices that have
|
||||
//! overlapping bounding boxes, which should then be tested for actual geometric
|
||||
//! intersection using IntPatch_InterferencePolyhedron::Intersect().
|
||||
class IntPatch_BVHTraversal : public BVH_PairTraverse<double, 3>
|
||||
{
|
||||
public:
|
||||
//! Pair of triangle indices (both 1-based, original indices in polyhedra).
|
||||
struct TrianglePair
|
||||
{
|
||||
int First; //!< Triangle index in first polyhedron (1-based)
|
||||
int Second; //!< Triangle index in second polyhedron (1-based)
|
||||
|
||||
TrianglePair(int theFirst = 0, int theSecond = 0)
|
||||
: First(theFirst),
|
||||
Second(theSecond)
|
||||
{
|
||||
}
|
||||
};
|
||||
|
||||
public:
|
||||
//! Creates an empty traversal object.
|
||||
Standard_EXPORT IntPatch_BVHTraversal();
|
||||
|
||||
//! Destructor.
|
||||
Standard_EXPORT virtual ~IntPatch_BVHTraversal();
|
||||
|
||||
//! Performs BVH traversal and collects candidate triangle pairs.
|
||||
//! @param[in] theSet1 BVH set for the first polyhedron
|
||||
//! @param[in] theSet2 BVH set for the second polyhedron
|
||||
//! @param[in] theSelfInterference if true, skip pairs where first index >= second index
|
||||
//! (used for self-intersection where we don't want to test same pair twice)
|
||||
//! @return number of collected pairs
|
||||
Standard_EXPORT int Perform(IntPatch_PolyhedronBVH& theSet1,
|
||||
IntPatch_PolyhedronBVH& theSet2,
|
||||
bool theSelfInterference = false);
|
||||
|
||||
//! Returns the collected triangle pairs.
|
||||
const NCollection_Vector<TrianglePair>& Pairs() const { return myPairs; }
|
||||
|
||||
//! Clears the collected pairs.
|
||||
void Clear() { myPairs.Clear(); }
|
||||
|
||||
public: //! @name BVH_PairTraverse interface implementation
|
||||
//! Rejects pair of nodes if their bounding boxes don't overlap.
|
||||
//! @param[in] theCMin1 minimum corner of the first node's bounding box
|
||||
//! @param[in] theCMax1 maximum corner of the first node's bounding box
|
||||
//! @param[in] theCMin2 minimum corner of the second node's bounding box
|
||||
//! @param[in] theCMax2 maximum corner of the second node's bounding box
|
||||
//! @param[out] theMetric unused metric parameter
|
||||
//! @return true if the pair should be rejected (no overlap), false otherwise
|
||||
Standard_EXPORT virtual bool RejectNode(const BVH_Vec3d& theCMin1,
|
||||
const BVH_Vec3d& theCMax1,
|
||||
const BVH_Vec3d& theCMin2,
|
||||
const BVH_Vec3d& theCMax2,
|
||||
double& theMetric) const override;
|
||||
|
||||
//! Accepts a pair of leaf elements and stores their original indices.
|
||||
//! @param[in] theIndex1 0-based index in the first BVH set
|
||||
//! @param[in] theIndex2 0-based index in the second BVH set
|
||||
//! @return true (always accepts the pair)
|
||||
Standard_EXPORT virtual bool Accept(const int theIndex1, const int theIndex2) override;
|
||||
|
||||
private:
|
||||
IntPatch_PolyhedronBVH* mySet1; //!< First BVH set
|
||||
IntPatch_PolyhedronBVH* mySet2; //!< Second BVH set
|
||||
bool mySelfInterference; //!< Self-interference mode flag
|
||||
NCollection_Vector<TrianglePair> myPairs; //!< Collected triangle pairs
|
||||
};
|
||||
|
||||
#endif // IntPatch_BVHTraversal_HeaderFile
|
||||
@@ -14,7 +14,6 @@
|
||||
// Alternatively, this file may be used under the terms of Open CASCADE
|
||||
// commercial license or contractual agreement.
|
||||
|
||||
#include <Bnd_BoundSortBox.hxx>
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <NCollection_Array1.hxx>
|
||||
#include <NCollection_HArray1.hxx>
|
||||
@@ -22,8 +21,10 @@
|
||||
#include <gp_Vec.hxx>
|
||||
#include <gp_XYZ.hxx>
|
||||
#include <Intf.hxx>
|
||||
#include <IntPatch_BVHTraversal.hxx>
|
||||
#include <IntPatch_InterferencePolyhedron.hxx>
|
||||
#include <IntPatch_Polyhedron.hxx>
|
||||
#include <IntPatch_PolyhedronBVH.hxx>
|
||||
#include <IntPatch_PolyhedronTool.hxx>
|
||||
#include <NCollection_LocalArray.hxx>
|
||||
#include <Standard_Integer.hxx>
|
||||
@@ -117,89 +118,22 @@ void IntPatch_InterferencePolyhedron::Perform(const IntPatch_Polyhedron& Objet)
|
||||
|
||||
void IntPatch_InterferencePolyhedron::Interference(const IntPatch_Polyhedron&) {}
|
||||
|
||||
void IntPatch_InterferencePolyhedron::Interference(const IntPatch_Polyhedron& FirstPol,
|
||||
const IntPatch_Polyhedron& SeconPol)
|
||||
void IntPatch_InterferencePolyhedron::Interference(const IntPatch_Polyhedron& theFirstPol,
|
||||
const IntPatch_Polyhedron& theSecondPol)
|
||||
{
|
||||
bool gridOnFirst = true;
|
||||
int NbTrianglesFirstPol = IntPatch_PolyhedronTool::NbTriangles(FirstPol);
|
||||
int NbTrianglesSecondPol = IntPatch_PolyhedronTool::NbTriangles(SeconPol);
|
||||
int iFirst, iSecon;
|
||||
// Build BVH sets for both polyhedra
|
||||
IntPatch_PolyhedronBVH aSet1(theFirstPol);
|
||||
IntPatch_PolyhedronBVH aSet2(theSecondPol);
|
||||
|
||||
//------------------------------------------------------------------------------------------
|
||||
//-- the same number of triangles it is necessary to test better on
|
||||
//-- the size of boxes.
|
||||
//--
|
||||
//-- the second is chosen if nbTri1 > 2*nbTri2 or if VolBoit1 > 2*VolBoit2
|
||||
//--
|
||||
//--if (!SelfIntf && NbTrianglesFirstPol>NbTrianglesSecondPol)
|
||||
//-- gridOnFirst=false;
|
||||
// Find candidate triangle pairs via BVH traversal
|
||||
IntPatch_BVHTraversal aTraversal;
|
||||
aTraversal.Perform(aSet1, aSet2, SelfIntf);
|
||||
|
||||
if (!SelfIntf)
|
||||
// Process each candidate pair
|
||||
const NCollection_Vector<IntPatch_BVHTraversal::TrianglePair>& aPairs = aTraversal.Pairs();
|
||||
for (const auto& aPair : aPairs)
|
||||
{
|
||||
if (NbTrianglesFirstPol > NbTrianglesSecondPol + NbTrianglesSecondPol)
|
||||
gridOnFirst = false;
|
||||
|
||||
double vol1, vol2, Xmin, Ymin, Zmin, Xmax, Ymax, Zmax;
|
||||
IntPatch_PolyhedronTool::Bounding(FirstPol).Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
|
||||
vol1 = (Xmax - Xmin) * (Ymax - Ymin) * (Zmax - Zmin);
|
||||
|
||||
IntPatch_PolyhedronTool::Bounding(SeconPol).Get(Xmin, Ymin, Zmin, Xmax, Ymax, Zmax);
|
||||
vol2 = (Xmax - Xmin) * (Ymax - Ymin) * (Zmax - Zmin);
|
||||
|
||||
if (vol1 > 8.0 * vol2)
|
||||
gridOnFirst = false;
|
||||
}
|
||||
|
||||
if (gridOnFirst)
|
||||
{
|
||||
Bnd_BoundSortBox TheGridFirst;
|
||||
TheGridFirst.Initialize(IntPatch_PolyhedronTool::Bounding(FirstPol),
|
||||
IntPatch_PolyhedronTool::ComponentsBounding(FirstPol));
|
||||
|
||||
for (iSecon = 1; iSecon <= NbTrianglesSecondPol; iSecon++)
|
||||
{
|
||||
|
||||
NCollection_List<int>::Iterator iLoI(
|
||||
TheGridFirst.Compare(IntPatch_PolyhedronTool::ComponentsBounding(SeconPol)->Value(iSecon)));
|
||||
while (iLoI.More())
|
||||
{
|
||||
iFirst = iLoI.Value();
|
||||
if (SelfIntf)
|
||||
{
|
||||
if (iFirst < iSecon)
|
||||
Intersect(iFirst, FirstPol, iSecon, SeconPol);
|
||||
}
|
||||
else
|
||||
Intersect(iFirst, FirstPol, iSecon, SeconPol);
|
||||
iLoI.Next();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
Bnd_BoundSortBox TheGridSecond;
|
||||
TheGridSecond.Initialize(IntPatch_PolyhedronTool::Bounding(SeconPol),
|
||||
IntPatch_PolyhedronTool::ComponentsBounding(SeconPol));
|
||||
|
||||
for (iFirst = 1; iFirst <= NbTrianglesFirstPol; iFirst++)
|
||||
{
|
||||
NCollection_List<int>::Iterator iLoI(TheGridSecond.Compare(
|
||||
IntPatch_PolyhedronTool::ComponentsBounding(FirstPol)->Value(iFirst)));
|
||||
|
||||
while (iLoI.More())
|
||||
{
|
||||
iSecon = iLoI.Value();
|
||||
if (SelfIntf)
|
||||
{
|
||||
if (iFirst < iSecon)
|
||||
Intersect(iFirst, FirstPol, iSecon, SeconPol);
|
||||
}
|
||||
else
|
||||
Intersect(iFirst, FirstPol, iSecon, SeconPol);
|
||||
iLoI.Next();
|
||||
}
|
||||
}
|
||||
Intersect(aPair.First, theFirstPol, aPair.Second, theSecondPol);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,189 @@
|
||||
// Copyright (c) 2024 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 <IntPatch_PolyhedronBVH.hxx>
|
||||
|
||||
#include <Bnd_Box.hxx>
|
||||
#include <IntPatch_Polyhedron.hxx>
|
||||
#include <IntPatch_PolyhedronTool.hxx>
|
||||
#include <gp_Pnt.hxx>
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
IntPatch_PolyhedronBVH::IntPatch_PolyhedronBVH()
|
||||
: BVH_PrimitiveSet<double, 3>(
|
||||
new BVH_LinearBuilder<double, 3>(BVH_Constants_LeafNodeSizeDefault,
|
||||
BVH_Constants_MaxTreeDepth)),
|
||||
myPoly(nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
IntPatch_PolyhedronBVH::IntPatch_PolyhedronBVH(const IntPatch_Polyhedron& thePoly)
|
||||
: BVH_PrimitiveSet<double, 3>(
|
||||
new BVH_LinearBuilder<double, 3>(BVH_Constants_LeafNodeSizeDefault,
|
||||
BVH_Constants_MaxTreeDepth)),
|
||||
myPoly(nullptr)
|
||||
{
|
||||
Init(thePoly);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
IntPatch_PolyhedronBVH::~IntPatch_PolyhedronBVH()
|
||||
{
|
||||
//
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
void IntPatch_PolyhedronBVH::Init(const IntPatch_Polyhedron& thePoly)
|
||||
{
|
||||
myPoly = &thePoly;
|
||||
|
||||
const int aNbTriangles = IntPatch_PolyhedronTool::NbTriangles(thePoly);
|
||||
|
||||
// Filter out degenerate triangles (those with void component bounding boxes)
|
||||
// by only including triangles with valid boxes in the index mapping.
|
||||
// This matches the behavior of the former Bnd_BoundSortBox-based approach,
|
||||
// which never matched void boxes.
|
||||
const occ::handle<NCollection_HArray1<Bnd_Box>>& aCompBnd =
|
||||
IntPatch_PolyhedronTool::ComponentsBounding(thePoly);
|
||||
|
||||
myIndexMap.Clear();
|
||||
for (int anIdx = 1; anIdx <= aNbTriangles; ++anIdx)
|
||||
{
|
||||
if (!aCompBnd->Value(anIdx).IsVoid())
|
||||
{
|
||||
myIndexMap.Append(anIdx); // Store 1-based original index
|
||||
}
|
||||
}
|
||||
|
||||
// Mark as dirty to trigger BVH rebuild
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
void IntPatch_PolyhedronBVH::Clear()
|
||||
{
|
||||
myPoly = nullptr;
|
||||
myIndexMap.Clear();
|
||||
MarkDirty();
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
int IntPatch_PolyhedronBVH::Size() const
|
||||
{
|
||||
if (myPoly == nullptr)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return static_cast<int>(myIndexMap.Size());
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
BVH_Box<double, 3> IntPatch_PolyhedronBVH::Box(const int theIndex) const
|
||||
{
|
||||
BVH_Box<double, 3> aBox;
|
||||
|
||||
if (myPoly == nullptr || theIndex < 0 || theIndex >= Size())
|
||||
{
|
||||
return aBox;
|
||||
}
|
||||
|
||||
// Get original 1-based triangle index
|
||||
const int anOrigIdx = myIndexMap.Value(theIndex);
|
||||
|
||||
// Use pre-computed component bounding boxes from the polyhedron.
|
||||
// These boxes include deflection enlargement, matching the behavior
|
||||
// of the former Bnd_BoundSortBox-based approach. Degenerate triangles
|
||||
// (with void boxes) are already excluded during Init().
|
||||
const occ::handle<NCollection_HArray1<Bnd_Box>>& aCompBnd =
|
||||
IntPatch_PolyhedronTool::ComponentsBounding(*myPoly);
|
||||
const Bnd_Box& aBndBox = aCompBnd->Value(anOrigIdx);
|
||||
|
||||
double aXmin, aYmin, aZmin, aXmax, aYmax, aZmax;
|
||||
aBndBox.Get(aXmin, aYmin, aZmin, aXmax, aYmax, aZmax);
|
||||
|
||||
aBox.Add(BVH_Vec3d(aXmin, aYmin, aZmin));
|
||||
aBox.Add(BVH_Vec3d(aXmax, aYmax, aZmax));
|
||||
|
||||
return aBox;
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
double IntPatch_PolyhedronBVH::Center(const int theIndex, const int theAxis) const
|
||||
{
|
||||
if (myPoly == nullptr || theIndex < 0 || theIndex >= Size())
|
||||
{
|
||||
return 0.0;
|
||||
}
|
||||
|
||||
// Get original 1-based triangle index
|
||||
const int anOrigIdx = myIndexMap.Value(theIndex);
|
||||
|
||||
// Get triangle vertex indices
|
||||
int aP1, aP2, aP3;
|
||||
IntPatch_PolyhedronTool::Triangle(*myPoly, anOrigIdx, aP1, aP2, aP3);
|
||||
|
||||
// Get vertex coordinates
|
||||
const gp_Pnt& aPnt1 = IntPatch_PolyhedronTool::Point(*myPoly, aP1);
|
||||
const gp_Pnt& aPnt2 = IntPatch_PolyhedronTool::Point(*myPoly, aP2);
|
||||
const gp_Pnt& aPnt3 = IntPatch_PolyhedronTool::Point(*myPoly, aP3);
|
||||
|
||||
// Compute centroid coordinate along specified axis
|
||||
switch (theAxis)
|
||||
{
|
||||
case 0:
|
||||
return (aPnt1.X() + aPnt2.X() + aPnt3.X()) / 3.0;
|
||||
case 1:
|
||||
return (aPnt1.Y() + aPnt2.Y() + aPnt3.Y()) / 3.0;
|
||||
case 2:
|
||||
return (aPnt1.Z() + aPnt2.Z() + aPnt3.Z()) / 3.0;
|
||||
default:
|
||||
return 0.0;
|
||||
}
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
void IntPatch_PolyhedronBVH::Swap(const int theIndex1, const int theIndex2)
|
||||
{
|
||||
if (theIndex1 == theIndex2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
// Swap indices in the mapping
|
||||
const int aTmp = myIndexMap.Value(theIndex1);
|
||||
myIndexMap.SetValue(theIndex1, myIndexMap.Value(theIndex2));
|
||||
myIndexMap.SetValue(theIndex2, aTmp);
|
||||
}
|
||||
|
||||
//==================================================================================================
|
||||
|
||||
int IntPatch_PolyhedronBVH::OriginalIndex(const int theIndex) const
|
||||
{
|
||||
if (theIndex < 0 || theIndex >= Size())
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
return myIndexMap.Value(theIndex);
|
||||
}
|
||||
@@ -0,0 +1,85 @@
|
||||
// Copyright (c) 2024 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.
|
||||
|
||||
#ifndef IntPatch_PolyhedronBVH_HeaderFile
|
||||
#define IntPatch_PolyhedronBVH_HeaderFile
|
||||
|
||||
#include <BVH_PrimitiveSet.hxx>
|
||||
#include <BVH_LinearBuilder.hxx>
|
||||
#include <NCollection_Vector.hxx>
|
||||
|
||||
class IntPatch_Polyhedron;
|
||||
|
||||
//! Wraps IntPatch_Polyhedron as a BVH_PrimitiveSet for efficient spatial queries.
|
||||
//! This class provides a BVH (Bounding Volume Hierarchy) representation of a polyhedron's
|
||||
//! triangles, enabling O(log n) spatial queries instead of linear search.
|
||||
//!
|
||||
//! The class stores a reference to the polyhedron (no data copy) and maintains
|
||||
//! an index mapping to track triangle reordering during BVH construction.
|
||||
class IntPatch_PolyhedronBVH : public BVH_PrimitiveSet<double, 3>
|
||||
{
|
||||
public:
|
||||
//! Creates an empty BVH set.
|
||||
Standard_EXPORT IntPatch_PolyhedronBVH();
|
||||
|
||||
//! Creates BVH set from the given polyhedron.
|
||||
//! @param[in] thePoly the polyhedron to wrap (must remain valid during BVH lifetime)
|
||||
Standard_EXPORT IntPatch_PolyhedronBVH(const IntPatch_Polyhedron& thePoly);
|
||||
|
||||
//! Destructor.
|
||||
Standard_EXPORT virtual ~IntPatch_PolyhedronBVH();
|
||||
|
||||
//! Initializes BVH set from the given polyhedron.
|
||||
//! @param[in] thePoly the polyhedron to wrap (must remain valid during BVH lifetime)
|
||||
Standard_EXPORT void Init(const IntPatch_Polyhedron& thePoly);
|
||||
|
||||
//! Clears the BVH set.
|
||||
Standard_EXPORT void Clear();
|
||||
|
||||
public: //! @name BVH_Set interface implementation
|
||||
// Make inherited Box() method visible
|
||||
using BVH_PrimitiveSet<double, 3>::Box;
|
||||
|
||||
//! Returns the total number of triangles.
|
||||
Standard_EXPORT virtual int Size() const override;
|
||||
|
||||
//! Returns AABB of the triangle with the given index.
|
||||
//! @param[in] theIndex 0-based triangle index (after BVH reordering)
|
||||
Standard_EXPORT virtual BVH_Box<double, 3> Box(const int theIndex) const override;
|
||||
|
||||
//! Returns centroid coordinate of the triangle along the given axis.
|
||||
//! @param[in] theIndex 0-based triangle index (after BVH reordering)
|
||||
//! @param[in] theAxis axis index (0=X, 1=Y, 2=Z)
|
||||
Standard_EXPORT virtual double Center(const int theIndex, const int theAxis) const override;
|
||||
|
||||
//! Swaps two triangles in the set (used during BVH construction).
|
||||
//! @param[in] theIndex1 first triangle index
|
||||
//! @param[in] theIndex2 second triangle index
|
||||
Standard_EXPORT virtual void Swap(const int theIndex1, const int theIndex2) override;
|
||||
|
||||
public: //! @name Additional methods
|
||||
//! Returns the original (1-based) triangle index in the polyhedron
|
||||
//! for the given 0-based index after BVH reordering.
|
||||
//! @param[in] theIndex 0-based triangle index (after BVH reordering)
|
||||
//! @return 1-based original triangle index in the polyhedron
|
||||
Standard_EXPORT int OriginalIndex(const int theIndex) const;
|
||||
|
||||
//! Returns true if the BVH set is initialized.
|
||||
bool IsInitialized() const { return myPoly != nullptr; }
|
||||
|
||||
private:
|
||||
const IntPatch_Polyhedron* myPoly; //!< Reference to the wrapped polyhedron
|
||||
NCollection_Vector<int> myIndexMap; //!< Maps current indices to original 1-based indices
|
||||
};
|
||||
|
||||
#endif // IntPatch_PolyhedronBVH_HeaderFile
|
||||
Reference in New Issue
Block a user