first commit
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
"""Example 15: export an internal cached mesh as OBJ.
|
||||
|
||||
Run from the repository root with:
|
||||
uv run python examples/15_cached_mesh_obj_export.py
|
||||
|
||||
This is a developer-facing example for the mesh-cache groundwork. It
|
||||
intentionally does not call the public STL exporter. Instead it builds a normal
|
||||
SimpleCAD solid, reads the framework's internal cached mesh, and writes a common
|
||||
Wavefront OBJ mesh file from that pure triangle data.
|
||||
|
||||
Application code should not depend on ``simplecadapi._mesh``. Future structural
|
||||
checking APIs will consume the same internal mesh cache without exposing mesh
|
||||
extraction to framework users.
|
||||
"""
|
||||
|
||||
from __future__ import annotations
|
||||
|
||||
from pathlib import Path
|
||||
|
||||
import simplecadapi as scad
|
||||
import simplecadapi._mesh as internal_mesh
|
||||
|
||||
|
||||
OUT_DIR = Path("examples/out/cached_mesh_obj_export")
|
||||
|
||||
|
||||
def build_demo_solid() -> scad.Solid:
|
||||
"""Build a small bracket-like solid using only normal modeling APIs."""
|
||||
|
||||
base = scad.make_box_rsolid(
|
||||
width=34.0,
|
||||
height=20.0,
|
||||
depth=6.0,
|
||||
bottom_face_center=(0.0, 0.0, 0.0),
|
||||
)
|
||||
through_hole = scad.make_cylinder_rsolid(
|
||||
radius=4.0,
|
||||
height=12.0,
|
||||
bottom_face_center=(0.0, 0.0, -3.0),
|
||||
axis=(0.0, 0.0, 1.0),
|
||||
)
|
||||
mount_slot = scad.make_box_rsolid(
|
||||
width=8.0,
|
||||
height=24.0,
|
||||
depth=10.0,
|
||||
bottom_face_center=(10.0, 0.0, -2.0),
|
||||
)
|
||||
boss = scad.make_cylinder_rsolid(
|
||||
radius=7.0,
|
||||
height=5.0,
|
||||
bottom_face_center=(-10.0, 0.0, 6.0),
|
||||
axis=(0.0, 0.0, 1.0),
|
||||
)
|
||||
|
||||
bracket = scad.cut_rsolid(
|
||||
base,
|
||||
through_hole,
|
||||
mount_slot,
|
||||
skip_non_intersecting=False,
|
||||
)
|
||||
bracket = scad.union_rsolid([bracket, boss])
|
||||
return scad.apply_tag(shape=bracket, tag="role.cached_mesh_obj_demo")
|
||||
|
||||
|
||||
def write_cached_mesh_obj(solid: scad.Solid, path: Path) -> internal_mesh.TriMesh:
|
||||
"""Write a Solid's internal cached mesh to Wavefront OBJ."""
|
||||
|
||||
mesh = internal_mesh.cached_mesh(solid)
|
||||
if mesh is None:
|
||||
detail = internal_mesh.mesh_error(solid) or "no internal mesh cache"
|
||||
raise RuntimeError(f"Solid has no cached mesh: {detail}")
|
||||
|
||||
lines = [
|
||||
"# OBJ written from SimpleCAD internal cached mesh",
|
||||
"# This example intentionally bypasses scad.export_stl(...).",
|
||||
]
|
||||
for x, y, z in mesh.vertices:
|
||||
lines.append(f"v {x:.9g} {y:.9g} {z:.9g}")
|
||||
for a, b, c in mesh.triangles:
|
||||
lines.append(f"f {int(a) + 1} {int(b) + 1} {int(c) + 1}")
|
||||
|
||||
path.write_text("\n".join(lines) + "\n", encoding="utf-8")
|
||||
return mesh
|
||||
|
||||
|
||||
def main() -> None:
|
||||
OUT_DIR.mkdir(parents=True, exist_ok=True)
|
||||
solid = build_demo_solid()
|
||||
obj_path = OUT_DIR / "cached_mesh_bracket.obj"
|
||||
mesh = write_cached_mesh_obj(solid=solid, path=obj_path)
|
||||
lower, upper = mesh.bounds
|
||||
|
||||
print("volume", round(solid.get_volume(), 3))
|
||||
print("faces", len(solid.get_faces()))
|
||||
print("mesh", f"vertices={mesh.vertex_count}", f"triangles={mesh.triangle_count}")
|
||||
print("bounds", f"min={tuple(round(v, 3) for v in lower)}", f"max={tuple(round(v, 3) for v in upper)}")
|
||||
print("wrote_obj", obj_path)
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in New Issue
Block a user