Mesh: improve MeshGeomFacet::IntersectWithFacet

This commit is contained in:
wmayer
2021-10-20 19:42:39 +02:00
parent 0086896279
commit 508d113e21
3 changed files with 101 additions and 30 deletions

View File

@@ -1036,6 +1036,15 @@ void MeshGeomFacet::SubSample (float fStep, std::vector<Base::Vector3f> &rclPoin
rclPoints.insert(rclPoints.end(), clPoints.begin(), clPoints.end());
}
bool MeshGeomFacet::IsCoplanar(const MeshGeomFacet &facet) const
{
const float eps = 1e-06f;
const float unit = 0.9995f;
float mult = fabs(this->GetNormal() * facet.GetNormal());
float dist = fabs(DistancePlaneToPoint(facet._aclPoints[0]));
return (mult >= unit) && (dist <= eps);
}
/**
* Fast Triangle-Triangle Intersection Test by Tomas Moeller
* http://www.acm.org/jgt/papers/Moller97/tritri.html
@@ -1068,6 +1077,39 @@ int MeshGeomFacet::IntersectWithFacet (const MeshGeomFacet& rclFacet,
Base::Vector3f& rclPt0,
Base::Vector3f& rclPt1) const
{
// Note: tri_tri_intersect_with_isection() does not return line of
// intersection when triangles are coplanar. See tritritest.h:18 and 658.
if (IsCoplanar(rclFacet)) {
// Since tri_tri_intersect_with_isection may return garbage values try to get
// sensible values with edge/edge intersections
std::vector<Base::Vector3f> intersections;
for (short i=0; i<3; i++) {
MeshGeomEdge edge1 = GetEdge(i);
for (short j=0; j<3; j++) {
MeshGeomEdge edge2 = rclFacet.GetEdge(j);
Base::Vector3f point;
if (edge1.IntersectWithEdge(edge2, point)) {
intersections.push_back(point);
}
}
}
// If triangles overlap there can be more than two intersection points
// In that case use any two of them.
if (intersections.size() >= 2) {
rclPt0 = intersections[0];
rclPt1 = intersections[1];
return 2;
}
else if (intersections.size() == 1) {
rclPt0 = intersections[0];
rclPt1 = intersections[0];
return 1;
}
return 0;
}
float V[3][3], U[3][3];
int coplanar = 0;
float isectpt1[3], isectpt2[3];
@@ -1089,45 +1131,17 @@ int MeshGeomFacet::IntersectWithFacet (const MeshGeomFacet& rclFacet,
rclPt0.x = isectpt1[0]; rclPt0.y = isectpt1[1]; rclPt0.z = isectpt1[2];
rclPt1.x = isectpt2[0]; rclPt1.y = isectpt2[1]; rclPt1.z = isectpt2[2];
// Note: tri_tri_intersect_with_isection() does not return line of
// intersection when triangles are coplanar. See tritritest.h:18 and 658.
if (coplanar) {
// Since tri_tri_intersect_with_isection may return garbage values try to get
// sensible values with edge/edge intersections
std::vector<Base::Vector3f> intersections;
for (short i=0; i<3; i++) {
MeshGeomEdge edge1 = GetEdge(i);
for (short j=0; j<3; j++) {
MeshGeomEdge edge2 = rclFacet.GetEdge(j);
Base::Vector3f point;
if (edge1.IntersectWithEdge(edge2, point)) {
intersections.push_back(point);
}
}
}
// If triangles overlap there can be more than two intersection points
// In that case use any two of them.
if (intersections.size() >= 2) {
rclPt0 = intersections[0];
rclPt1 = intersections[1];
}
else if (intersections.size() == 1) {
rclPt0 = intersections[0];
rclPt1 = intersections[0];
}
return 2;
}
// With extremely acute-angled triangles it may happen that the algorithm
// claims an intersection but the intersection points are far outside the
// model. So, a plausibility check is to verify that the intersection points
// are inside the bounding boxes of both triangles.
Base::BoundBox3f box1 = this->GetBoundBox();
box1.Enlarge(0.001f);
if (!box1.IsInBox(rclPt0) || !box1.IsInBox(rclPt1))
return 0;
Base::BoundBox3f box2 = rclFacet.GetBoundBox();
box2.Enlarge(0.001f);
if (!box2.IsInBox(rclPt0) || !box2.IsInBox(rclPt1))
return 0;

View File

@@ -546,6 +546,10 @@ public:
/** Apply a transformation on the triangle.
*/
void Transform(const Base::Matrix4D&);
/**
* Checks if the two triangles are coplanar.
*/
bool IsCoplanar(const MeshGeomFacet &facet) const;
protected:
Base::Vector3f _clNormal; /**< Normal of the facet. */

View File

@@ -226,6 +226,59 @@ class MeshGeoTestCases(unittest.TestCase):
res=f1.intersect(f2)
self.assertTrue(len(res) == 0)
def testIntersectionOfTransformedMesh(self):
self.planarMesh.append( [0.0,10.0,10.0] )
self.planarMesh.append( [10.0,0.0,10.0] )
self.planarMesh.append( [10.0,10.0,10.0] )
self.planarMesh.append( [6.0,8.0,10.0] )
self.planarMesh.append( [16.0,8.0,10.0] )
self.planarMesh.append( [6.0,18.0,10.0] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
mat = Base.Matrix()
mat.rotateX(1.0)
mat.rotateY(1.0)
mat.rotateZ(1.0)
planarMeshObject.transformGeometry(mat)
f1 = planarMeshObject.Facets[0]
f2 = planarMeshObject.Facets[1]
res=f1.intersect(f2)
self.assertEqual(len(res), 2)
def testIntersectionOfParallelTriangles(self):
self.planarMesh.append( [0.0,10.0,10.0] )
self.planarMesh.append( [10.0,0.0,10.0] )
self.planarMesh.append( [10.0,10.0,10.0] )
self.planarMesh.append( [6.0,8.0,10.1] )
self.planarMesh.append( [16.0,8.0,10.1] )
self.planarMesh.append( [6.0,18.0,10.1] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
mat = Base.Matrix()
mat.rotateX(1.0)
mat.rotateY(1.0)
mat.rotateZ(1.0)
planarMeshObject.transformGeometry(mat)
f1 = planarMeshObject.Facets[0]
f2 = planarMeshObject.Facets[1]
res=f1.intersect(f2)
self.assertTrue(len(res) == 0)
def testIntersectionOnEdge(self):
self.planarMesh.append( [5.0, -1.9371663331985474, 0.49737977981567383] )
self.planarMesh.append( [4.0, -1.9371663331985474, 0.49737977981567383] )
self.planarMesh.append( [5.0, -1.9842294454574585, 0.25066646933555603] )
self.planarMesh.append( [4.6488823890686035, -1.7827962636947632, 0.4577442705631256] )
self.planarMesh.append( [4.524135112762451, -2.0620131492614746, 0.5294350385665894] )
self.planarMesh.append( [4.6488823890686035, -1.8261089324951172, 0.23069120943546295] )
planarMeshObject = Mesh.Mesh(self.planarMesh)
f1 = planarMeshObject.Facets[0]
f2 = planarMeshObject.Facets[1]
res = f1.intersect(f2)
self.assertEqual(len(res), 2)
def testIntersectionCoplanar(self):
self.planarMesh.append( [0.,10.,10.] )
self.planarMesh.append( [10.,0.,10.] )