Skip to content

fix: IsInnerShell classifies on the B-rep itself (region nesting) - #694

Closed
brett19 wants to merge 13 commits into
tangency-labs:mainfrom
brett19:fix/region-nesting-inner-shell-trims
Closed

brett19 wants to merge 13 commits into
tangency-labs:mainfrom
brett19:fix/region-nesting-inner-shell-trims

Conversation

@brett19

@brett19 brett19 commented Oct 24, 2026 •

Copy link
Copy Markdown
Collaborator

This follows up the 9 cases #685 parked in known_mismatches.toml. Status: draft. The root cause is found, but the fix is blocked on a larger port (see below).

Root cause

  • topology_traverser::is_inner_shell ran its rays and GetPointsInFace on a b.clone() scratch copy.
  • points_in_face ran CalculateUVDomainFromUVTrimCurves and its iso-line CurveOnClassify on further copies.
  • Upstream's const face queries leave the UV trim curves they create on the B-rep, so C++ exported stored trims that Rust lacked. For brep_p6 two_disjoint_cubes, geom.len was cpp 1385 vs rust 1232.
  • Found by logging every set_uv_trim_curve with its B-rep address: 15 trims landed on the final B-rep and 18 on copies, all of them from is_inner_shell.

What this branch does

  • is_inner_shell, points_in_face and Shell::is_inner_shell take &mut Brep and run on the caller's B-rep.
  • The iso-line classification copies the UV trims, tolerance growth and gap caches back from its CurveOnClassifyCache snapshot.

Results:

  • topology.brep_p6 make_face.json#89..95: geometry and topology now match C++ exactly. Only the Mark2 counter still differs. Upstream IntersectTSBound takes its trimmed-cache branch with SmNewMarkAndLock (SmCurveClass.cpp:16242), while the port walks the loop uses. These 7 cases stay known mismatches with that reason.
  • The skin cases (skin_concentric_loops, skin_primitive_annular), plus creation_p2 gen0201/gen0214, now defer at TrimSrfCache::build_tree_with_face for a face-owned surface. Their known-mismatch entries are removed.
  • topology.shell reaches 911/911 pass locally.

