#!/usr/bin/env python3 """Measure mesh files for geometry fingerprints (duplicate detection). Usage: fingerprint.py [ ...] Prints one JSON line per file: {path, fp: {faces, area, volume, extents}} or {path, error}. Multi-object files (e.g. 3MF projects) are measured as one combined mesh. """ import sys import json import trimesh import threemf_stream def measure(path): if path.lower().endswith(".3mf"): # Leave out negative/modifier/support parts, so a project matches the # model it prints (e.g. its STL export). meshes, placements = threemf_stream.load(path) placements = threemf_stream.printable(threemf_stream.read_project(path), placements) stats = threemf_stream.measure(meshes, placements) if not stats["faces"]: raise ValueError("no geometry found") return stats mesh = trimesh.load(path, force="mesh") if mesh is None or len(mesh.faces) == 0: raise ValueError("no geometry found") try: volume = abs(float(mesh.volume)) except Exception: volume = 0.0 return { "faces": int(len(mesh.faces)), "area": float(mesh.area), "volume": volume, "extents": [float(x) for x in mesh.extents], } def main(): for path in sys.argv[1:]: try: out = {"path": path, "fp": measure(path)} except Exception as exc: out = {"path": path, "error": str(exc)[:200]} print(json.dumps(out), flush=True) return 0 if __name__ == "__main__": sys.exit(main())