8.2 KiB
Primitive and Profile Operation Serialization
This guide covers replayable primitive/profile operations in the canonical operation graph.
All examples assume:
import json
import simplecadapi as scad
with scad.GraphSession() as session:
...
payload = json.loads(scad.export_model_json(session))
In exported JSON, each operation appears in payload["graph"]["nodes"] as:
{
"node_id": "node_xxxxxxxx",
"op": "make_line_redge",
"params": {...},
"inputs": [],
"output_count": 1,
"tags": [...],
"display": {...},
"param_exprs": {...},
"context": {...}
}
display, tags, context, semantic_delta, and topo_delta are useful metadata. Replay primarily depends on op, params, and inputs.
Point
Source:
p = scad.make_point_rvertex(1.0, 2.0, 3.0)
Serialized node:
{
"op": "make_point_rvertex",
"params": {"x": 1.0, "y": 2.0, "z": 3.0},
"inputs": [],
"output_count": 1
}
Replay effect: calls make_point_rvertex(x, y, z) and returns a Vertex.
Line edge
Source:
edge = scad.make_line_redge((0, 0, 0), (5, 0, 0))
Serialized node:
{
"op": "make_line_redge",
"params": {"start": [0.0, 0.0, 0.0], "end": [5.0, 0.0, 0.0]},
"inputs": [],
"output_count": 1
}
Replay effect: calls make_line_redge(start, end) and returns an Edge.
Segment aliases
make_segment_redge(start, end) is an alias of make_line_redge(...) and records the same make_line_redge node.
make_segment_rwire(start, end) lowers to:
make_line_redgemake_wire_from_edges_rwire
There is no canonical make_segment_wire node in model JSON.
Circle edge, wire, and face
Source edge:
edge = scad.make_circle_redge((0, 0, 0), 2.0, normal=(0, 0, 1))
Serialized node:
{
"op": "make_circle_redge",
"params": {
"center": [0.0, 0.0, 0.0],
"radius": 2.0,
"normal": [0.0, 0.0, 1.0]
},
"inputs": [],
"output_count": 1
}
Replay effect: calls make_circle_redge(center, radius, normal).
Source wire:
wire = scad.make_circle_rwire((0, 0, 0), 2.0)
Lowered serialized graph:
make_circle_redge -> make_wire_from_edges_rwire
Source face:
face = scad.make_circle_rface((0, 0, 0), 2.0)
Lowered serialized graph:
make_circle_redge -> make_wire_from_edges_rwire -> make_face_from_wire_rface
There is no canonical make_circle_wire or make_circle_face node.
Three-point arc edge and wire
Source edge:
arc = scad.make_three_point_arc_redge(
(0, 0, 0),
(1, 1, 0),
(2, 0, 0),
)
Serialized node:
{
"op": "make_three_point_arc_redge",
"params": {
"start": [0.0, 0.0, 0.0],
"middle": [1.0, 1.0, 0.0],
"end": [2.0, 0.0, 0.0]
},
"inputs": [],
"output_count": 1
}
Replay effect: calls make_three_point_arc_redge(start, middle, end).
make_three_point_arc_rwire(...) lowers to:
make_three_point_arc_redge -> make_wire_from_edges_rwire
Angle arc edge and wire
Source edge:
arc = scad.make_angle_arc_redge(
center=(0, 0, 0),
radius=1.0,
start_angle=0.0,
end_angle=1.57,
normal=(0, 0, 1),
)
Serialized node:
{
"op": "make_angle_arc_redge",
"params": {
"center": [0.0, 0.0, 0.0],
"radius": 1.0,
"start_angle": 0.0,
"end_angle": 1.57,
"normal": [0.0, 0.0, 1.0]
},
"inputs": [],
"output_count": 1
}
Replay effect: calls make_angle_arc_redge(center, radius, start_angle, end_angle, normal).
make_angle_arc_rwire(...) lowers to:
make_angle_arc_redge -> make_wire_from_edges_rwire
Spline edge and wire
Source edge:
fit = scad.fit_cubic_bspline_control_points(
[(0, 0, 0), (1, 1, 0), (2, 0, 0)],
tolerance=0.01,
)
spline = scad.make_spline_redge(
control_points=fit.control_points,
knots=fit.unique_knots,
multiplicities=fit.multiplicities,
)
Serialized node:
{
"op": "make_spline_redge",
"params": {
"control_points": [[0.0, 0.0, 0.0], [0.6, 1.0, 0.0], [1.4, 1.0, 0.0], [2.0, 0.0, 0.0]],
"degree": 3,
"knots": [0.0, 1.0],
"multiplicities": [4, 4],
"weights": null,
"periodic": false
},
"inputs": [],
"output_count": 1
}
Replay effect: calls make_spline_redge(control_points=..., degree=..., knots=..., multiplicities=..., weights=..., periodic=...).
make_spline_rwire(control_points=..., ...) lowers to:
make_spline_redge -> make_wire_from_edges_rwire
make_spline_redge now stores an exact B-spline definition. It does not accept sampled/interpolated curve points directly; use fit_cubic_bspline_control_points(...) first when human/LLM-authored code starts from samples.
Helix edge and wire
Source edge:
helix = scad.make_helix_redge(
pitch=0.7,
height=2.2,
radius=0.9,
center=(0, 0, 0),
dir=(0, 0, 1),
)
Serialized node:
{
"op": "make_helix_redge",
"params": {
"pitch": 0.7,
"height": 2.2,
"radius": 0.9,
"center": [0.0, 0.0, 0.0],
"dir": [0.0, 0.0, 1.0]
},
"inputs": [],
"output_count": 1
}
Replay effect: calls make_helix_redge(pitch, height, radius, center, dir).
make_helix_rwire(...) lowers to:
make_helix_redge -> make_wire_from_edges_rwire
Wire from edges
Source:
a = scad.make_line_redge((0, 0, 0), (1, 0, 0))
b = scad.make_line_redge((1, 0, 0), (1, 1, 0))
wire = scad.make_wire_from_edges_rwire([a, b])
Serialized node:
{
"op": "make_wire_from_edges_rwire",
"params": {"edge_count": 2},
"inputs": ["node_for_a", "node_for_b"],
"output_count": 1
}
Replay effect:
- Replay each input edge node.
- Collect input edge outputs in input order.
- Call
make_wire_from_edges_rwire(edges).
The actual edge geometry is not duplicated inside this node; it is recovered through inputs.
Face from wire
Source:
face = scad.make_face_from_wire_rface(wire, normal=(0, 0, 1))
Serialized node:
{
"op": "make_face_from_wire_rface",
"params": {"normal": [0.0, 0.0, 1.0]},
"inputs": ["node_for_wire"],
"output_count": 1
}
Replay effect:
- Replay the input wire node.
- Call
make_face_from_wire_rface(wire, normal=...).
Rectangle wire and face lowering
Source:
wire = scad.make_rectangle_rwire(4.0, 2.0, center=(0, 0, 0))
face = scad.make_rectangle_rface(4.0, 2.0, center=(0, 0, 0))
Lowered serialized graph:
make_rectangle_rwire:
make_line_redge x4 -> make_wire_from_edges_rwire
make_rectangle_rface:
make_line_redge x4 -> make_wire_from_edges_rwire -> make_face_from_wire_rface
There is no canonical make_rectangle_wire or make_rectangle_face node.
Polyline wire lowering
Source:
wire = scad.make_polyline_rwire(
[(0, 0, 0), (1, 0, 0), (1, 1, 0)],
closed=False,
)
Lowered serialized graph:
make_line_redge x(number_of_segments) -> make_wire_from_edges_rwire
If closed=True, one additional closing line edge is emitted.
There is no canonical make_polyline_wire node.
Box, cylinder, sphere, and cone lowering
These user-facing primitive solids are intentionally lowered to canonical profile/feature operations.
Box
Source:
box = scad.make_box_rsolid(4.0, 2.0, 1.0)
Lowered serialized graph:
make_line_redge x4
-> make_wire_from_edges_rwire
-> make_face_from_wire_rface
-> make_extrude_rsolid
Replay effect: rebuilds the rectangular face, then extrudes it.
There is no canonical make_box node.
Cylinder
Source:
cyl = scad.make_cylinder_rsolid(1.0, 3.0)
Lowered serialized graph:
make_circle_redge
-> make_wire_from_edges_rwire
-> make_face_from_wire_rface
-> make_extrude_rsolid
There is no canonical make_cylinder node.
Sphere
Source:
sphere = scad.make_sphere_rsolid(1.5, center=(0, 0, 0))
Lowered serialized graph:
profile edges/wire/face -> make_revolve_rsolid
There is no canonical make_sphere node.
Cone / truncated cone
Source:
cone = scad.make_cone_rsolid(1.2, 2.0, top_radius=0.4)
Lowered serialized graph:
profile edges/wire/face -> make_revolve_rsolid
There is no canonical make_cone node.