Skip to content

import(): weld an AMF object's vertices by exact position - #270

Merged
revarbat merged 1 commit into
mainfrom
fix/amf-hole-weld
Oct 8, 2026
Merged

revarbat merged 1 commit into
mainfrom
fix/amf-hole-weld

Conversation

@revarbat

@revarbat revarbat commented Oct 8, 2026

Copy link
Copy Markdown
Member

An AMF object whose triangles don't share vertex indices -- a triangle soup, or a duplicated vertex list -- imported as an open surface ("N boundary edges, M unwelded vertices") that could not take part in CSG. OpenSCAD 2026.02.01 merges an object's vertices at exactly the same position, so the same file imports closed there, including a solid with a through-hole (genus 1).

Fix

loadAmf now reads each object into its own LoadedMesh, runs the STL importer's existing weldVertices on it, then appends it with the index offset: exact-only and per object, as OpenSCAD does (objects are never welded to each other). weldVertices moves out of mesh_import.cpp's anonymous namespace into mesh_import.hpp. CLAUDE.md's AMF note is corrected (unit is ignored, as in OpenSCAD) and describes the weld.

What OpenSCAD does (from running the binary only)

  • Exact-position duplicates within an object: merged → closed (soup cube/sphere/ring, duplicated list, far from origin; a triangle degenerate after welding is dropped silently).
  • Across objects: no merging.
  • Genuinely open meshes stay open; nothing is patched.
  • Near-coincident vertices: not merged by import (only by OpenSCAD's generic CSG-time repair, ≤ ~3e-7, same for polyhedron() -- a separate item).

Verification

  • vs OpenSCAD: every exact-duplicate case now matches its volume and vertex/face counts; open meshes, near-coincident jitter and closed controls unchanged.
  • Regression: 148 files (30 seeded models exported as STL/OFF/3MF/AMF/OBJ) imported by old and new and re-exported to OFF and 3MF: all byte-identical, identical messages.
  • 3 new gtests in tests/test_import_export.cpp (2 fail on the old code; the third pins the per-object boundary). Full suite: 1471 passed.
  • All corpus runs under a timeout + 1.5 GB RSS watchdog; no runaways.

🤖 Generated with Claude Code

OpenSCAD (checked against 2026.02.01) treats an AMF object's vertices at
exactly the same position as one vertex, so a closed object written as a
triangle soup -- or with its vertex list duplicated, or a solid with a
through-hole whose triangles never share indices -- imports as a closed
solid. We took the indices as written, so every such file came in as an
open surface ("N boundary edges, M unwelded vertices") that could not
take part in CSG.

Each object is now welded with STL's existing exact-match weldVertices
(moved out of mesh_import.cpp's anonymous namespace). The weld is per
object, never across objects, and never merges near-coincident vertices,
matching OpenSCAD's import; its CSG-time repair of near-coincident
vertices is a generic polyhedron/PolySet behaviour, not AMF's.

Genuinely open meshes stay open, as in OpenSCAD. A corpus of 148
STL/OFF/OBJ/3MF/AMF files imports byte-identically before and after; of
30 hand-written and generated AMF cases only the 6 with duplicated
positions changed, each to OpenSCAD's closed result.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
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