Repository navigation
feat(mesh-ops): diagnostic-driven repair_mesh composite op (T-A4) - #378
Merged
Merged
Conversation
repair_mesh diagnoses the mesh, runs only the steps the diagnostic calls for (degenerate faces, non-manifold edges, hole filling without a size limit, face re-orientation), then re-checks, for up to three passes or until a pass makes no progress. A mesh left inside-out is flipped at the end. Each pass is judged on position-merged geometry, exactly as inspect_mesh sees it, so UV seams are not mistaken for holes and a reported success holds once the file is re-inspected. A sound mesh is left alone and no file is written. With fill_holes off, only face-preserving fixes run, since removing faces would open holes. The result reports the before/after topology, the remaining issues, and whether textures were dropped (the output is geometry only). inspect_mesh now flags inside-out meshes, and suggest_fixes proposes repair_mesh, which also makes inconsistent winding fixable. The legacy repair op is unchanged for the mesh-repair workflow node. The generic /optimize/op route now writes its output next to the input under a unique name, like the dedicated edit routes. The agent and MCP server get a repair_mesh tool. Closes #298
The shipped venv installs only api/requirements.txt, which never pulls scipy: trimesh treats it as optional. inspect_mesh, suggest_fixes and repair_mesh need it for connected parts, hole loops and vertex merging, so they failed outside a dev environment, where torch brings it in. repair_mesh re-oriented faces with trimesh.repair.fix_winding, which needs networkx, also undeclared; it now uses pymeshlab, and skips the step for a pass while the mesh is still non-manifold. A guard test runs every mesh-op family with networkx unimportable, including the re-orientation path, and checks scipy stays declared.
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.
Closes #298
Summary
Adds
repair_mesh, a composite op driven by theinspect_meshdiagnostic (T-A2): "repair this mesh" now turns a holed, non-manifold mesh into a watertight, manifold one — checked by re-runninginspect_meshon the output, not just by the repair's own bookkeeping.The existing
repairop could not meet that bar: even with the paramssuggest_fixeschose, it left holes open (size limit), introduced inconsistent winding, and had no way to fix flipped or inside-out faces.This PR also fixes a dependency bug that already affects
inspect_meshondev— see below.How
repair_meshworksEach pass is judged on position-merged geometry, exactly as
inspect_meshsees it — an earlier version judged pymeshlab's raw output and reported success on meshes that still had non-manifold edges once re-inspected.fill_holes: false(for meshes meant to stay open) only runs face-preserving fixes, since removing faces would open holes it can't close.textures_dropped— the output is geometry only.Other changes
inspect_meshnow flags inside-out meshes (is_inside_out, counted againstprintable).suggest_fixesproposesrepair_mesh, so inconsistent winding becomes fixable.POST /optimize/op/{id}route writes its output next to the input under a unique name ({stem}_{op}_{id8}.glb), like the dedicated edit routes, instead ofWorkflows/.repair_meshtool (reports what remains and warns when textures were dropped). MCP:modly_repair_mesh.repairop is unchanged — themesh-repairworkflow node depends on it.Dependency fix (affects
devtoday)The shipped venv installs only
api/requirements.txt(50 packages, verified with a pip dry-run), which does not include scipy — trimesh treats it as optional.inspect_meshandsuggest_fixes(T-A2) need it for connected parts, hole loops and vertex merging, so they fail in the installed app; tests passed only because dev venvs get scipy through torch.scipy>=1.10is now declared inapi/requirements.txt(the requirements hash change re-runs pip once on update).repair_meshno longer usestrimesh.repair.fix_winding(needs networkx, also undeclared); it re-orients with pymeshlab.The pre-push hook caught the networkx dependency: it failed on the system Python, which has no networkx.
Testing
npm test— 275 Python tests (4 skipped), 262 Node tests, all passing; also run on a Python without networkx.repair_meshtests: holed + non-manifold → watertight & manifold, large hole, flipped faces, inside-out, sound mesh untouched,fill_holes: falsenever removes faces, textured input, input untouched, no-triangle file rejected.Known limits
repair); keeping them is a follow-up.