Input precision and bounded cutter candidates¶
Issue #3925 exposed two problems that must be distinguished: damaged inputs to the geometry census, and genuine cutter-union regressions. A repair that makes an unre-based census pass can make valid production geometry worse.
Establish the coordinate frame before measuring¶
The loader subtracts a site or detected model origin before converting geometry
to f32. The census previously constructed GeometryRouter::with_units without
that offset. In the public Revit fixture, coordinates near 2.78 million metres
have f32 spacing of 25 cm. Narrow covering faces collapse before a boolean even
starts; no later snap or weld can recover those lost coordinates.
The census now makes the same site-first, detected-origin-second frame choice.
Its migrated reference was generated with that harness on c5da72799, before
3912, not from the repair branch. This preserves an independent comparison¶
while replacing measurements of prematurely rounded geometry. The raw reference changes only on models whose frame changes. The pre-existing corpus floor, coverage, directed-edge, triangulator-invariance and volume gates remain active.
The heavy reference is regenerated by the same procedure with
-- --ignored heavy_fixture --nocapture. Holter is unchanged; the school
model's site frame changes 305 rows and the known torn population becomes 26.
One school row, #406997, carries forward an already-existing re-tessellation
from the dependency base f7872db62: 66 triangles and 6.524184 m³ in the census.
An independent base probe reproduces those values, and IfcOpenShell gives
approximately 6.524177 m³. The repair changes no real-loader mesh in this model.
One additional reference row, S_Office #91291, changes from torn to closed.
That result agrees with the existing canonical loader output. IfcOpenShell
0.8.2 independently gives approximately 0.075697 m³; the census result is
approximately 0.075770 m³. A real-fixture test checks closure and volume. This
local oracle is supporting evidence, not a substitute for CI's pinned engine.
Reproduce the reference migration¶
Use a separate worktree at c5da72799. Copy only this PR's
rust/geometry/tests/triangulation_invariance.rs and
rust/geometry/tests/census_rtc/ into it, and make the manifest fixtures
available. Leave all production Rust at that reference commit. Run:
IFCLITE_CENSUS_BLESS=1 cargo test -p ifc-lite-geometry --release \
--features triangulation-alt --test triangulation_invariance \
watertightness_census_and_triangulator_invariance -- --nocapture
Use a separate Cargo target directory, or clean the workspace crates when
switching worktrees: a stale shared-target binary invalidates this comparison.
The generated reference differs on 272 rows across five models. Compare the
repair branch against that reference with blessing disabled. Only the separately
reviewed S_Office row is then taken from the branch's generated run report;
repaired_office_covering_matches_independent_solid_3925 checks its physical
closure and volume. Do not regenerate the entire reference from branch output.
Preserve accepted production geometry¶
The mutual weld and its shared-corner protection remain unchanged. An earlier experiment disabled that protection for subtraction and chose an unpromoted union before the existing reconciled union. It improved the synthetic union sweep and the old census, but introduced tears and incorrect volumes in a large architecture model. That experiment was discarded.
The opening-union consumer now retains its existing reconciled candidate when it is usable. Only an empty or non-closed union permits one coordinate-preserving candidate, still checked for exact edge closure before subtraction. A budget trip prevents the retry. The reconstructed multi-slab prism path is unchanged. This repairs the CSG wall without changing the accepted large-model cuts.
The roof-chain consumer has a separate requirement: preserve its unpromoted candidate and validate the actual subtraction. A rejected or diagnostically torn cut permits one reconciled candidate. That candidate must satisfy the existing acceptance checks, produce no failure diagnostics, and remove no more volume than the sum of the clean individual trial removals. Invalid trials cannot certify that upper bound. An unsuccessful candidate retains the original result and diagnostics, or the existing sequential path if no original cut was accepted. The accept-gate rejection work in #3922 remains a dependency.
Neither candidate introduces a retry loop or resets the element work budget. These decisions live in shared Rust and apply to native and WASM consumers.
Browser detail settings are a separate control¶
The full-load matrix covers eleven real models in native and browser consumers.
The correctness-only native comparison preserves every mesh except the intended
CSG129 repair. The browser's default low-detail path preserves every model's
geometry digest except two IfcWallStandardCase products in a large architecture
fixture, #235933 and #236415. Both were already non-watertight; neither becomes a
certified solid. The performance-only comparison must use the corrected baseline
rather than treating these correctness changes as performance changes.
Raw browser positions and indices were compared with an independent IfcOpenShell 0.8.2 solid. Its surface area is approximately 19.857750 square metres for each wall. The first wall moves from 19.857307 to 19.857714 square metres; the second moves from 19.719556 to 19.892625. Both are closer to the reference, although the second still has excess surface area. Bounds differ by less than 16 micrometres between the two ifc-lite revisions.
A local diagnostic welds nearby vertices and splits edges at collinear vertices before counting unmatched directed segments. At 100-micrometre tolerance, total unmatched segment length falls from 5.538 to 0.117 metres and from 11.081 to 5.491 metres, respectively. This is a diagnostic, not a closure guarantee: counting raw edges confounds additional T-junctions with larger holes, while signed volume on an open mesh depends on the chosen origin. Neither quantity alone certifies a repair. Both walls still need a separate watertightness fix. The load's CSG failures fall from 629 to 625, with the same 27 affected products and 13 silent no-ops. Private source geometry and raw comparisons remain local.
Published work and its limits¶
- CGAL corefinement distinguishes exact topology from rounded output coordinates. Exact decisions do not certify a mesh after premature coordinate rounding.
- CGAL autorefinement and snap rounding describes bounded repair; it does not guarantee a valid result for every input.
- Mesh Arrangements for Solid Geometry supports shared variadic arrangements rather than repeatedly perturbing a growing pairwise accumulator.
- Interactive and Robust Mesh Booleans depends on input preconditions. Its robustness claim does not cover arbitrary collapsed IFC triangle soup.
- CGAL plane regularization separates angular and positional compatibility. It motivates investigating face-level constraints, but does not establish that an isolated corner rule preserves an entire solid.
These sources inform the investigation; they do not prove this implementation. Real-file comparisons, independent solid measurements, mutation checks and end-to-end loads provide that evidence. A global switch based on any degenerate triangle was also rejected: unrelated invalid geometry must not change how a healthy component's corners are reconciled.