Something went wrong. Try again.
3D printing models
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990#!/usr/bin/env python3"""Extract one object's mesh from a .3mf file as a text STL."""from __future__ import annotations
import argparseimport reimport sysimport zipfilefrom pathlib import Path
def parse_mesh(xml_body: str) -> tuple[list[tuple[float, float, float]], list[tuple[int, int, int]]]: verts = [ (float(x), float(y), float(z)) for x, y, z in re.findall( r'<vertex x="([-\d.eE+]+)" y="([-\d.eE+]+)" z="([-\d.eE+]+)"', xml_body, ) ] tris = [ (int(a), int(b), int(c)) for a, b, c in re.findall( r'<triangle v1="(\d+)" v2="(\d+)" v3="(\d+)"', xml_body ) ] return verts, tris
def write_stl( path: Path, verts: list[tuple[float, float, float]], tris: list[tuple[int, int, int]],) -> None: with path.open("w") as f: f.write("solid model\n") for a, b, c in tris: v0, v1, v2 = verts[a], verts[b], verts[c] ux, uy, uz = v1[0] - v0[0], v1[1] - v0[1], v1[2] - v0[2] vx, vy, vz = v2[0] - v0[0], v2[1] - v0[1], v2[2] - v0[2] nx, ny, nz = uy * vz - uz * vy, uz * vx - ux * vz, ux * vy - uy * vx length = (nx * nx + ny * ny + nz * nz) ** 0.5 or 1.0 f.write(f" facet normal {nx / length} {ny / length} {nz / length}\n") f.write(" outer loop\n") for vertex in (v0, v1, v2): f.write(f" vertex {vertex[0]} {vertex[1]} {vertex[2]}\n") f.write(" endloop\n endfacet\n") f.write("endsolid model\n")
def main() -> int: ap = argparse.ArgumentParser(description=__doc__) ap.add_argument("source", type=Path, help="input .3mf file") ap.add_argument("--object-id", required=True, help="object id to extract") ap.add_argument("--output", "-o", type=Path, required=True, help="output .stl path") ap.add_argument( "--model-path", default="3D/3dmodel.model", help="path of the model XML inside the 3mf (default: %(default)s)", ) args = ap.parse_args()
with zipfile.ZipFile(args.source) as z: xml = z.read(args.model_path).decode("utf-8")
pattern = re.compile( rf'<object id="{re.escape(args.object_id)}"[^>]*>(.*?)</object>', re.DOTALL, ) match = pattern.search(xml) if not match: print(f"object id={args.object_id!r} not found", file=sys.stderr) return 1
verts, tris = parse_mesh(match.group(1)) if not verts or not tris: print( f"object id={args.object_id!r} has no mesh (wrapper object?)", file=sys.stderr, ) return 1
args.output.parent.mkdir(parents=True, exist_ok=True) write_stl(args.output, verts, tris) print(f"wrote {args.output} ({len(verts)} verts, {len(tris)} tris)") return 0
if __name__ == "__main__": raise SystemExit(main())