From 468104b1b5a7f4e2009b6993d9488b2d9e1d7820 Mon Sep 17 00:00:00 2001 From: Petru Conduraru Date: Sat, 11 Jul 2026 07:54:38 +0300 Subject: [PATCH] Detect clash for perfectly aligned coplanar-face overlaps (#4594) The manifold clash intersection test (test_intersection in IfcGeomTree.h) witnesses overlap by the penetration depth of each triangle vertex into the other solid, plus edge piercing. For two perfectly centered walls that share their y and z extents and overlap only in x, the penetrating end-cap corner vertices land exactly on the other wall's coincident side faces, so every witness vertex has zero depth and the piercing edges are coplanar with the shared faces. The real overlap is only witnessed at a point strictly interior to B, which nothing sampled, so the clash was missed (nudging either solid off-axis restored detection). Sample the triangle centroid as an extra protrusion witness. For a face-coincident overlap the centroid is strictly interior and yields a depth above tolerance; for merely touching or abutting geometry the centroid stays on the shared surface (depth ~0) and is still discarded by the existing strict "> tolerance" gate, so no false positives are added. Verified on OCC 7.9.2 (python clash tree): the perfectly aligned 50mm overlap goes from 0 to 1 clash, while an off-axis nudge (still 1), an abutting shared-face pair (0) and a 50mm gap (0) are unchanged. On real models a corner-abutting 5 wall building stays 0 and a 614 element facade stays 169 clashes, identical before and after. Co-Authored-By: Claude Opus 4.8 --- src/ifcgeom/kernels/opencascade/IfcGeomTree.h | 23 +++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h index cafd5deaa6..90162081e0 100644 --- a/src/ifcgeom/kernels/opencascade/IfcGeomTree.h +++ b/src/ifcgeom/kernels/opencascade/IfcGeomTree.h @@ -556,6 +556,29 @@ namespace IfcGeom { } } + // A triangle can genuinely lie inside B while every one of its + // vertices sits exactly on a shared boundary face of B (so each + // vertex has zero penetration depth). This is the perfectly + // aligned / coplanar overlap that otherwise goes undetected + // (#4594): two centered walls overlapping on a shared axis, where + // the penetrating end-cap's corners land on B's coincident side + // faces. The triangle centroid is strictly interior in that case, + // so sample it as an extra protrusion witness. Merely touching + // (non-overlapping) geometry keeps a centroid on B's surface, i.e. + // depth ~0, and is still discarded by the "> tolerance" gate below. + { + const gp_Pnt centroid( + (verts_a[tri[0]].X() + verts_a[tri[1]].X() + verts_a[tri[2]].X()) / 3.0, + (verts_a[tri[0]].Y() + verts_a[tri[1]].Y() + verts_a[tri[2]].Y()) / 3.0, + (verts_a[tri[0]].Z() + verts_a[tri[1]].Z() + verts_a[tri[2]].Z()) / 3.0 + ); + if ( ! obb_b.IsOut(centroid) + && is_point_in_shape(centroid, bvh_b, tris_b, verts_b) + && is_point_in_shape(centroid, bvh_b, tris_b, verts_b, true)) { + points_in_b.push_back(centroid); + } + } + // If there are no points in b, this may be a "piercing" triangle. if (points_in_b.empty()) { gp_Vec v1_a_vec(verts_a[tri[0]].XYZ());