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 <noreply@anthropic.com>
CGAL 6.x deleted operator< from Point_d, so std::map<Point_d, ...>
no longer compiles. Adds a custom lexicographic comparator and updates
the three affected maps in snap_halfspaces and snap_halfspaces_2.
Fixes builds with newer GCC/libstdc++ that no longer provide <cstdint>,
<cstring>, <cfloat>, <memory>, <algorithm> etc. transitively. Also
disambiguates visit<> calls in taxonomy.h with the full namespace and
casts the character value in IfcCharacterDecoder to uint32_t to silence
ambiguous overload warnings.
The temporary-offset workaround (#7408, commit bd57cc8735) subtracts the
directrix centroid (`mean`) from the curve points before building the
sweep near the origin, then must add it back to restore the original
location. The restore negated the sign — `Move(-mean)` instead of
`Move(+mean)` — placing the swept solid at -mean (mirrored through the
origin) rather than its true position.
Only triggers for polyline directrixes (`is_polyhedron()`) whose centroid
is more than 100 m from the origin (`mean.norm() > 1e2`), so models
centered near the origin are unaffected. Models that keep absolute site
coordinates (e.g. many Revit/ODA IFC exports) render affected swept
solids — reinforcing bars, pipes — at a mirrored phantom location far
from the rest of the model.
IfcSectionedSurface and IfcSectionedSolidHorizontal both of CrossSectionPositions attributes which are lists of IfcAxis2PlacementLinear. The implementation of each class used its own bespoke mapping of IfcAxis2PlacementLinear, which were identical to each other and slightly different than IfcAxis2PlacementLinear. Now the two sectioned classes use the one and only mapping for IfcAxis2PlacementLinear