Fix IndexError in replay_simplification for meshes with unreferenced vertices (#60) - #97
Merged
Merged
Conversation
…vertices (#60) Vertices not referenced by any triangle are dropped by the decimation core, but the pure-array index bookkeeping (compute_indice_mapping) retained them and assigned each an index. That shifted the decimated index of every vertex following an unreferenced one, so indice_mapping pointed past the end of the decimated points and _map_isolated_points (or the final remap) raised: IndexError: index N is out of bounds for axis 0 with size N This is common with meshes carrying UV/texture data (e.g. loaded via trimesh), which frequently contain unreferenced vertices. Strip unreferenced vertices up front so the vertex numbering is dense, run the replay on the compacted mesh, then re-expand indice_mapping to the original vertex count with unreferenced vertices mapped to -1. The collapses are remapped to the compacted numbering; an unreferenced vertex can never be a collapse origin, so a negative entry there means the collapses do not match the mesh and raises a clear ValueError. Meshes whose vertices are all referenced take an unchanged code path. Adds two regression tests: unreferenced vertices at the end of the array, and inserted in the middle (which previously shifted the mapping silently) with the decimated mesh and referenced-vertex mapping asserted identical to the isolated-free mesh. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Summary
Fixes #60 —
replay_simplificationraisedIndexError: index N is out of bounds for axis 0 with size Ninside_map_isolated_pointswhen the input mesh contained vertices not referenced by any triangle.Root cause
The decimation core drops unreferenced vertices, so
_replay.return_points()never includes them. But the pure-array bookkeepingcompute_indice_mappingcomputes ranks over all non-collapsed vertices — including the unreferenced ones — and assigns each an index. Because ranks are assigned in ascending original-index order, an unreferenced vertex shifts the decimated index of every vertex that follows it. The resultingindice_mappingtherefore points one-or-more past the end of the decimated point set, and:indice_mapping = mapping[indice_mapping]remap (or, when an unreferenced vertex is touched by a degenerate edge,_map_isolated_points) indexes out of bounds → the crash.This is common for meshes carrying UV/texture data (the issue reporter loaded via
trimesh), which frequently contain unreferenced vertices.Fix
Strip unreferenced vertices up front so the vertex numbering is dense, replay on the compacted mesh, then re-expand
indice_mappingback to the original vertex count with unreferenced vertices mapped to-1(they are not part of the triangle-only decimated mesh). Collapses are remapped to the compacted numbering; since an unreferenced vertex has no incident edge it can never be a collapse origin, so a negative entry there indicates collapses that don't match the mesh and raises a clearValueError.Meshes whose vertices are all referenced are untouched (same code path as before).
Reproducer (before this PR)
Testing
Two regression tests (offline, no VTK/network): unreferenced vertices at the end of the array, and inserted in the middle (the silent-shift case) — asserting no crash, that unreferenced vertices map to
-1, and that the decimated mesh and the referenced-vertex mapping are bit-for-bit identical to the same mesh without the isolated vertices. Full suite: 41 tests pass locally (PyVista 0.48.4 / VTK 9.6.2).🤖 Generated with Claude Opus 4.8 (Claude Code)