Files
IfcOpenShell/src
Petru Conduraru 493a798283 ifcgeom: detect and repair collinear self-intersections in profiles
IfcGeom::util::wire_intersections only detected self-intersecting
profile boundaries where two edges cross transversally, since
GeomAPI_ExtremaCurveCurve never reports a single well-defined extremum
for edges that are parallel to each other. A profile made of several
disjoint loops chained together through a shared, overlapping return
path (a self-intersection built from collinear overlapping edges
rather than a crossing) went entirely undetected, so the raw invalid
wire reached OCCT's face builder unmodified. OpenCascadeKernel::convert
for a face additionally collapsed any detected self-intersection cycles
down to the single largest one via select_largest, which is correct
for spurious export noise but silently discards real loops when a
lone boundary (no holes) resolves into several disjoint, genuinely
separate parts of the same profile.

Fixes issue #6287: an IfcArbitraryClosedProfileDef boundary shaped like
a comb of four rectangles joined by overlapping zero-width vertical
segments produced one merged, overlong extrusion instead of four
separate ones, because the overlap was invisible to the crossing-only
detector and, once detected in other cases, all but the largest cycle
was thrown away.

wire_utils.cpp adds collinear_overlap_point, which checks whether an
edge endpoint lies strictly inside another parallel edge's span along
their common line, and feeds that point into the existing crossing
based cycle isolation logic unchanged. face.cpp now keeps every
sufficiently large cycle (at least a tenth of the largest one's area)
as its own outer wire when a lone boundary self-intersects, mirroring
how multiple genuine outer boundaries are already turned into a
compound of faces, instead of reducing them all to one.

Verified against the reporter's attached file: the opening's own
comb shaped profile previously produced a single merged solid
spanning the full profile length (72 to 36 triangles, no gaps between
window positions); it now produces four disjoint prisms with the
correct gaps between them. A sweep of test/input (258 files) is
byte identical for 252 files; the remaining differences recover
previously missing subtraction geometry in known regression fixtures
(1015, 336) or are floating point noise below 1e-12 relative
(377, 487), consistent with a pre-existing nondeterminism already
present in the unmodified build on at least one other fixture (423).

Generated with the assistance of an AI coding tool.
2026-07-20 14:32:16 +03:00
..
2026-07-18 22:39:33 +05:00
2026-07-15 19:20:17 +05:00
2026-07-18 22:39:33 +05:00
2026-07-18 22:39:33 +05:00