Repository navigation
feat: snap implicit cuts to existing vertices, add does_self_intersect - #25
Merged
lachlangrose merged 1 commit intoSep 28, 2026
Conversation
3 tasks done
lachlangrose
added this pull request to stack #26
September 28, 2026 11:58
lachlangrose
force-pushed
the
fix/implicit-cut-snap-and-diagnostics
branch
from
September 28, 2026 11:59
dbcc111 to
a47e56f
Compare
Follow-on work to the mesh review, sitting between the review follow-ups and the clip fix. - cut_with_implicit_function now snaps a crossing to an existing vertex when it lands within snap_tol (as a fraction of the edge), instead of emitting a sliver an infinitesimal distance from it. A per-edge dedup guard stops the second visit to a shared edge pushing a duplicate crossing vertex, which was tearing the mesh along every seam and compounding over sequential cuts. The snap is recorded per slot (newtris_on_seam), not by writing the isovalue into the shared per-vertex array. The per-vertex form leaks a per-edge fact into every sub-triangle incident to that vertex: a legitimate keep-side sub-triangle then reads as entirely on-seam and an inclusive keep/discard test drops it from BOTH sides, silently deleting kept surface wherever the seam runs through a vertex. The filter now asks whether any original (non-crossing) vertex lies strictly on the keep side, and applies only to the one-sided modes so PRESERVE_INTERSECTION still keeps the whole surface. - does_self_intersect() exposes PMP::does_self_intersect. A self-intersecting surface is outside the domain of the boolean operations, so this is the check to run before handing a mesh to them. - Document the threading contract: most methods release the GIL, so concurrent access to one TriMesh is a data race in C++, not just a wrong answer. corefine additionally mutates its `other` argument, which was undocumented. - perf: convert_to_exact / convert_to_double_mesh use a flat vector remap keyed on the dense Vertex_index instead of std::map, and preallocate to the source's live counts; set_mesh gains an rvalue overload so the converters' temporaries move rather than deep-copy; snapshot_constraint_coords(interior_only) skips border edges the caller is about to re-derive anyway. Tests: the snap partition (both sides sum to the input area, and snapping does not move the cut) and does_self_intersect. 82 passing. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
lachlangrose
force-pushed
the
fix/implicit-cut-snap-and-diagnostics
branch
from
September 28, 2026 12:11
a47e56f to
5ed79bf
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What & why
Follow-on work to the mesh review.
Implicit-cut snapping.
cut_with_implicit_functionnow snaps a crossing onto anexisting vertex when it lands within
snap_tol(as a fraction of the edge) instead ofemitting a sliver an infinitesimal distance from it, and a per-edge dedup guard stops the
second visit to a shared edge pushing a duplicate crossing vertex — that was tearing the
mesh along every seam and compounding over sequential cuts.
The snap is recorded per slot, not by writing the isovalue into the shared per-vertex
array. The per-vertex form leaks a per-edge fact into every sub-triangle incident to that
vertex: a legitimate keep-side sub-triangle then reads as entirely on-seam, and an
inclusive keep/discard test drops it from both sides. Measured on a 2-triangle case, the
per-vertex form kept 0.25 of a correct 0.375 — a third of the retained surface silently
deleted. The filter now asks whether any original (non-crossing) vertex lies strictly on
the keep side, and applies only to the one-sided modes so
PRESERVE_INTERSECTIONstillkeeps everything.
does_self_intersect()exposesPMP::does_self_intersect. A self-intersectingsurface is outside the domain of the boolean operations, so this is the check to run
before handing a mesh to them.
Threading contract documented. Most methods release the GIL, so concurrent access to
one
TriMeshis a data race in C++ — corrupt memory, not merely a wrong answer.corefineadditionally mutates its
otherargument, which was undocumented.perf on the kernel converters: flat vector remap keyed on the dense
Vertex_indexinstead of
std::map, preallocation to the source's live counts, an rvalueset_meshsothe converters' temporaries move rather than deep-copy, and
interior_onlyon theconstraint snapshot to skip border edges the caller re-derives anyway.
How to verify
82 passing. New: the snap partition (both sides sum to the input area; snapping does not
move the cut) and three for
does_self_intersectincluding that it does not mutate.Risk
duplicate-crossing tear used to happen. That is the point of the change; both directions
are covered by tests.
unchanged, only allocation.
does_self_intersectis new public surface. No signatures changed.Checklist
pytestpasses locally🤖 Generated with Claude Code