Blocker

  • topology.topology_traverser is green on main. With this branch, 14 of its op-7 (IsInnerShell) cases go from pass to deferred at SmFace handle of a surface's face (topology.face_p2).
  • Why: the scratch copy came from Brep::clone, which drops geometry owners (see fix: B-rep copies keep geometry owners #681). The ray's surface looked free, so an untrimmed cache was built. On the real B-rep, the face-owned surface needs a face-bound trimmed cache, and global_line_intersect_held's RaySurface handles don't bind one.
  • Probes ruled out the copy-backs: neither undoing the UV-domain change nor undoing the snapshot copy-back removes these deferrals.
  • Proposed fix:
    • Give global_line_intersect_held / the IsInnerShell ray world a face-bound trimmed surface cache, as smsurf_GetSurfaceCache builds.
    • Port IntersectTSBound's cached branch with its mark, which needs &mut Kernel.
    • That would clear the traverser deferrals, the skin build_tree_with_face deferral and the brep_p6 Mark2 counter together.
  • fix: B-rep copies keep geometry owners #681 overlap: fix: B-rep copies keep geometry owners #681 plans to make these same library copies keep owners (including is_inner_shell's). That would hit the same deferral, so the two need to be coordinated.

Local checks on 165745d64: fmt, clippy -D warnings, cargo test -p solidcore (2079 lib tests) and wasm all pass.

PARTIAL topology.brep_p6 cases=595 passed=588 failed=0 deferred=0 known_mismatch=7
PASS    topology.shell cases=911 passed=911 failed=0 deferred=0
PARTIAL topology.topology_traverser cases=909 passed=895 failed=0 deferred=14   <- green on main (regression)
PARTIAL topology.face_p2 cases=2692 passed=2596 failed=0 deferred=96
PARTIAL query.face_p2 cases=1344 passed=1326 failed=0 deferred=18
PARTIAL topology.brep_p7 cases=348 passed=289 failed=0 deferred=59
PARTIAL primitive.primitive_creation_p2 cases=328 passed=234 failed=0 deferred=74
PARTIAL sweep.api_surfaces cases=882 passed=881 failed=0 deferred=1

🤖 Generated with Claude Code

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@brett19 brett19 changed the title fix: region nesting disagreement after shell-ray face preparation (IsInnerShell UV trims, ClassifyLoops mark) fix: IsInnerShell classifies on the B-rep itself (region nesting) Oct 24, 2026
brett19 and others added 4 commits October 23, 2026 17:15
IsInnerShell ran its rays and PointsInFace on a copy of the B-rep, and
PointsInFace's UV-domain and curve classification on further copies, so
the UV trim curves upstream's const face queries leave on the B-rep were
dropped. Run them on the caller's B-rep and copy the classification
snapshot's trims and tolerance growth back.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…in its rays

Running IsInnerShell in place fixes the brep_p6 geometry but turns 14
topology.topology_traverser passes into deferrals at the face-owned
trimmed surface cache: the scratch copy used to drop surface owners.
Record the blocker and the proposed follow-up.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
… branch

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
brett19 and others added 8 commits October 23, 2026 18:03
…ntersectTSBound's cached branch

The surface's cache slot now holds its SmTrimSrfCache: smsurf_GetSurfaceCache of a
face surface reuses it (CacheMakeOrValidate), PointClassify reads it
(GetObjectCache), Notify(PRE_EDIT) marks it modified. IntersectTSBound fetches it and
takes the cached leaf-node branch with its context mark (SmNewMarkAndLock, claimed
through atomic context marks).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…und makes missing trims in its cached branch

ComputeUVPoint fetches the face surface's cache (smsurf_GetSurfaceCache) and keeps it
checked out around GlobalPointSolve, whose fast drop classifies on the B-rep when the
cache is trimmed with point testing on. IntersectTSBound's cached branch runs its
traversals itself, so GetOrCreateUVTrimCurve makes a missing trim on the
classification snapshot when the edge use is visited.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…s cleared are kept; scratch copies share the cache slots

IntersectVertices and IntersectEdges clear the face surface's owner while they read
the vertex/face and edge/face gaps, so a trimmed cache that ComputeUVPoint makes then
is a standalone one, and upstream keeps it on the surface (SmCacheMgrTSrf). The
face-unaware smsurf_GetSurfaceCache keeps such a cache too when it is made in an
owner-cleared scope. The classification snapshots, HasSeamProblem's seam objects and
the curve classification's binormal and sector scratch copies stand for the B-rep
itself, so their face surfaces share the B-rep's cache slots
(Brep::clone_sharing_surface_caches).

difftest: intersect.curve_class_p9's ComputeUVPoint fixture attaches the shim's cache
first, as the shim does; topology.brep_p4 seeds the face surfaces' cache states a
file read leaves.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…cs for the kept trimmed caches

The shared import recomputes the cached gaps the C++ export reported. Its
ComputeUVPoint calls now fetch the face surface's trimmed cache, which would build it
with the face (making UV trim curves the C++ B-rep does not have). The refill now runs
as during a Boolean operation and drops the trimmed caches it kept, leaving each
surface's slot as before (topology.brep_p4: 241 -> 302 passes).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…dings and unit notes for the kept trimmed caches

A face cache built while the B-rep is edited has no face data, and the base cache's
GetTree would ask to rebuild it with the face (an Unported dispatch gap): the face
source's own GetTree stands. Found with tangency-labs#694 merged (primitive_creation_p2 gen0201,
gen0214 then pass).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…shell-trims

# Conflicts:
#	crates/difftest/known_mismatches.toml
…cy-labs#697's kept trimmed caches

Merged tangency-labs#697 (face surfaces keep their trimmed caches; IntersectTSBound's cached
branch and its mark). The 7 brep_p6 region-nesting known mismatches now pass and are
removed; the unit is green (595/595). The two skin annulus cases still differ (the cap
comes out as two faces) and stay listed with a findings entry.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@brett19

brett19 commented Oct 24, 2026

Copy link
Copy Markdown
Collaborator Author

@bherbruck, could you tell me why this was closed? Was it because #697 seemed to supersede it? #697 fixed the traverser deferrals that blocked this PR, but this branch still adds the &mut IsInnerShell / PointsInFace route, which makes topology.brep_p6 green (595/595) and clears 7 region-nesting known mismatches. I've reopened it as #714, merged with #697 and the latest main. If there's a reason this direction shouldn't land, let me know and I'll close that one too.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant