feat: integrate SimpleCADAPI 2.0.2 CAD workflows
This commit is contained in:
@@ -10,14 +10,19 @@ The long-form schema reference remains [`../operation_graph_json_spec.md`](../op
|
||||
import json
|
||||
import simplecadapi as scad
|
||||
|
||||
with scad.GraphSession() as session:
|
||||
body = scad.make_box_rsolid(10, 6, 2)
|
||||
hole = scad.make_cylinder_rsolid(1, 4, bottom_face_center=(0, 0, -1))
|
||||
@scad.model(graph_id="drilled_block")
|
||||
def build_model():
|
||||
body = scad.make_box_rsolid(width=10, height=6, depth=2)
|
||||
hole = scad.make_cylinder_rsolid(
|
||||
radius=1, height=4, bottom_face_center=(0, 0, -1)
|
||||
)
|
||||
result = scad.cut_rsolid(body, hole)
|
||||
scad.capture_result(value=result)
|
||||
return result
|
||||
|
||||
model_json = scad.export_model_json(session)
|
||||
payload = json.loads(model_json)
|
||||
rebuilt = scad.replay_model_json(model_json)
|
||||
model = build_model()
|
||||
payload = json.loads(model.model_json)
|
||||
rebuilt = model.replay()
|
||||
```
|
||||
|
||||
Inspect these fields:
|
||||
@@ -29,6 +34,17 @@ Inspect these fields:
|
||||
- `node["inputs"]`: upstream node ids used by replay.
|
||||
- `payload["leaf_ids"]`: explicit final result node ids.
|
||||
- `payload["expression_graph"]`: expression DAG used by expression-backed parameters.
|
||||
- `payload["tolerance_graph"]`: dimension-chain requirements and validation evidence.
|
||||
|
||||
For new top-level models, `ModelResult.model_json` is the preferred artifact
|
||||
accessor. Use `@scad.requires_session` for reusable builders and
|
||||
`scad.capture_result(...)` when the final output should not be inferred from
|
||||
all graph leaves. If a model invocation also needs durable CAD/viewer files,
|
||||
pass `export_dir=...` to `@scad.model`; its captured geometry/product values
|
||||
then produce one self-contained `<graph_id>.scene.zip`. It embeds
|
||||
`model/model.json`, mapped project-relative Python sources, and the evaluated
|
||||
render/selection assets. It does not create adjacent model/session JSON, STEP,
|
||||
STL, or FCStd files. No files are written when `export_dir` is omitted.
|
||||
|
||||
## Important rule: source API is not always graph API
|
||||
|
||||
@@ -52,11 +68,13 @@ Many user-facing functions are convenience APIs. During an active `GraphSession`
|
||||
- [Primitive and profile operations](primitives-and-profiles.md)
|
||||
- [Features, booleans, transforms, patterns, and selectors](features-booleans-transforms.md)
|
||||
- [Expressions and replay behavior](expressions-and-replay.md)
|
||||
- [Physical units and dimension inference](../physical-units.md)
|
||||
- [Dimension tolerance chains](../dimension-tolerance-chains.md)
|
||||
|
||||
## Example
|
||||
## Examples
|
||||
|
||||
See [`../../../examples/07_serialization_operation_tree.py`](../../../examples/07_serialization_operation_tree.py). It intentionally exercises every canonical core operation and writes:
|
||||
|
||||
- `examples/out/serialization_operation_tree.model.json`
|
||||
- `examples/out/serialization_operation_tree.summary.md`
|
||||
- `examples/out/serialization_operation_tree.step`
|
||||
The retained examples use the same model/session contract. See
|
||||
[`../../../examples/08_constrained_sketch.py`](../../../examples/08_constrained_sketch.py)
|
||||
for sketch promotion and replay, and
|
||||
[`../../../examples/10_part_assembly.py`](../../../examples/10_part_assembly.py)
|
||||
for product hierarchy and automatic artifact export.
|
||||
|
||||
@@ -15,14 +15,15 @@ This lets consumers choose between:
|
||||
```python
|
||||
import simplecadapi as scad
|
||||
|
||||
width = scad.var("width", 24.0, comment="plate width")
|
||||
height = scad.var("height", 12.0, comment="plate height")
|
||||
thickness = scad.var("thickness", 4.0, comment="plate thickness")
|
||||
width = scad.var("width", 24.0, unit="mm", comment="plate width", tolerance=0.1)
|
||||
height = scad.var("height", 12.0, unit="mm", comment="plate height", tolerance=0.1)
|
||||
thickness = scad.var("thickness", 4.0, unit="mm", comment="plate thickness", tolerance=(-0.05, 0.1))
|
||||
|
||||
with scad.GraphSession() as session:
|
||||
plate = scad.make_box_rsolid(width, height, thickness)
|
||||
rib = scad.make_box_rsolid(width / 4.0, height, thickness * 2.0)
|
||||
part = scad.union_rsolid(plate, rib)
|
||||
session.require_tolerance(width + height, 0.2, tolerance_unit="mm", name="plate_envelope")
|
||||
|
||||
model_json = scad.export_model_json(session)
|
||||
```
|
||||
@@ -48,7 +49,9 @@ A node with expression-backed params may look like:
|
||||
}
|
||||
```
|
||||
|
||||
`params.distance` is the evaluated snapshot. `param_exprs.distance` says the value came from expression node `var_thickness`.
|
||||
`params.distance` is the evaluated canonical snapshot. Unit-aware lengths are
|
||||
stored in millimeters and angles in degrees. `param_exprs.distance` says the value
|
||||
came from expression node `var_thickness` and preserves its declaration metadata.
|
||||
|
||||
For tuple/list params, `param_exprs` mirrors the shape of the parameter and uses `null` where no expression is present:
|
||||
|
||||
@@ -78,12 +81,24 @@ Consumers that want parameterization should:
|
||||
|
||||
Consumers that only want geometry can ignore `param_exprs` and `expression_graph`.
|
||||
|
||||
Variable nodes may contain `unit`, `tolerance`, and `tolerance_unit`. Registered
|
||||
units use string symbols; custom units use `{symbol, dimension,
|
||||
scale_to_canonical}` objects. Import reconstructs the expression graph and reruns
|
||||
dimension inference rather than trusting external dimension claims.
|
||||
|
||||
Session/model payloads store derived-dimension requirements in `tolerance_graph`.
|
||||
See [Physical Units](../physical-units.md) and [Dimension Tolerance
|
||||
Chains](../dimension-tolerance-chains.md) for inference, propagation, and
|
||||
validation semantics.
|
||||
|
||||
## Replay policy in current implementation
|
||||
|
||||
`replay_model_json(model_json)` currently uses the canonical low-level `graph` and the numeric values in `node.params`.
|
||||
|
||||
That means replay is deterministic with respect to the exported snapshot. It does not currently re-solve expressions with changed variable values.
|
||||
|
||||
Replay does validate stored tolerance requirements before rebuilding the nominal geometry. A failing tolerance chain blocks replay, but passing bounds do not cause replay to sample or regenerate limit geometry.
|
||||
|
||||
In practical terms:
|
||||
|
||||
```python
|
||||
|
||||
@@ -122,6 +122,40 @@ Replay effect:
|
||||
2. Replay path wire from input 1.
|
||||
3. Call `sweep_rsolid(profile, path, is_frenet=...)`.
|
||||
|
||||
## Twisted Sweep
|
||||
|
||||
Source:
|
||||
|
||||
```python
|
||||
profile = scad.make_rectangle_rface(width=2.0, height=1.0)
|
||||
solid = scad.twisted_sweep_rsolid(
|
||||
profile=profile,
|
||||
distance=8.0,
|
||||
twist_angle=30.0,
|
||||
)
|
||||
```
|
||||
|
||||
Serialized node:
|
||||
|
||||
```json
|
||||
{
|
||||
"op": "make_twisted_sweep_rsolid",
|
||||
"params": {
|
||||
"axis": [0.0, 0.0, 1.0],
|
||||
"origin": [0.0, 0.0, 0.0],
|
||||
"distance": 8.0,
|
||||
"twist_angle": 30.0,
|
||||
"guide_radius": 1.0
|
||||
},
|
||||
"inputs": ["node_for_profile_face"],
|
||||
"output_count": 1
|
||||
}
|
||||
```
|
||||
|
||||
Replay reconstructs the continuous auxiliary-spine rotation law from the
|
||||
recorded parameters and invokes `twisted_sweep_rsolid(...)`. No sampled loft
|
||||
sections are stored or inferred.
|
||||
|
||||
## Helical sweep macro lowering
|
||||
|
||||
Source:
|
||||
|
||||
Reference in New Issue
Block a user