feat: integrate SimpleCADAPI 2.0.2 CAD workflows

This commit is contained in:
Jerry
2026-08-03 11:17:05 +08:00
parent b5738e9109
commit c3a0f269b7
481 changed files with 110229 additions and 12826 deletions
+48 -11
View File
@@ -21,6 +21,16 @@ import tempfile
from pathlib import Path
from typing import Any
SCRIPT_DIR = Path(__file__).resolve().parent
if str(SCRIPT_DIR) not in sys.path:
sys.path.insert(0, str(SCRIPT_DIR))
from designir_codec import (
DesignIRCodecError,
read_designir,
write_designir,
)
from build123d import (
Align,
Box,
@@ -113,8 +123,8 @@ class DesignIRError(ValueError):
def read_json(path: Path) -> dict[str, Any]:
try:
value = json.loads(path.read_text(encoding="utf-8"))
except (OSError, json.JSONDecodeError) as exc:
value = read_designir(path)
except (OSError, json.JSONDecodeError, DesignIRCodecError) as exc:
raise DesignIRError(f"Cannot read JSON {path}: {exc}") from exc
if not isinstance(value, dict):
raise DesignIRError("DesignIR must be a JSON object")
@@ -122,6 +132,9 @@ def read_json(path: Path) -> dict[str, Any]:
def write_json(path: Path, value: dict[str, Any]) -> None:
if path.name.endswith(".designir.json") and "surface_layer" in value:
write_designir(path, value)
return
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(json.dumps(value, ensure_ascii=False, indent=2) + "\n", encoding="utf-8")
@@ -587,13 +600,26 @@ def build_simplecad_shape(payload: dict[str, Any]) -> tuple[Any, str]:
raise DesignIRError("SimpleCADAPI backend is unavailable") from exc
values = parameter_values(payload)
shape: Any = None
z_min: float | None = None
z_max: float | None = None
with scad.GraphSession() as session:
def semantic_tag(value: object, *, prefix: str = "feature") -> str:
token = re.sub(r"[^a-z0-9]+", ".", str(value).lower()).strip(".")
return f"{prefix}.{token or 'unnamed'}"
graph_id = re.sub(
r"[^a-zA-Z0-9_.-]+",
"_",
str(payload.get("model_id") or payload.get("family") or "designir_model"),
).strip("._-") or "designir_model"
@scad.model(graph_id=graph_id)
def compile_model() -> Any:
shape: Any = None
z_min: float | None = None
z_max: float | None = None
for feature in payload["features"]:
operation = feature["operation"]
axis = feature_axis(payload, feature)
feature_tag = semantic_tag(feature["id"])
if operation in {"extrude_circle", "add_cylinder"}:
radius = resolve_value(
feature["radius"], values, f"{feature['id']}.radius"
@@ -612,11 +638,13 @@ def build_simplecad_shape(payload: dict[str, Any]) -> tuple[Any, str]:
height=height,
bottom_face_center=point,
axis=tuple(axis),
tag_prefix=feature_tag,
result_tag=f"{feature_tag}.primitive",
)
shape = (
tool
if shape is None
else scad.union_rsolid([shape, tool], clean=True)
else scad.union_rsolid(shape, tool, clean=True)
)
z_min = point[2] if z_min is None else min(z_min, point[2])
z_max = (
@@ -649,11 +677,13 @@ def build_simplecad_shape(payload: dict[str, Any]) -> tuple[Any, str]:
height=depth,
depth=height,
bottom_face_center=point,
tag_prefix=feature_tag,
result_tag=f"{feature_tag}.primitive",
)
shape = (
tool
if shape is None
else scad.union_rsolid([shape, tool], clean=True)
else scad.union_rsolid(shape, tool, clean=True)
)
z_min = point[2] if z_min is None else min(z_min, point[2])
z_max = (
@@ -709,17 +739,24 @@ def build_simplecad_shape(payload: dict[str, Any]) -> tuple[Any, str]:
height=cutter_height,
bottom_face_center=(x, y, z_min - 1.0),
axis=(0.0, 0.0, 1.0),
tag_prefix=f"{feature_tag}.tool.item{index + 1}",
result_tag=f"{feature_tag}.tool.item{index + 1}.solid",
)
for x, y in centers
for index, (x, y) in enumerate(centers)
]
shape = scad.cut_rsolid(
shape, cutters, skip_non_intersecting=False
shape, *cutters, skip_non_intersecting=False
)
shape = scad.apply_tag(shape=shape, tag=f"{feature_tag}.result")
print(
f"simplecad grounding {feature['id']}: volume={shape.get_volume():.6f}",
file=sys.stderr,
)
model_json = scad.export_model_json(session=session, indent=2)
return scad.capture_result(value=shape)
result = compile_model()
shape = result.value
model_json = result.model_json
if shape is None or shape.get_volume() <= 0:
raise DesignIRError("DesignIR did not produce a valid SimpleCAD solid")
return shape, model_json