Skip to content

Weld boolean-seam vertices to fix non-manifold STL exports - #164

Open
1Richter wants to merge 1 commit into
tracefinity:mainfrom
1Richter:fix/mesh-vertex-merge-tolerance
Open

Weld boolean-seam vertices to fix non-manifold STL exports#164
1Richter wants to merge 1 commit into
tracefinity:mainfrom
1Richter:fix/mesh-vertex-merge-tolerance

Conversation

@1Richter

@1Richter 1Richter commented Aug 3, 2026

Copy link
Copy Markdown
Contributor

Summary

  • manifold3d's boolean ops can leave a seam where two near-identical vertices land ~1e-4mm apart instead of exactly coincident. trimesh's default merge_vertices() tolerance is tighter than that gap, so the later nondegenerate_faces() pass drops the resulting sliver triangle without first welding its vertices into their neighbors, opening a small boundary hole that slicers report as non-manifold geometry.
  • Widen the merge tolerance to digits_vertex=3 (1e-3mm) before dropping degenerate faces. That's far below FDM print resolution, so it can't affect print fidelity.
  • Add a regression test that reproduces the hole deterministically on a plain stacking-lip bin at grid_y=6 — no tool polygons needed, the defect is in the shell/lip geometry itself.

Originally reproduced on a real customer export (grid_x=6, grid_y=9, stacking lip off, real tool cutouts).

Test evidence

  • pytest backend/tests/test_mesh_watertightness.py — 1 passed
  • pytest backend/tests -k "stl or mesh or manifold or split" — 7 passed
  • ruff check backend/app/services/stl_generator_manifold.py backend/tests/test_mesh_watertightness.py — clean
  • Full backend suite: 289 passed. The remaining 10 failures (test_store_load_errors.py permission tests, test_tracer_config.py env-based tracer selection) are pre-existing on main too — Windows chmod semantics and a local FAL_KEY env var, unrelated to this change.

manifold3d's booleans can leave two vertices that should be identical
~1e-4mm apart instead of exactly coincident. trimesh's default
merge_vertices() tolerance is tighter than that gap, so the later
nondegenerate_faces() pass drops the resulting sliver triangle without
first welding its vertices into their neighbors -- opening a small
boundary hole that slicers report as non-manifold geometry.

Reproduced on a real customer export (a split part failed Orca's
manifold check) and, deterministically without any tool data, on a
plain stacking-lip bin at grid_y=6 (252mm) -- below that size the same
config exports clean, so this is a precision issue, not a modeling
bug. merge_vertices(digits_vertex=3) welds anything within 1um,
comfortably below FDM resolution, before the degenerate-face cleanup
runs.
Copilot AI review requested due to automatic review settings August 3, 2026 18:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the STL export pipeline by welding near-duplicate vertices produced by manifold3d boolean seams before removing degenerate faces, preventing tiny boundary holes that slicers flag as non-manifold geometry.

Changes:

  • Increased trimesh vertex merge precision to handle ~1e-4 mm seam gaps before nondegenerate_faces() cleanup.
  • Added a regression test that deterministically reproduces (and now prevents) the boundary-hole case on a plain stacking-lip bin at grid_y=6.

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
backend/app/services/stl_generator_manifold.py Widens trimesh vertex welding (merge_vertices(digits_vertex=3)) prior to degenerate-face removal to avoid seam-induced boundary holes.
backend/tests/test_mesh_watertightness.py Adds a watertightness regression test ensuring the exported bin mesh has no boundary edges and is watertight.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@1Richter

1Richter commented Aug 3, 2026

Copy link
Copy Markdown
Contributor Author

Independently re-verified this before opening the PR:

  • pytest backend/tests/test_mesh_watertightness.py — 1 passed
  • pytest backend/tests -k "stl or mesh or manifold or split" — 7 passed (no regressions in adjacent geometry paths)
  • ruff check backend/app/services/stl_generator_manifold.py backend/tests/test_mesh_watertightness.py — clean
  • Full backend suite on this branch: 289 passed. Compared the same run against main: the same 10 tests fail there too (Windows chmod/permission semantics in test_store_load_errors.py, and a local FAL_KEY env var affecting test_tracer_config.py) — pre-existing, unrelated to this change.
  • Branch merges cleanly against current main (CLEAN/MERGEABLE).

🤖 Verification run 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.

2 participants