Skip to content

Booleans still tear on overlapping and rotated operands after the #3341 parity fix #3353

Description

@louistrue

Split out of #3341 so that fix's green is not read as covering this.

#3341 was one specific defect: the parity ray-cast in point_inside used a segment sized to the OTHER operand's extent, so the endpoint could land inside the target, miss the exit crossing, and delete a face. That is fixed, and against an analytic oracle the predicate now agrees on 4,000,000 queries where main was wrong 8947 times.

A separate family of tears survives it.

Measurement

A sweep of 60000 random box pairs, run before and after the #3341 fix, across Difference, Union and Intersection, over touching / disjoint / overlapping / rotated configurations. "Torn" means the boolean result has a non-zero directed-edge imbalance when both operands went in closed.

  • Disjoint pairs tear at 0.16% on main across all three ops and go to exactly 0 with the fix. That family is closed.
  • 96 of 60000 pairs still tear with the fix, concentrated in:
    • overlapping pairs: 0.16 to 0.28%
    • rotated (non-axis-aligned) pairs: 0.08 to 0.38%
    • touching pairs under Union: 0.10%

The fix never creates a tear: its torn set is a strict subset of main's in every cell measured.

Why it is a distinct defect

38 of the 96 were drilled into. 37 of 38 show flipped = 0 — no classification verdict changed between the pre-fix and post-fix predicate. So these tears are not caused by the parity endpoint at all; they were there before #3341 and are untouched by it.

That points at the arrangement or retriangulation stage rather than at classification, but which stage is unproven — nobody has traced one of these to a line yet.

Why it matters

This is the same failure shape as #3341: two closed operands in, a non-watertight shell out. It is the mechanism behind the torn thin IfcCovering layers reported in the #3219 investigation (198 and 662 edges of degree != 2), which survived every cap-gate variant tried and survived setting the flush-cap pad to zero.

ClippingProcessor::validate_mesh (rust/geometry/src/csg/mod.rs) checks only NaN, Inf and index bounds, so none of this is caught at the boundary. Note that enforcing closed-in/closed-out there is measured to be actively harmful (4 suite failures, watertightness up to 8.6x worse, #1007 reopened, +114% volume on 841_house #3698 via the #635 AABB fallback, 114 census regressions) — it should become an observation column, not a gate. Tracked separately.

Suggested start

Take one rotated overlapping pair from the sweep, confirm both operands are closed going in, and bisect the pipeline the way #3341 was bisected: operands in, boolean() out, then consolidate_coplanar. #3341 turned out to be upstream of consolidation; this one may not be.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingrustPull requests that update rust code

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions