From 508d113e2187c39f99d69c3e4694008a570a3a13 Mon Sep 17 00:00:00 2001 From: wmayer Date: Wed, 20 Oct 2021 19:42:39 +0200 Subject: [PATCH] Mesh: improve MeshGeomFacet::IntersectWithFacet --- src/Mod/Mesh/App/Core/Elements.cpp | 74 ++++++++++++++++++------------ src/Mod/Mesh/App/Core/Elements.h | 4 ++ src/Mod/Mesh/App/MeshTestsApp.py | 53 +++++++++++++++++++++ 3 files changed, 101 insertions(+), 30 deletions(-) diff --git a/src/Mod/Mesh/App/Core/Elements.cpp b/src/Mod/Mesh/App/Core/Elements.cpp index 4e8cad49d3..bd434698ce 100644 --- a/src/Mod/Mesh/App/Core/Elements.cpp +++ b/src/Mod/Mesh/App/Core/Elements.cpp @@ -1036,6 +1036,15 @@ void MeshGeomFacet::SubSample (float fStep, std::vector &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 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 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; diff --git a/src/Mod/Mesh/App/Core/Elements.h b/src/Mod/Mesh/App/Core/Elements.h index a0af29e49c..513c4adacb 100644 --- a/src/Mod/Mesh/App/Core/Elements.h +++ b/src/Mod/Mesh/App/Core/Elements.h @@ -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. */ diff --git a/src/Mod/Mesh/App/MeshTestsApp.py b/src/Mod/Mesh/App/MeshTestsApp.py index d467b1e016..4c32fc6570 100644 --- a/src/Mod/Mesh/App/MeshTestsApp.py +++ b/src/Mod/Mesh/App/MeshTestsApp.py @@ -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.] )