3MF: export, and 3MF/STL import as mesh bodies

Export: ExportCommand/CLI --out/MCP export with .3mf write a 3MF Core package
([Content_Types].xml, _rels/.rels, 3D/3dmodel.model; millimetres), one
mesh object and build item per body, named after it, vertices shared and
welded watertight (T-junctions between faces split), base-material colours
when bodies carry one (STEP colours now ride on bodies). Tessellation as
for STL. File > Export 3MF.

Import: doc.open/drag-drop/CLI/MCP open accept .3mf and .stl; Insert Mesh
(ParaMeshInsertAlignCommand) adds them to a design as a MeshImport feature.
Kernel mesh bodies render, measure exactly, move and export; solid
features refuse them with a clear error. 3MF reading flattens components
and build transforms, converts units, reads colours; sizes, entries,
nesting and element counts are capped.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AS5Tn3xieewUSg3uxrMVdL
This commit is contained in:
bherbruckandClaude Opus 5.5 committed 2026-10-07 21:30:38 +00:00
1 parent 043a542e29
commit ea3dd0ed6e
30 files changed
+1361 -47

No files matched your search

+19
View File
@@ -59,6 +59,25 @@ fn min_edge_radius(m: &Mesh) -> Option<f64> {
/// small radii down to 5e-6). Faces whose fine tessellation disagrees with a coarse one (a
/// meshing failure) use the coarse result.
pub fn measure(b: &Body) -> Result<BodyMeasure> {
if let Some((pos, tris)) = b.triangle_mesh() {
// Exact for a mesh body; topology counts are facets, sides and vertices.
let m = b.tessellate(1.0)?;
let mm = m.measure();
let edges = b.mesh.as_ref().map(|m| m.edge_count()).unwrap_or(0);
let merged =
TopoCounts { faces: tris.len(), edges, vertices: pos.len(), face_types: [("mesh".to_string(), tris.len())].into_iter().collect() };
return Ok(BodyMeasure {
volume: mm.volume,
area: mm.area,
centroid: mm.centroid,
bbox: m.bounds(),
faces: tris.len(),
edges,
vertices: pos.len(),
shells: 1,
merged,
});
}
let size = b.size();
let coarse = b.tessellate((size * 1e-3).max(1e-3))?;
// Chord error relative to a radius sets the volume error: keep it near 3e-4 of the