726 lines
22 KiB
Python
726 lines
22 KiB
Python
"""Constrained sketch-first modeling with isomorphic SimpleCADAPI calls.
|
|
|
|
Run from the repository root with:
|
|
uv run python examples/08_constrained_sketch.py
|
|
|
|
Generated files:
|
|
examples/out/constrained_sketch.model.json
|
|
examples/out/constrained_sketch.step
|
|
examples/out/constrained_sketch.fcstd
|
|
|
|
When the intent is a sketch/profile, use the sketch APIs. Concrete geometry
|
|
APIs remain for paths, pure geometry, and lowering targets.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
import json
|
|
from pathlib import Path
|
|
|
|
import simplecadapi as scad
|
|
|
|
|
|
OUT = Path("examples/out")
|
|
MODEL_JSON_PATH = OUT / "constrained_sketch.model.json"
|
|
STEP_PATH = OUT / "constrained_sketch.step"
|
|
FCSTD_PATH = OUT / "constrained_sketch.fcstd"
|
|
FREECAD_CMD = Path("/Applications/FreeCAD.app/Contents/Resources/bin/freecadcmd")
|
|
|
|
|
|
def _solve_and_report(name: str, sketch: scad.Sketch) -> None:
|
|
result = scad.inspect_sketch_rsketchresult(
|
|
sketch=sketch,
|
|
require_fully_constrained=True,
|
|
)
|
|
points = sorted(
|
|
(point_id, round(point[0], 3), round(point[1], 3))
|
|
for point_id, point in result.solved_points.items()
|
|
)
|
|
scalars = sorted(
|
|
(key, round(value, 3)) for key, value in result.solved_scalars.items()
|
|
)
|
|
print(
|
|
f"{name}_sketch",
|
|
result.status,
|
|
"dof",
|
|
result.dof,
|
|
"residual",
|
|
f"{result.residual_norm:.2e}",
|
|
"points",
|
|
points[:4],
|
|
"scalars",
|
|
scalars[:2],
|
|
)
|
|
|
|
|
|
@scad.requires_session
|
|
def _promote_face(name: str, sketch: scad.Sketch):
|
|
_solve_and_report(name=name, sketch=sketch)
|
|
return scad.make_face_from_sketch_rface(
|
|
sketch=sketch,
|
|
require_fully_constrained=True,
|
|
)
|
|
|
|
|
|
@scad.requires_session
|
|
def make_rect_profile(name, x0, y0, width, height):
|
|
sketch = scad.make_sketch_rsketch(name=name, plane="XY")
|
|
|
|
sketch = scad.add_point_rsketch(sketch=sketch, point_id="p0", x=x0, y=y0)
|
|
sketch = scad.add_point_rsketch(
|
|
sketch=sketch,
|
|
point_id="p1",
|
|
x=x0 + width,
|
|
y=y0,
|
|
)
|
|
sketch = scad.add_point_rsketch(
|
|
sketch=sketch,
|
|
point_id="p2",
|
|
x=x0 + width,
|
|
y=y0 + height,
|
|
)
|
|
sketch = scad.add_point_rsketch(
|
|
sketch=sketch,
|
|
point_id="p3",
|
|
x=x0,
|
|
y=y0 + height,
|
|
)
|
|
|
|
sketch = scad.add_line_rsketch(
|
|
sketch=sketch,
|
|
entity_id="bottom",
|
|
start="p0",
|
|
end="p1",
|
|
)
|
|
sketch = scad.add_line_rsketch(
|
|
sketch=sketch,
|
|
entity_id="right",
|
|
start="p1",
|
|
end="p2",
|
|
)
|
|
sketch = scad.add_line_rsketch(
|
|
sketch=sketch,
|
|
entity_id="top",
|
|
start="p2",
|
|
end="p3",
|
|
)
|
|
sketch = scad.add_line_rsketch(
|
|
sketch=sketch,
|
|
entity_id="left",
|
|
start="p3",
|
|
end="p0",
|
|
)
|
|
|
|
sketch = scad.constrain_horizontal_rsketch(sketch=sketch, line="bottom")
|
|
sketch = scad.constrain_vertical_rsketch(sketch=sketch, line="right")
|
|
sketch = scad.constrain_parallel_rsketch(
|
|
sketch=sketch,
|
|
a="bottom",
|
|
b="top",
|
|
)
|
|
sketch = scad.constrain_parallel_rsketch(
|
|
sketch=sketch,
|
|
a="left",
|
|
b="right",
|
|
)
|
|
sketch = scad.constrain_perpendicular_rsketch(
|
|
sketch=sketch,
|
|
a="bottom",
|
|
b="right",
|
|
)
|
|
sketch = scad.constrain_equal_length_rsketch(
|
|
sketch=sketch,
|
|
a="bottom",
|
|
b="top",
|
|
)
|
|
sketch = scad.constrain_equal_length_rsketch(
|
|
sketch=sketch,
|
|
a="left",
|
|
b="right",
|
|
)
|
|
sketch = scad.constrain_distance_rsketch(
|
|
sketch=sketch,
|
|
a="p0",
|
|
b="p1",
|
|
value=width,
|
|
)
|
|
sketch = scad.constrain_distance_rsketch(
|
|
sketch=sketch,
|
|
a="p0",
|
|
b="p3",
|
|
value=height,
|
|
)
|
|
sketch = scad.constrain_fix_rsketch(sketch=sketch, target="p0")
|
|
return _promote_face(name=name, sketch=sketch)
|
|
|
|
|
|
@scad.requires_session
|
|
def make_circle_profile(name, center_x, center_y, radius, circle_id):
|
|
sketch = scad.make_sketch_rsketch(name=name, plane="XY")
|
|
sketch = scad.add_point_rsketch(
|
|
sketch=sketch,
|
|
point_id="center",
|
|
x=center_x,
|
|
y=center_y,
|
|
)
|
|
sketch = scad.add_circle_rsketch(
|
|
sketch=sketch,
|
|
entity_id=circle_id,
|
|
center="center",
|
|
radius=radius,
|
|
)
|
|
sketch = scad.constrain_fix_rsketch(sketch=sketch, target="center")
|
|
sketch = scad.constrain_radius_rsketch(
|
|
sketch=sketch,
|
|
circle=circle_id,
|
|
value=radius,
|
|
)
|
|
return _promote_face(name=name, sketch=sketch)
|
|
|
|
|
|
@scad.requires_session
|
|
def make_guided_diamond_profile(name, center_x, center_y, width, height, guide_gap):
|
|
half_w = width / 2.0
|
|
half_h = height / 2.0
|
|
sketch = scad.make_sketch_rsketch(name=name, plane="XY")
|
|
|
|
for point_id, x, y in (
|
|
("center", center_x, center_y),
|
|
("left", center_x - half_w, center_y),
|
|
("top", center_x, center_y + half_h),
|
|
("right", center_x + half_w, center_y),
|
|
("bottom", center_x, center_y - half_h),
|
|
("guide_upper_start", center_x - half_w, center_y + guide_gap),
|
|
("guide_upper_end", center_x, center_y + half_h + guide_gap),
|
|
("guide_lower_start", center_x + half_w, center_y - guide_gap),
|
|
("guide_lower_end", center_x, center_y - half_h - guide_gap),
|
|
):
|
|
sketch = scad.add_point_rsketch(
|
|
sketch=sketch,
|
|
point_id=point_id,
|
|
x=x,
|
|
y=y,
|
|
)
|
|
|
|
for entity_id, start, end, construction in (
|
|
("bottom_left", "left", "bottom", False),
|
|
("right_bottom", "bottom", "right", False),
|
|
("top_right", "right", "top", False),
|
|
("left_top", "top", "left", False),
|
|
("guide_upper", "guide_upper_start", "guide_upper_end", True),
|
|
("guide_lower", "guide_lower_start", "guide_lower_end", True),
|
|
):
|
|
sketch = scad.add_line_rsketch(
|
|
sketch=sketch,
|
|
entity_id=entity_id,
|
|
start=start,
|
|
end=end,
|
|
construction=construction,
|
|
)
|
|
|
|
sketch = scad.constrain_fix_rsketch(sketch=sketch, target="center")
|
|
for function, a, b, value in (
|
|
(scad.constrain_distance_x_rsketch, "left", "center", half_w),
|
|
(scad.constrain_distance_y_rsketch, "left", "center", 0.0),
|
|
(scad.constrain_distance_x_rsketch, "center", "right", half_w),
|
|
(scad.constrain_distance_y_rsketch, "center", "right", 0.0),
|
|
(scad.constrain_distance_x_rsketch, "center", "top", 0.0),
|
|
(scad.constrain_distance_y_rsketch, "center", "top", half_h),
|
|
(scad.constrain_distance_x_rsketch, "bottom", "center", 0.0),
|
|
(scad.constrain_distance_y_rsketch, "bottom", "center", half_h),
|
|
):
|
|
sketch = function(sketch=sketch, a=a, b=b, value=value)
|
|
|
|
for function, a, b in (
|
|
(scad.constrain_parallel_rsketch, "left_top", "right_bottom"),
|
|
(scad.constrain_parallel_rsketch, "top_right", "bottom_left"),
|
|
(scad.constrain_equal_length_rsketch, "left_top", "top_right"),
|
|
(scad.constrain_equal_length_rsketch, "top_right", "right_bottom"),
|
|
(scad.constrain_equal_length_rsketch, "right_bottom", "bottom_left"),
|
|
):
|
|
sketch = function(sketch=sketch, a=a, b=b)
|
|
|
|
for function, a, b, value in (
|
|
(scad.constrain_distance_x_rsketch, "left", "guide_upper_start", 0.0),
|
|
(scad.constrain_distance_y_rsketch, "left", "guide_upper_start", guide_gap),
|
|
(scad.constrain_distance_x_rsketch, "top", "guide_upper_end", 0.0),
|
|
(scad.constrain_distance_y_rsketch, "top", "guide_upper_end", guide_gap),
|
|
(scad.constrain_distance_x_rsketch, "guide_lower_start", "right", 0.0),
|
|
(scad.constrain_distance_y_rsketch, "guide_lower_start", "right", guide_gap),
|
|
(scad.constrain_distance_x_rsketch, "guide_lower_end", "bottom", 0.0),
|
|
(scad.constrain_distance_y_rsketch, "guide_lower_end", "bottom", guide_gap),
|
|
):
|
|
sketch = function(sketch=sketch, a=a, b=b, value=value)
|
|
|
|
for function, a, b in (
|
|
(scad.constrain_parallel_rsketch, "guide_upper", "guide_lower"),
|
|
(scad.constrain_parallel_rsketch, "guide_upper", "right_bottom"),
|
|
(scad.constrain_parallel_rsketch, "guide_lower", "left_top"),
|
|
(scad.constrain_equal_length_rsketch, "guide_upper", "right_bottom"),
|
|
(scad.constrain_equal_length_rsketch, "guide_lower", "left_top"),
|
|
):
|
|
sketch = function(sketch=sketch, a=a, b=b)
|
|
return _promote_face(name=name, sketch=sketch)
|
|
|
|
|
|
@scad.requires_session
|
|
def make_curve_guided_relief_profile(name, center_x, center_y, radius, guide_span):
|
|
sketch = scad.make_sketch_rsketch(name=name, plane="XY")
|
|
|
|
for point_id, x, y in (
|
|
("center", center_x, center_y),
|
|
("rim", center_x + radius, center_y),
|
|
("clearance_center", center_x, center_y),
|
|
("upper_left", center_x - guide_span, center_y + radius),
|
|
("upper_right", center_x + guide_span, center_y + radius),
|
|
("lower_left", center_x - guide_span, center_y - radius),
|
|
("lower_right", center_x + guide_span, center_y - radius),
|
|
):
|
|
sketch = scad.add_point_rsketch(
|
|
sketch=sketch,
|
|
point_id=point_id,
|
|
x=x,
|
|
y=y,
|
|
)
|
|
|
|
sketch = scad.add_circle_rsketch(
|
|
sketch=sketch,
|
|
entity_id="relief",
|
|
center="center",
|
|
radius=radius,
|
|
)
|
|
sketch = scad.add_circle_rsketch(
|
|
sketch=sketch,
|
|
entity_id="clearance",
|
|
center="clearance_center",
|
|
radius=radius,
|
|
construction=True,
|
|
)
|
|
for entity_id, start, end in (
|
|
("radius_probe", "center", "rim"),
|
|
("upper_rail", "upper_left", "upper_right"),
|
|
("lower_rail", "lower_left", "lower_right"),
|
|
):
|
|
sketch = scad.add_line_rsketch(
|
|
sketch=sketch,
|
|
entity_id=entity_id,
|
|
start=start,
|
|
end=end,
|
|
construction=True,
|
|
)
|
|
|
|
sketch = scad.constrain_fix_rsketch(sketch=sketch, target="center")
|
|
sketch = scad.constrain_radius_rsketch(
|
|
sketch=sketch,
|
|
circle="relief",
|
|
value=radius,
|
|
)
|
|
sketch = scad.constrain_point_on_rsketch(
|
|
sketch=sketch,
|
|
point="rim",
|
|
entity="relief",
|
|
)
|
|
sketch = scad.constrain_horizontal_rsketch(
|
|
sketch=sketch,
|
|
line="radius_probe",
|
|
)
|
|
sketch = scad.constrain_length_rsketch(
|
|
sketch=sketch,
|
|
line="radius_probe",
|
|
value=radius,
|
|
)
|
|
|
|
sketch = scad.constrain_concentric_rsketch(
|
|
sketch=sketch,
|
|
a="relief",
|
|
b="clearance",
|
|
)
|
|
sketch = scad.constrain_equal_radius_rsketch(
|
|
sketch=sketch,
|
|
a="relief",
|
|
b="clearance",
|
|
)
|
|
sketch = scad.constrain_horizontal_rsketch(
|
|
sketch=sketch,
|
|
line="upper_rail",
|
|
)
|
|
sketch = scad.constrain_horizontal_rsketch(
|
|
sketch=sketch,
|
|
line="lower_rail",
|
|
)
|
|
sketch = scad.constrain_tangent_rsketch(
|
|
sketch=sketch,
|
|
a="upper_rail",
|
|
b="relief",
|
|
)
|
|
sketch = scad.constrain_tangent_rsketch(
|
|
sketch=sketch,
|
|
a="lower_rail",
|
|
b="relief",
|
|
)
|
|
|
|
for a, b, value in (
|
|
("center", "upper_left", -guide_span),
|
|
("center", "upper_right", guide_span),
|
|
("center", "lower_left", -guide_span),
|
|
("center", "lower_right", guide_span),
|
|
):
|
|
sketch = scad.constrain_distance_x_rsketch(
|
|
sketch=sketch,
|
|
a=a,
|
|
b=b,
|
|
value=value,
|
|
)
|
|
return _promote_face(name=name, sketch=sketch)
|
|
|
|
|
|
@scad.model(graph_id="constrained_sketch")
|
|
def build_model():
|
|
plate_w = scad.var(name="plate_w", default=96.0, comment="plate width")
|
|
plate_h = scad.var(name="plate_h", default=54.0, comment="plate height")
|
|
plate_t = scad.var(name="plate_t", default=6.0, comment="plate thickness")
|
|
boss_r = scad.var(
|
|
name="boss_r",
|
|
default=14.0,
|
|
comment="raised center boss radius",
|
|
)
|
|
boss_h = scad.var(
|
|
name="boss_h",
|
|
default=5.0,
|
|
comment="raised center boss height",
|
|
)
|
|
bore_r = scad.var(name="bore_r", default=5.0, comment="through bore radius")
|
|
mount_r = scad.var(
|
|
name="mount_r",
|
|
default=3.0,
|
|
comment="mounting hole radius",
|
|
)
|
|
margin_x = scad.var(
|
|
name="mount_margin_x",
|
|
default=12.0,
|
|
comment="mounting hole x margin",
|
|
)
|
|
margin_y = scad.var(
|
|
name="mount_margin_y",
|
|
default=9.0,
|
|
comment="mounting hole y margin",
|
|
)
|
|
slot_w = scad.var(name="slot_w", default=34.0, comment="service slot width")
|
|
slot_h = scad.var(name="slot_h", default=8.0, comment="service slot height")
|
|
slot_y = scad.var(
|
|
name="slot_center_y",
|
|
default=16.0,
|
|
comment="service slot center y",
|
|
)
|
|
diamond_w = scad.var(
|
|
name="guided_diamond_w",
|
|
default=14.0,
|
|
comment="guided diamond pocket width",
|
|
)
|
|
diamond_h = scad.var(
|
|
name="guided_diamond_h",
|
|
default=8.0,
|
|
comment="guided diamond pocket height",
|
|
)
|
|
diamond_guide_gap = scad.var(
|
|
name="guided_diamond_guide_gap",
|
|
default=5.0,
|
|
comment="parallel guide rail offset",
|
|
)
|
|
relief_r = scad.var(
|
|
name="curve_relief_r",
|
|
default=4.0,
|
|
comment="curve-guided relief radius",
|
|
)
|
|
relief_guide_span = scad.var(
|
|
name="curve_relief_guide_span",
|
|
default=9.0,
|
|
comment="curve relief construction rail half span",
|
|
)
|
|
|
|
center_x = plate_w / 2.0
|
|
center_y = plate_h / 2.0
|
|
|
|
plate_profile = make_rect_profile(
|
|
name="plate_outline",
|
|
x0=0.0,
|
|
y0=0.0,
|
|
width=plate_w,
|
|
height=plate_h,
|
|
)
|
|
plate_profile = scad.apply_tag(
|
|
shape=plate_profile,
|
|
tag="demo.profile.plate",
|
|
)
|
|
plate = scad.extrude_rsolid(
|
|
profile=plate_profile,
|
|
direction=(0.0, 0.0, 1.0),
|
|
distance=plate_t,
|
|
tag_prefix="constrained_sketch.plate",
|
|
result_tag="part.constrained_sketch.base_plate",
|
|
)
|
|
plate = scad.apply_tag(shape=plate, tag="demo.body.base_plate")
|
|
|
|
boss_profile = make_circle_profile(
|
|
name="center_boss",
|
|
center_x=center_x,
|
|
center_y=center_y,
|
|
radius=boss_r,
|
|
circle_id="boss_outer",
|
|
)
|
|
boss_overlap = 1.0
|
|
boss = scad.extrude_rsolid(
|
|
profile=boss_profile,
|
|
direction=(0.0, 0.0, 1.0),
|
|
distance=boss_h + boss_overlap,
|
|
tag_prefix="constrained_sketch.boss",
|
|
result_tag="part.constrained_sketch.raised_boss",
|
|
)
|
|
boss = scad.translate_shape(
|
|
shape=boss,
|
|
vector=(0.0, 0.0, plate_t - boss_overlap),
|
|
)
|
|
boss = scad.apply_tag(shape=boss, tag="demo.body.raised_boss")
|
|
|
|
body = scad.union_rsolid(plate, boss, glue=False)
|
|
|
|
bore_profile = make_circle_profile(
|
|
name="center_bore",
|
|
center_x=center_x,
|
|
center_y=center_y,
|
|
radius=bore_r,
|
|
circle_id="bore",
|
|
)
|
|
bore_cutter = scad.extrude_rsolid(
|
|
profile=bore_profile,
|
|
direction=(0.0, 0.0, 1.0),
|
|
distance=plate_t + boss_h + 2.0,
|
|
tag_prefix="constrained_sketch.bore.cutter",
|
|
result_tag="tool.constrained_sketch.center_bore",
|
|
)
|
|
bore_cutter = scad.translate_shape(
|
|
shape=bore_cutter,
|
|
vector=(0.0, 0.0, -1.0),
|
|
)
|
|
|
|
slot_profile = make_rect_profile(
|
|
name="service_slot",
|
|
x0=center_x - slot_w / 2.0,
|
|
y0=slot_y - slot_h / 2.0,
|
|
width=slot_w,
|
|
height=slot_h,
|
|
)
|
|
slot_cutter = scad.extrude_rsolid(
|
|
profile=slot_profile,
|
|
direction=(0.0, 0.0, 1.0),
|
|
distance=plate_t + 2.0,
|
|
tag_prefix="constrained_sketch.slot.cutter",
|
|
result_tag="tool.constrained_sketch.service_slot",
|
|
)
|
|
slot_cutter = scad.translate_shape(
|
|
shape=slot_cutter,
|
|
vector=(0.0, 0.0, -1.0),
|
|
)
|
|
|
|
diamond_profile = make_guided_diamond_profile(
|
|
name="guided_diamond_pocket",
|
|
center_x=plate_w - 24.0,
|
|
center_y=plate_h - 18.0,
|
|
width=diamond_w,
|
|
height=diamond_h,
|
|
guide_gap=diamond_guide_gap,
|
|
)
|
|
diamond_cutter = scad.extrude_rsolid(
|
|
profile=diamond_profile,
|
|
direction=(0.0, 0.0, 1.0),
|
|
distance=plate_t + 2.0,
|
|
tag_prefix="constrained_sketch.diamond.cutter",
|
|
result_tag="tool.constrained_sketch.diamond_pocket",
|
|
)
|
|
diamond_cutter = scad.translate_shape(
|
|
shape=diamond_cutter,
|
|
vector=(0.0, 0.0, -1.0),
|
|
)
|
|
|
|
curve_relief_profile = make_curve_guided_relief_profile(
|
|
name="curve_guided_relief",
|
|
center_x=plate_w / 3.0,
|
|
center_y=plate_h - 12.0,
|
|
radius=relief_r,
|
|
guide_span=relief_guide_span,
|
|
)
|
|
curve_relief_cutter = scad.extrude_rsolid(
|
|
profile=curve_relief_profile,
|
|
direction=(0.0, 0.0, 1.0),
|
|
distance=plate_t + 2.0,
|
|
tag_prefix="constrained_sketch.curve_relief.cutter",
|
|
result_tag="tool.constrained_sketch.curve_relief",
|
|
)
|
|
curve_relief_cutter = scad.translate_shape(
|
|
shape=curve_relief_cutter,
|
|
vector=(0.0, 0.0, -1.0),
|
|
)
|
|
|
|
mount_centers = [
|
|
("mount_sw", margin_x, margin_y),
|
|
("mount_se", plate_w - margin_x, margin_y),
|
|
("mount_ne", plate_w - margin_x, plate_h - margin_y),
|
|
("mount_nw", margin_x, plate_h - margin_y),
|
|
]
|
|
mount_cutters = []
|
|
for name, x_pos, y_pos in mount_centers:
|
|
mount_tag = name.replace("_", ".")
|
|
mount_profile = make_circle_profile(
|
|
name=name,
|
|
center_x=x_pos,
|
|
center_y=y_pos,
|
|
radius=mount_r,
|
|
circle_id="mount_hole",
|
|
)
|
|
mount_cutter = scad.extrude_rsolid(
|
|
profile=mount_profile,
|
|
direction=(0.0, 0.0, 1.0),
|
|
distance=plate_t + 2.0,
|
|
tag_prefix=f"constrained_sketch.{mount_tag}.cutter",
|
|
result_tag=f"tool.constrained_sketch.{mount_tag}",
|
|
)
|
|
mount_cutters.append(
|
|
scad.translate_shape(
|
|
shape=mount_cutter,
|
|
vector=(0.0, 0.0, -1.0),
|
|
)
|
|
)
|
|
|
|
part = scad.cut_rsolid(
|
|
body,
|
|
bore_cutter,
|
|
slot_cutter,
|
|
diamond_cutter,
|
|
curve_relief_cutter,
|
|
mount_cutters,
|
|
skip_non_intersecting=False,
|
|
)
|
|
part = scad.apply_tag(
|
|
shape=part,
|
|
tag="demo.constrained_sketch_bracket",
|
|
)
|
|
scad.capture_result(value=part)
|
|
return {
|
|
"part": part,
|
|
"plate_profile": plate_profile,
|
|
"diamond_profile": diamond_profile,
|
|
"curve_relief_profile": curve_relief_profile,
|
|
}
|
|
|
|
|
|
def main() -> None:
|
|
OUT.mkdir(parents=True, exist_ok=True)
|
|
result = build_model()
|
|
data = result.value
|
|
MODEL_JSON_PATH.write_text(result.model_json, encoding="utf-8")
|
|
|
|
rebuilt = result.replay()
|
|
scad.export_step(shapes=rebuilt, filename=str(STEP_PATH))
|
|
|
|
freecad_cmd = str(FREECAD_CMD) if FREECAD_CMD.exists() else None
|
|
scad.translator.freecad_translator.translate_model_json_to_fcstd(
|
|
json_str=result.model_json,
|
|
output_path=str(FCSTD_PATH),
|
|
document_name="SimpleCADConstrainedSketchDemo",
|
|
freecad_cmd=freecad_cmd,
|
|
)
|
|
|
|
payload = json.loads(result.model_json)
|
|
ops = [node["op"] for node in payload["graph"]["nodes"]]
|
|
promotion_nodes = [
|
|
node
|
|
for node in payload["graph"]["nodes"]
|
|
if node["op"]
|
|
in {"make_face_from_sketch_rface", "make_wire_from_sketch_rwire"}
|
|
]
|
|
diamond_promotion = next(
|
|
node
|
|
for node in promotion_nodes
|
|
if node["params"]["sketch"].get("name") == "guided_diamond_pocket"
|
|
)
|
|
diamond_constraints = diamond_promotion["params"]["sketch"].get(
|
|
"constraints",
|
|
[],
|
|
)
|
|
curve_promotion = next(
|
|
node
|
|
for node in promotion_nodes
|
|
if node["params"]["sketch"].get("name") == "curve_guided_relief"
|
|
)
|
|
curve_constraints = curve_promotion["params"]["sketch"].get(
|
|
"constraints",
|
|
[],
|
|
)
|
|
sketch_entity_tags = sorted(
|
|
tag
|
|
for edge in scad.ql.select(items=data["plate_profile"].get_edges())
|
|
.where(scad.ql.tag(pattern="sketch_entity.*"))
|
|
.all()
|
|
for tag in scad.list_tags(shape=edge)
|
|
if tag.startswith("sketch_entity.")
|
|
)
|
|
diamond_entity_tags = sorted(
|
|
tag
|
|
for edge in scad.ql.select(items=data["diamond_profile"].get_edges())
|
|
.where(scad.ql.tag(pattern="sketch_entity.*"))
|
|
.all()
|
|
for tag in scad.list_tags(shape=edge)
|
|
if tag.startswith("sketch_entity.")
|
|
)
|
|
curve_entity_tags = sorted(
|
|
tag
|
|
for edge in scad.ql.select(items=data["curve_relief_profile"].get_edges())
|
|
.where(scad.ql.tag(pattern="sketch_entity.*"))
|
|
.all()
|
|
for tag in scad.list_tags(shape=edge)
|
|
if tag.startswith("sketch_entity.")
|
|
)
|
|
|
|
print("graph_nodes", len(ops))
|
|
print("sketch_ops", sum(1 for op in ops if "sketch" in op))
|
|
print("promotion_nodes", len(promotion_nodes))
|
|
print(
|
|
"promotion_solve_snapshots",
|
|
sum(
|
|
1
|
|
for node in promotion_nodes
|
|
if "solve_snapshot" in node.get("params", {})
|
|
),
|
|
)
|
|
print("contains_public_solve_node", "make_solve_sketch_rsketchresult" in ops)
|
|
print("plate_sketch_entity_tags", sketch_entity_tags)
|
|
print("diamond_sketch_entity_tags", diamond_entity_tags)
|
|
print("diamond_constraint_count", len(diamond_constraints))
|
|
print(
|
|
"diamond_parallel_equal_constraints",
|
|
sum(
|
|
1
|
|
for constraint in diamond_constraints
|
|
if constraint.get("kind") in {"parallel", "equal_length"}
|
|
),
|
|
)
|
|
print("curve_sketch_entity_tags", curve_entity_tags)
|
|
print("curve_constraint_count", len(curve_constraints))
|
|
print(
|
|
"curve_tangent_equal_radius_constraints",
|
|
sum(
|
|
1
|
|
for constraint in curve_constraints
|
|
if constraint.get("kind")
|
|
in {"tangent", "equal_radius", "concentric", "point_on"}
|
|
),
|
|
)
|
|
print("volume", round(data["part"].get_volume(), 3))
|
|
print("wrote", MODEL_JSON_PATH)
|
|
print("wrote", STEP_PATH)
|
|
print("wrote", FCSTD_PATH)
|
|
|
|
|
|
if __name__ == "__main__":
|
|
main()
|