from __future__ import annotations from pathlib import Path from typing import Any def geometry_backend_status() -> dict[str, Any]: status = {"ocp": False, "cascadio": False, "available": False, "detail": []} try: import OCP # noqa: F401 status["ocp"] = True status["detail"].append("OCP import OK") except Exception as e: # noqa: BLE001 status["detail"].append(f"OCP unavailable: {e}") try: import cascadio # noqa: F401 status["cascadio"] = True status["detail"].append("cascadio import OK") except Exception as e: # noqa: BLE001 status["detail"].append(f"cascadio unavailable: {e}") status["available"] = bool(status["ocp"] or status["cascadio"]) return status def export_meshes_stub(step_path: Path, meshes_dir: Path, link_names: list[str]) -> dict[str, Any]: """MVP mesh export. Full per-link tessellation needs OCP/pythonocc. Until then we record intended mesh filenames and leave placeholders. """ meshes_dir.mkdir(parents=True, exist_ok=True) status = geometry_backend_status() created: list[str] = [] pending: list[str] = [] if status["cascadio"]: try: import cascadio # Whole-assembly export as a starting point (not per-link). out = meshes_dir / "assembly.glb" # cascadio API: step_to_glb(in, out) in recent versions if hasattr(cascadio, "step_to_glb"): cascadio.step_to_glb(str(step_path), str(out)) created.append(str(out)) else: pending.append("cascadio installed but step_to_glb API not found") except Exception as e: # noqa: BLE001 pending.append(f"cascadio export failed: {e}") for name in link_names: target = meshes_dir / f"{name}.stl" if not target.exists(): # Tiny valid-ish ASCII STL placeholder so packages are non-empty. target.write_text( "solid placeholder\n" " facet normal 0 0 1\n" " outer loop\n" " vertex 0 0 0\n" " vertex 1 0 0\n" " vertex 0 1 0\n" " endloop\n" " endfacet\n" "endsolid placeholder\n", encoding="utf-8", ) created.append(str(target)) pending.append(f"{name}.stl is a placeholder triangle (replace after OCCT tessellation)") return {"backend": status, "created": created, "pending": pending}