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
@@ -0,0 +1,17 @@
# Dimension
## Class Definition
```python
class Dimension(length: int = 0, angle: int = 0)
```
*Source: units.py*
## Import Surface
- top-level: `from simplecadapi import Dimension`
## Description
Physical dimension represented by integer length and angle exponents.
@@ -0,0 +1,20 @@
# DimensionTolerance
## Class Definition
```python
class DimensionTolerance(lower_deviation: float, upper_deviation: float)
```
*Source: expr.py*
## Import Surface
- top-level: `from simplecadapi import DimensionTolerance`
## Description
Permitted lower and upper deviations from a nominal dimension.
Deviations are signed: the lower deviation must be less than or equal to
zero and the upper deviation must be greater than or equal to zero.
@@ -21,6 +21,7 @@ Current design goals:
- Translate only from the canonical low-level `graph` IR
- Preserve node metadata and graph lineage as FreeCAD custom properties
- Preserve `expression_graph` as explicit translator metadata
- Preserve dimension tolerances and tolerance-chain requirements as metadata
- Preserve exported assembly constraints as document metadata objects
- Keep assembly metadata from the full model payload alongside the IR-driven
geometry translation
@@ -16,16 +16,14 @@ class GraphSession(graph_id: Optional[str] = None)
Context manager that records CAD operations into a DAG.
with GraphSession() as session:
n1 = record_operation(
"make_line_redge", {"start": (0, 0, 0), "end": (1, 0, 0)}
)
n2 = record_operation(
"make_line_redge", {"start": (1, 0, 0), "end": (1, 1, 0)}
)
record_operation(
"make_wire_from_edges_rwire", {"edge_count": 2}, inputs=[n1, n2]
)
For new replayable model entry points, prefer `@scad.model`, which owns the
session and returns a `ModelResult`. Use `GraphSession` directly for lower-level
graph workflows. `result_node_ids` reports nodes selected by `capture_result`:
# Access the graph after the session
print(session.graph.topological_order())
```python
with GraphSession(graph_id="demo") as session:
body = make_box_rsolid(width=10.0, height=6.0, depth=2.0)
session.capture_result(value=body)
print(session.result_node_ids)
```
@@ -0,0 +1,39 @@
# ModelResult
## Class Definition
```python
@dataclass(frozen=True)
class ModelResult:
value: Any
session: GraphSession
result_node_ids: Tuple[str, ...]
model_json: str
session_json: str
artifact_paths: Mapping[str, Path] = field(default_factory=dict)
```
*Source: graph.py*
## Import Surface
- top-level: `from simplecadapi import ModelResult`
## Description
Immutable result returned by a function decorated with `@scad.model`.
It contains the ordinary Python return value, the completed graph session, the
explicit result node ids, the model/session JSON artifacts, and any paths
written by automatic artifact export.
```python
result = build_model()
rebuilt = result.replay()
```
`replay()` replays `result.model_json`. Use `result.value` for the application
return value and `result.result_node_ids` to inspect the captured graph outputs.
Use `result.export_artifacts(output_dir=...)` to write one self-contained
`<graph_id>.scene.zip` after the model runs. The package embeds model JSON,
mapped project-relative Python sources, and render/selection assets; automatic
export does not write adjacent model/session JSON, STEP, STL, or FCStd files.
@@ -65,14 +65,38 @@ This index includes generated docs for the public SimpleCAD API surface, includi
- [loft_rsolid](loft_rsolid.md) *(from operations.py)* `top-level`
- [revolve_rsolid](revolve_rsolid.md) *(from operations.py)* `top-level`
- [sweep_rsolid](sweep_rsolid.md) *(from operations.py)* `top-level`
- [twisted_sweep_rsolid](twisted_sweep_rsolid.md) *(from operations.py)* `top-level`
## Tagging and Selection
- [apply_tag](apply_tag.md) *(from operations.py)* `top-level`
- [apply_tag_rselection](apply_tag_rselection.md) *(from operations.py)* `top-level`
- [explain_tag](explain_tag.md) *(from operations.py)* `top-level`
- [list_tags](list_tags.md) *(from operations.py)* `top-level`
- [select_edges_by_tag](select_edges_by_tag.md) *(from operations.py)* `top-level`
- [select_faces_by_tag](select_faces_by_tag.md) *(from operations.py)* `top-level`
Creation-time topology-identity tags are supported by profile constructors and
native feature primitives through `tag_prefix`. QL selectors also support `shared_boundary(...)`,
`intersection(...)`, `incident_to(...)`, `incident_face_count(...)`, and
`solids()` for relation-aware Edge selection.
## Unified Tag Contract
Topology identity and user semantics share one public tag model. Every binding
is inspected with `list_tags(...)` and `explain_tag(...)` and queried with
`ql.tag(...)`; one topology object may carry several tags for different uses.
`tag_prefix="housing"` creates topology-identity tags such as
`housing.face.top` and `housing.solid`. These bindings carry `topology_name`
evidence and project only when kernel history proves exact correspondence.
Role parameters such as `top_face_tag`, `side_faces_tag`, and
`generated_faces_tag`, plus `result_tag`, create tags whose evidence identifies
the kernel-proven role or result. Their tag text alone does not establish
topology identity. There is one public tag parameter per target role, not a
generic role-to-tag mapping.
## Boolean Operations
- [cut_rsolid](cut_rsolid.md) *(from operations.py)* `top-level`
@@ -98,6 +122,10 @@ This index includes generated docs for the public SimpleCAD API surface, includi
## Modeling Graph and Replay
- [GraphSession](GraphSession.md) *(from graph.py)* `top-level`
- [ModelResult](ModelResult.md) *(from graph.py)* `top-level`
- [capture_result](capture_result.md) *(from graph.py)* `top-level`
- [model](model.md) *(from graph.py)* `top-level`
- [requires_session](requires_session.md) *(from graph.py)* `top-level`
- [export_graph_json](export_graph_json.md) *(from serializer.py)* `top-level`
- [export_model_json](export_model_json.md) *(from serializer.py)* `top-level`
- [export_session_json](export_session_json.md) *(from serializer.py)* `top-level`
@@ -111,12 +139,34 @@ This index includes generated docs for the public SimpleCAD API surface, includi
## Expressions and Parameters
- [Const](Const.md) *(from expr.py)* `top-level`
- [DimensionTolerance](DimensionTolerance.md) *(from expr.py)* `top-level`
- [Expr](Expr.md) *(from expr.py)* `top-level`
- [ExpressionGraph](ExpressionGraph.md) *(from expr.py)* `top-level`
- [ToleranceAnalysis](ToleranceAnalysis.md) *(from tolerance.py)* `top-level`
- [ToleranceAnalysisError](ToleranceAnalysisError.md) *(from tolerance.py)* `top-level`
- [ToleranceCheck](ToleranceCheck.md) *(from tolerance.py)* `top-level`
- [ToleranceContribution](ToleranceContribution.md) *(from tolerance.py)* `top-level`
- [ToleranceGraph](ToleranceGraph.md) *(from tolerance.py)* `top-level`
- [ToleranceReport](ToleranceReport.md) *(from tolerance.py)* `top-level`
- [ToleranceRequirement](ToleranceRequirement.md) *(from tolerance.py)* `top-level`
- [ToleranceValidationError](ToleranceValidationError.md) *(from tolerance.py)* `top-level`
- [Var](Var.md) *(from expr.py)* `top-level`
- [analyze_tolerance](analyze_tolerance.md) *(from tolerance.py)* `top-level`
- [check_tolerance](check_tolerance.md) *(from tolerance.py)* `top-level`
- [const](const_function.md) *(from expr.py)* `top-level`
- [var](var_function.md) *(from expr.py)* `top-level`
## Physical Units
- [Dimension](Dimension.md) *(from units.py)* `top-level`
- [Unit](Unit.md) *(from units.py)* `top-level`
- [UnitValidationError](UnitValidationError.md) *(from units.py)* `top-level`
- [canonical_unit_for_dimension](canonical_unit_for_dimension.md) *(from units.py)* `top-level`
- [convert_value](convert_value.md) *(from units.py)* `top-level`
- [expression_uses_units](expression_uses_units.md) *(from units.py)* `top-level`
- [get_unit](get_unit.md) *(from units.py)* `top-level`
- [infer_dimension](infer_dimension.md) *(from units.py)* `top-level`
## Types and Errors
- [SimpleCADError](SimpleCADError.md) *(from errors.py)* `top-level`
@@ -207,11 +257,15 @@ This index includes generated docs for the public SimpleCAD API surface, includi
- [meta](meta.md) *(from ql.py)* `submodule:ql`
- [not_](not_.md) *(from ql.py)* `submodule:ql`
- [or_](or_.md) *(from ql.py)* `submodule:ql`
- [output_role](output_role.md) *(from ql.py)* `submodule:ql`
- [place_component_rassembly](place_component_rassembly.md) *(from operations.py)* `top-level`
- [radial_pattern_rsolidlist](radial_pattern_rsolidlist.md) *(from operations.py)* `top-level`
- [render_screenshot_rpath](render_screenshot_rpath.md) *(from operations.py)* `top-level`
- [select](select.md) *(from ql.py)* `submodule:ql`
- [solids](solids.md) *(from ql.py)* `submodule:ql`
- [solve_assembly_constraints_rassembly](solve_assembly_constraints_rassembly.md) *(from operations.py)* `top-level`
- [source_binding](source_binding.md) *(from ql.py)* `submodule:ql`
- [source_topology](source_topology.md) *(from ql.py)* `submodule:ql`
- [tag](tag.md) *(from ql.py)* `submodule:ql`
- [unground_component_rassembly](unground_component_rassembly.md) *(from operations.py)* `top-level`
- [value](value.md) *(from ql.py)* `submodule:ql`
@@ -22,3 +22,10 @@ Use `make_sketch_rsketch(...)`, `add_point_rsketch(...)`,
profiles. Public sketch construction APIs are functional and return an
updated `Sketch` document. The legacy `curves` constructor remains only for
reading already-built wire/edge containers.
Entity IDs are creation-time local identifiers. Constrained profile promotion uses
the ordered promotion map to bind each entity to exactly one generated Edge,
creating `sketch.<sketch-name>.entity.<entity-id>` and
`sketch.<sketch-name>.profile.<profile-id>` tags with `topology_name` evidence.
Downstream features may project these tags only when their kernel history proves exact
correspondence.
@@ -0,0 +1,17 @@
# ToleranceAnalysis
## Class Definition
```python
class ToleranceAnalysis(target_expr_id: str, method: ToleranceMethod, nominal: float, lower_bound: float, upper_bound: float, lower_deviation: float, upper_deviation: float, dimension: Dimension | None = None, unit: Unit | None = None, contributions: Tuple[ToleranceContribution, ...] = ())
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import ToleranceAnalysis`
## Description
Nominal value and propagated limits for an expression.
@@ -0,0 +1,17 @@
# ToleranceAnalysisError
## Class Definition
```python
class ToleranceAnalysisError
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import ToleranceAnalysisError`
## Description
Raised when a tolerance chain cannot be propagated safely.
@@ -0,0 +1,17 @@
# ToleranceCheck
## Class Definition
```python
class ToleranceCheck(requirement: ToleranceRequirement, analysis: ToleranceAnalysis, passed: bool, lower_margin: float, upper_margin: float)
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import ToleranceCheck`
## Description
Validation result for one tolerance requirement.
@@ -0,0 +1,17 @@
# ToleranceContribution
## Class Definition
```python
class ToleranceContribution(variable_expr_id: str, variable_name: str, nominal: float, source_tolerance: DimensionTolerance, sensitivity: float | None, lower_deviation: float, upper_deviation: float, source_unit: Unit | None = None)
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import ToleranceContribution`
## Description
One source dimension's propagated contribution to a result.
@@ -0,0 +1,17 @@
# ToleranceGraph
## Class Definition
```python
class ToleranceGraph(expression_graph: ExpressionGraph)
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import ToleranceGraph`
## Description
Tolerance requirements attached to one expression graph.
@@ -0,0 +1,17 @@
# ToleranceReport
## Class Definition
```python
class ToleranceReport(checks: Tuple[ToleranceCheck, ...] = ())
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import ToleranceReport`
## Description
Validation report for every requirement in a tolerance graph.
@@ -0,0 +1,17 @@
# ToleranceRequirement
## Class Definition
```python
class ToleranceRequirement(requirement_id: str, target_expr_id: str, tolerance: DimensionTolerance, method: ToleranceMethod = 'worst_case', name: str = '', tolerance_unit: Unit | None = None, target_dimension: Dimension | None = None)
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import ToleranceRequirement`
## Description
Permitted result deviations for one derived dimension.
@@ -0,0 +1,17 @@
# ToleranceValidationError
## Class Definition
```python
class ToleranceValidationError(report: 'ToleranceReport')
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import ToleranceValidationError`
## Description
Raised when one or more declared tolerance requirements fail.
@@ -0,0 +1,20 @@
# Unit
## Class Definition
```python
class Unit(symbol: str, dimension: Dimension, scale_to_canonical: float)
```
*Source: units.py*
## Import Surface
- top-level: `from simplecadapi import Unit`
## Description
Named unit with a scale to SimpleCAD's canonical numeric units.
Custom units are supported and serialize their symbol, dimension, and scale.
Registered built-in units serialize as compact symbols.
@@ -0,0 +1,17 @@
# UnitValidationError
## Class Definition
```python
class UnitValidationError
```
*Source: units.py*
## Import Surface
- top-level: `from simplecadapi import UnitValidationError`
## Description
Raised when units or expression dimensions are physically inconsistent.
@@ -3,7 +3,7 @@
## Class Definition
```python
class Var(name: str, default: float, comment: str | None = None, expr_id: str = field(default_factory=lambda : _make_expr_id('var')))
class Var(name: str, default: float, comment: str | None = None, expr_id: str = field(default_factory=lambda : _make_expr_id('var')), tolerance: DimensionTolerance | None = None, unit: Unit | None = None, tolerance_unit: Unit | None = None)
```
*Source: expr.py*
@@ -14,4 +14,8 @@ class Var(name: str, default: float, comment: str | None = None, expr_id: str =
## Description
Named scalar parameter with a default fallback value.
Named scalar parameter with optional physical-unit and tolerance intent.
``default`` and ``tolerance`` remain in their declared units. Evaluation,
geometry parameters, and tolerance propagation convert them to SimpleCAD's
canonical CAD units: millimeters for length and degrees for angle.
@@ -14,4 +14,6 @@ def add_line_rsketch(sketch: Sketch, entity_id: str, start: Union[SketchRef, str
## Description
Add a named line entity and return an updated sketch document.
Add an identified line entity and return an updated sketch document. Its
`entity_id` becomes the local segment of the canonical topology-identity tag for
the corresponding promoted profile Edge.
@@ -0,0 +1,27 @@
# analyze_tolerance
## API Definition
```python
def analyze_tolerance(value: ScalarLike, *, method: ToleranceMethod = 'worst_case') -> ToleranceAnalysis
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import analyze_tolerance`
## Description
Propagate source manufacturing tolerances through a scalar expression.
``worst_case`` returns guaranteed interval bounds. Affine chains are
dependency-aware, so repeated variables such as ``x - x`` cancel exactly;
nonlinear chains use conservative interval arithmetic. ``rss`` performs a
first-order root-sum-square calculation using analytic sensitivities.
Unit-aware variables are converted to canonical CAD units before
propagation. The returned analysis reports the inferred physical dimension
and canonical result unit. Every variable in the expression must declare a
source tolerance.
@@ -14,10 +14,13 @@ def apply_tag(shape: AnyShape, tag: str) -> AnyShape
## Description
Attach a normalized tag to a shape using the standard propagation policy.
Attach a normalized local user tag to a shape.
Tags must already be normalized lowercase tokens such as
``role.mounting_surface`` or ``group.fasteners``. Propagation is intentionally
not configurable from the public API; the default tag policy propagates
semantic role/anchor/group tags downward and keeps topology-specific tags
local.
`role.mounting_surface` or `group.fasteners`. The default topology policy is
`local` for every tag; token prefixes do not imply downward propagation.
Lineage visibility is limited to proven continuation and fragment witnesses.
`apply_tag(...)` preserves its historical in-place wrapper behavior. Use
`apply_tag_rselection(...)` when you need an independent semantic shape view,
explicit topology propagation, or a replayable multi-entity assignment.
@@ -0,0 +1,36 @@
# apply_tag_rselection
## API Definition
```python
def apply_tag_rselection(
scope: AnyShape,
targets: Union[ShapeSelector, Sequence[AnyShape]],
tag: str,
topology_propagation: str | TopologyPropagation = TopologyPropagation.LOCAL,
lineage_policy: str | LineagePolicy = LineagePolicy.CONTINUATION_FRAGMENT,
) -> AnyShape
```
*Source: operations.py*
## Import Surface
- top-level: `from simplecadapi import apply_tag_rselection`
## Description
Return an independent semantic view over the same geometry with one canonical
`TagBinding` attached to the selected entities. `targets` may be a serializable
QL `ShapeSelector` or a non-empty sequence of topology objects belonging to
`scope`.
Topology propagation defaults to `local`. Set `topology_propagation="downward"`
only when descendants should inherit the binding. Lineage defaults to proven
continuation and fragment derivations; it never makes lineage part of the
`effective` scope.
Inside `GraphSession`, the operation records the complete binding, target intent,
and selected-reference evidence. Replay re-resolves the target and checks that
the evidence has not drifted. The semantic node does not replace geometry-owned
topology references.
@@ -0,0 +1,19 @@
# canonical_unit_for_dimension
## API Definition
```python
def canonical_unit_for_dimension(dimension: Dimension) -> Unit
```
*Source: units.py*
## Import Surface
- top-level: `from simplecadapi import canonical_unit_for_dimension`
## Description
Return the canonical unit used by CAD and tolerance calculations.
Length, area, volume, and angle use ``mm``, ``mm^2``, ``mm^3``, and ``deg``.
@@ -0,0 +1,30 @@
# capture_result
## API Definition
```python
def capture_result(*, value: Any) -> Any
```
*Source: graph.py*
## Import Surface
- top-level: `from simplecadapi import capture_result`
## Description
Mark the graph nodes represented by `value` as explicit final outputs of the
active model session. The value is returned unchanged. Explicit capture keeps
intermediate/debug graph leaves out of `ModelResult.model_json`. Captured
geometry/product values are also the inputs to automatic artifact export when
the model decorator receives `export_dir=...`.
```python
@scad.model(graph_id="demo")
def build_demo():
body = scad.make_box_rsolid(width=10.0, height=4.0, depth=2.0)
return scad.capture_result(value=body)
```
Call it inside `@model` or another active `GraphSession`.
@@ -3,7 +3,14 @@
## API Definition
```python
def chamfer_rsolid(solid: Solid, edges: Union[Sequence[Edge], ShapeSelector], distance: ScalarLike) -> Solid
def chamfer_rsolid(
solid: Solid,
edges: Union[Sequence[Edge], ShapeSelector],
distance: ScalarLike,
*,
result_tag: Optional[str] = None,
generated_faces_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +21,10 @@ def chamfer_rsolid(solid: Solid, edges: Union[Sequence[Edge], ShapeSelector], di
## Description
Apply chamfers to selected solid edges.
Apply chamfers to selected solid edges. `generated_faces_tag` targets every face
with the kernel-proven `chamfer.patch` role. OCC contour expansion is included
rather than treating only the seed edge as the feature boundary.
The operation fails if a requested patch role has no proven result. `result_tag`
tags the resulting solid, and graph recording lowers assignments to replayable
semantic nodes.
@@ -0,0 +1,22 @@
# check_tolerance
## API Definition
```python
def check_tolerance(value: ScalarLike, tolerance: ToleranceLike, *, method: ToleranceMethod = 'worst_case', name: str | None = None, tolerance_unit: UnitLike | None = None) -> ToleranceCheck
```
*Source: tolerance.py*
## Import Surface
- top-level: `from simplecadapi import check_tolerance`
## Description
Propagate and verify one Length or Angle requirement.
``tolerance_unit`` defaults to the target dimension's canonical unit. When
provided, it must be dimensionally compatible and is converted before the
comparison. Legacy unitless requirements remain supported when no unit is
supplied.
@@ -0,0 +1,17 @@
# convert_value
## API Definition
```python
def convert_value(value: int | float, from_unit: UnitLike, to_unit: UnitLike) -> float
```
*Source: units.py*
## Import Surface
- top-level: `from simplecadapi import convert_value`
## Description
Convert a finite numeric value between dimensionally compatible units.
@@ -3,7 +3,11 @@
## API Definition
```python
def cut_rsolid(*solids: Union[Solid, Sequence[Solid]], skip_non_intersecting: bool = True) -> Solid
def cut_rsolid(
*solids: Union[Solid, Sequence[Solid]],
skip_non_intersecting: bool = True,
tracking_policy: TrackingPolicy | str = TrackingPolicy.FULL,
) -> Solid
```
*Source: operations.py*
@@ -29,6 +33,10 @@ sequences, and returns a single `Solid`.
- **Description**: When True, tools with no meaningful intersection are ignored for interactive convenience. Graph replay records this flag and should use False for strict diagnostic workflows.
### tracking_policy
- **Description**: `TrackingPolicy.FULL` computes topology history and lineage. `TrackingPolicy.GRAPH` preserves the canonical cut node, parameters, inputs, result topology references, and replay while omitting `TopoDelta` and history-derived topology lineage. Intersection validation and `skip_non_intersecting` behavior are unchanged.
## Returns
Solid: The cut result solid.
@@ -0,0 +1,27 @@
# explain_tag
## API Definition
```python
def explain_tag(
shape: AnyShape,
tag: str,
scope: str | TagScope = TagScope.EFFECTIVE,
) -> List[Dict[str, Any]]
```
*Source: operations.py*
## Import Surface
- top-level: `from simplecadapi import explain_tag`
## Description
Return every visible canonical binding that produces `tag` in the requested
scope. Explanations preserve binding identity, producer, attachment, evidence,
and policy-allowed lineage witnesses, so equal tag tokens from different
producers remain distinguishable.
As with `list_tags(...)`, `effective` excludes lineage. A lineage explanation
requires complete topology-history coverage.
@@ -3,7 +3,12 @@
## API Definition
```python
def export_model_json(session: 'GraphSession', indent: int = 2) -> str
def export_model_json(
session: 'GraphSession',
indent: int = 2,
*,
result_node_ids: Optional[Sequence[str]] = None,
) -> str
```
*Source: serializer.py*
@@ -20,3 +25,8 @@ Current Phase 1 scope uses the active session as the container of:
- operation graph
- expression graph
- capabilities/schema metadata
When `result_node_ids` is omitted, explicitly captured session results are used
when available; otherwise export falls back to graph leaves. New top-level model
code normally reads `ModelResult.model_json` instead of calling this function
directly.
@@ -0,0 +1,17 @@
# expression_uses_units
## API Definition
```python
def expression_uses_units(value: 'ScalarLike') -> bool
```
*Source: units.py*
## Import Surface
- top-level: `from simplecadapi import expression_uses_units`
## Description
Return whether an expression contains an explicit unit declaration.
@@ -3,7 +3,17 @@
## API Definition
```python
def extrude_rsolid(profile: Union[Wire, Face], direction: Tuple[float, float, float], distance: ScalarLike) -> Solid
def extrude_rsolid(
profile: Union[Wire, Face],
direction: Tuple[float, float, float],
distance: ScalarLike,
*,
tag_prefix: Optional[str] = None,
result_tag: Optional[str] = None,
start_face_tag: Optional[str] = None,
end_face_tag: Optional[str] = None,
side_faces_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +24,26 @@ def extrude_rsolid(profile: Union[Wire, Face], direction: Tuple[float, float, fl
## Description
Create a solid by extruding a profile.
Create a solid by extruding a profile. Kernel history assigns the output roles
`extrusion.start`, `extrusion.end`, and `extrusion.side`. Use the role tag
arguments to attach tags to those exact role sets.
Use creation-time profile topology tags (`tag_prefix` and `edge_tags`) when
durable feature Face/Edge identity is required. A tagged profile Edge yields a
corresponding `<tag_prefix>.face.side.<edge_tag>` when OCC proves the generated
side Face. Tagged Faces expose their effective tags to boundary Edge queries; use QL
`incident_to(..., distinct=True)` or `shared_boundary(...)` to disambiguate
an Edge by its two neighboring Faces.
Start and end roles require exactly one proven face. The side role requires one
or more proven faces and tags all of them. Missing, ambiguous, or unsupported
roles fail the whole operation instead of returning an untagged result.
`result_tag` attaches a local tag to the resulting solid. In a `GraphSession`,
all requested tags lower to replayable `apply_tag_rselection` semantic nodes;
they are not stored as geometry parameters.
Topology tags produced by `tag_prefix` remain directly queryable after
booleans when OCC provides a complete preserved or modified Face history. The
result binding retains the original semantic binding ID and source topology ID;
new boundary faces do not inherit the topology tag.
@@ -3,7 +3,14 @@
## API Definition
```python
def fillet_rsolid(solid: Solid, edges: Union[Sequence[Edge], ShapeSelector], radius: ScalarLike) -> Solid
def fillet_rsolid(
solid: Solid,
edges: Union[Sequence[Edge], ShapeSelector],
radius: ScalarLike,
*,
result_tag: Optional[str] = None,
generated_faces_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +21,10 @@ def fillet_rsolid(solid: Solid, edges: Union[Sequence[Edge], ShapeSelector], rad
## Description
Apply fillets to selected solid edges.
Apply fillets to selected solid edges. `generated_faces_tag` targets every face
with the kernel-proven `fillet.patch` role. OCC contour expansion is included,
so the role is not limited to the original seed edge.
The operation fails if a requested patch role has no proven result. `result_tag`
tags the resulting solid. In a `GraphSession`, assignments are separate replayable
semantic nodes with asserted user provenance.
@@ -0,0 +1,17 @@
# get_unit
## API Definition
```python
def get_unit(value: UnitLike) -> Unit
```
*Source: units.py*
## Import Surface
- top-level: `from simplecadapi import get_unit`
## Description
Resolve a built-in unit name/alias or return an existing ``Unit``.
@@ -0,0 +1,21 @@
# infer_dimension
## API Definition
```python
def infer_dimension(value: 'ScalarLike') -> Dimension | None
```
*Source: units.py*
## Import Surface
- top-level: `from simplecadapi import infer_dimension`
## Description
Infer and validate an expression's result dimension.
``None`` means the expression uses only legacy variables without unit
declarations. Expressions that contain explicit units are validated
strictly and cannot mix in legacy variables.
@@ -3,7 +3,10 @@
## API Definition
```python
def list_tags(shape: AnyShape) -> List[str]
def list_tags(
shape: AnyShape,
scope: str | TagScope = TagScope.EFFECTIVE,
) -> List[str]
```
*Source: operations.py*
@@ -14,4 +17,12 @@ def list_tags(shape: AnyShape) -> List[str]
## Description
Return shape tags in deterministic sorted order.
Return shape tags in deterministic sorted order for one semantic scope.
- `local`: bindings attached directly to the entity.
- `inherited`: bindings visible through explicit downward topology propagation.
- `effective`: local plus inherited bindings. Lineage is not included.
- `lineage`: bindings visible through complete, policy-allowed topology history.
Lineage queries fail with a semantic capability error when complete topology
history is unavailable; they do not guess from geometry or enumeration order.
@@ -3,7 +3,17 @@
## API Definition
```python
def loft_rsolid(profiles: List[Wire], ruled: bool = False) -> Solid
def loft_rsolid(
profiles: List[Wire],
ruled: bool = False,
*,
tracking_policy: TrackingPolicy | str = TrackingPolicy.FULL,
tag_prefix: Optional[str] = None,
result_tag: Optional[str] = None,
start_face_tag: Optional[str] = None,
end_face_tag: Optional[str] = None,
side_faces_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +24,13 @@ def loft_rsolid(profiles: List[Wire], ruled: bool = False) -> Solid
## Description
Create a solid by lofting multiple profiles.
Create a solid by lofting multiple profiles. Kernel history assigns
`loft.start`, `loft.end`, and `loft.side` roles. Start and end tags require one
proven face each; side tags apply to all proven side faces. `result_tag` targets
the solid. Recorded assignments are replayable semantic nodes.
`TrackingPolicy.FULL` is the default and preserves complete kernel topology
history. `TrackingPolicy.GRAPH` skips topology-history queries while still
recording and replaying the `make_loft_rsolid` graph node. In `GRAPH` mode,
`result_tag` remains available, but face-role tags and `tag_prefix` require
`FULL` tracking.
@@ -3,7 +3,21 @@
## API Definition
```python
def make_box_rsolid(width: ScalarLike, height: ScalarLike, depth: ScalarLike, bottom_face_center: Tuple[float, float, float] = (0, 0, 0)) -> Solid
def make_box_rsolid(
width: ScalarLike,
height: ScalarLike,
depth: ScalarLike,
bottom_face_center: Tuple[float, float, float] = (0, 0, 0),
*,
tag_prefix: Optional[str] = None,
result_tag: Optional[str] = None,
bottom_face_tag: Optional[str] = None,
top_face_tag: Optional[str] = None,
front_face_tag: Optional[str] = None,
back_face_tag: Optional[str] = None,
left_face_tag: Optional[str] = None,
right_face_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +28,12 @@ def make_box_rsolid(width: ScalarLike, height: ScalarLike, depth: ScalarLike, bo
## Description
Create a box solid.
Create a native box with six exact kernel-backed Face roles: `box.bottom`,
`box.top`, `box.front`, `box.back`, `box.left`, and `box.right`.
`tag_prefix="housing"` creates `housing.solid` and corresponding
`housing.face.<role>` topology-identity tags. Use the face tag arguments for
role tags and `result_tag` for the Solid.
Box Edge roles are unsupported because the current OCP builder does not expose
equivalent direct Edge witnesses. Select an exact Edge from two tagged incident
Faces with QL `incident_to(..., distinct=True)` or `shared_boundary(...)`.
@@ -3,7 +3,13 @@
## API Definition
```python
def make_circle_redge(center: Tuple[float, float, float], radius: ScalarLike, normal: Tuple[float, float, float] = (0, 0, 1)) -> Edge
def make_circle_redge(
center: Tuple[float, float, float],
radius: ScalarLike,
normal: Tuple[float, float, float] = (0, 0, 1),
*,
tag_prefix: Optional[str] = None,
) -> Edge
```
*Source: operations.py*
@@ -14,4 +20,5 @@ def make_circle_redge(center: Tuple[float, float, float], radius: ScalarLike, no
## Description
Create a circular edge.
Create a circular edge. `tag_prefix` optionally creates the topology tag
`<tag_prefix>.edge`.
@@ -3,7 +3,14 @@
## API Definition
```python
def make_circle_rface(center: Tuple[float, float, float], radius: ScalarLike, normal: Tuple[float, float, float] = (0, 0, 1)) -> Face
def make_circle_rface(
center: Tuple[float, float, float],
radius: ScalarLike,
normal: Tuple[float, float, float] = (0, 0, 1),
*,
tag_prefix: Optional[str] = None,
edge_tag: Optional[str] = None,
) -> Face
```
*Source: operations.py*
@@ -14,4 +21,8 @@ def make_circle_rface(center: Tuple[float, float, float], radius: ScalarLike, no
## Description
Create a circular face.
Create a circular face. `tag_prefix` creates `<tag_prefix>.face`, while
`edge_tag` supplies the final segment of `<tag_prefix>.edge.<edge_tag>` for its
boundary Edge, or the complete Edge tag when `tag_prefix` is omitted. The Face
topology tag is visible to effective boundary-Edge QL queries without copying
arbitrary local Face tags to every Edge.
@@ -3,7 +3,14 @@
## API Definition
```python
def make_circle_rwire(center: Tuple[float, float, float], radius: ScalarLike, normal: Tuple[float, float, float] = (0, 0, 1)) -> Wire
def make_circle_rwire(
center: Tuple[float, float, float],
radius: ScalarLike,
normal: Tuple[float, float, float] = (0, 0, 1),
*,
tag_prefix: Optional[str] = None,
edge_tag: Optional[str] = None,
) -> Wire
```
*Source: operations.py*
@@ -14,4 +21,8 @@ def make_circle_rwire(center: Tuple[float, float, float], radius: ScalarLike, no
## Description
Create a circular wire.
Create a circular wire. `tag_prefix` creates `<tag_prefix>.wire`, while
`edge_tag` supplies the final segment of `<tag_prefix>.edge.<edge_tag>` for its
single circular Edge, or the complete Edge tag when `tag_prefix` is omitted.
These topology tags are preserved only where a downstream operation has
complete, kernel-proven correspondence.
@@ -3,7 +3,22 @@
## API Definition
```python
def make_cone_rsolid(bottom_radius: ScalarLike, height: ScalarLike, top_radius: ScalarLike = 0.0, bottom_face_center: Tuple[float, float, float] = (0, 0, 0), axis: Tuple[float, float, float] = (0, 0, 1)) -> Solid
def make_cone_rsolid(
bottom_radius: ScalarLike,
height: ScalarLike,
top_radius: ScalarLike = 0.0,
bottom_face_center: Tuple[float, float, float] = (0, 0, 0),
axis: Tuple[float, float, float] = (0, 0, 1),
*,
tag_prefix: Optional[str] = None,
result_tag: Optional[str] = None,
start_face_tag: Optional[str] = None,
end_face_tag: Optional[str] = None,
side_face_tag: Optional[str] = None,
start_edge_tag: Optional[str] = None,
end_edge_tag: Optional[str] = None,
seam_edge_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +29,12 @@ def make_cone_rsolid(bottom_radius: ScalarLike, height: ScalarLike, top_radius:
## Description
Create a cone or truncated cone solid.
Create a native cone or frustum with direct kernel-backed `cone.start`,
`cone.end`, and `cone.side` Face roles and `cone.start_boundary`,
`cone.end_boundary`, and `cone.seam` Edge roles.
A pointed cone (`top_radius=0`) has no `cone.end` Face, so requesting that role
fails. Its `cone.end_boundary` is the kernel's degenerate apex Edge. A frustum
has all six roles. `tag_prefix="adapter"` creates corresponding
`adapter.face.*` and `adapter.edge.*` topology-identity tags; use the role tag
arguments for role assignments.
@@ -3,7 +3,21 @@
## API Definition
```python
def make_cylinder_rsolid(radius: ScalarLike, height: ScalarLike, bottom_face_center: Tuple[float, float, float] = (0, 0, 0), axis: Tuple[float, float, float] = (0, 0, 1)) -> Solid
def make_cylinder_rsolid(
radius: ScalarLike,
height: ScalarLike,
bottom_face_center: Tuple[float, float, float] = (0, 0, 0),
axis: Tuple[float, float, float] = (0, 0, 1),
*,
tag_prefix: Optional[str] = None,
result_tag: Optional[str] = None,
start_face_tag: Optional[str] = None,
end_face_tag: Optional[str] = None,
side_face_tag: Optional[str] = None,
start_edge_tag: Optional[str] = None,
end_edge_tag: Optional[str] = None,
seam_edge_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +28,9 @@ def make_cylinder_rsolid(radius: ScalarLike, height: ScalarLike, bottom_face_cen
## Description
Create a cylinder solid.
Create a native cylinder with kernel-backed topology tags. `tag_prefix="shaft"` produces
`shaft.face.start`, `shaft.face.end`, `shaft.face.side`, and corresponding
`shaft.edge.start`, `shaft.edge.end`, and `shaft.edge.seam` tags. Face tags
are inherited by their boundary Edges. Role tags use the native
`cylinder.*` Face/Edge roles. Use QL `incident_to(..., distinct=True)` or
`shared_boundary(...)` to select an Edge from its two neighboring tagged Faces.
@@ -14,4 +14,12 @@ def make_face_from_sketch_rface(sketch: Sketch, profile: int | str = 0, *, requi
## Description
Promote a sketch profile to a concrete face, solving internally.
Promote a sketch profile to a concrete face, solving internally. The Face and
each boundary Edge receive canonical tags with `topology_name` evidence from the
exact Sketch promotion map. For a Sketch with `name="rect"`, profile `bottom`,
and entity ID `right`, the tags are `sketch.rect.profile.bottom` and
`sketch.rect.entity.right`.
The bindings replay from the Sketch payload and promotion parameters. Legacy
compatibility tags such as `sketch_entity.right` remain separate from the
canonical topology-identity tags.
@@ -3,7 +3,12 @@
## API Definition
```python
def make_face_from_wire_rface(wire: Wire, normal: Tuple[float, float, float] = (0, 0, 1)) -> Face
def make_face_from_wire_rface(
wire: Wire,
normal: Tuple[float, float, float] = (0, 0, 1),
*,
tag_prefix: Optional[str] = None,
) -> Face
```
*Source: operations.py*
@@ -14,4 +19,6 @@ def make_face_from_wire_rface(wire: Wire, normal: Tuple[float, float, float] = (
## Description
Create a face from a closed wire.
Create a face from a closed wire. Existing proven Edge topology tags on the
wire are copied to corresponding Face boundary Edges. `tag_prefix` optionally
adds the Face tag `<tag_prefix>.face`.
@@ -3,7 +3,12 @@
## API Definition
```python
def make_line_redge(start: Tuple[ScalarLike, ScalarLike, ScalarLike], end: Tuple[ScalarLike, ScalarLike, ScalarLike]) -> Edge
def make_line_redge(
start: Tuple[ScalarLike, ScalarLike, ScalarLike],
end: Tuple[ScalarLike, ScalarLike, ScalarLike],
*,
tag_prefix: Optional[str] = None,
) -> Edge
```
*Source: operations.py*
@@ -14,4 +19,7 @@ def make_line_redge(start: Tuple[ScalarLike, ScalarLike, ScalarLike], end: Tuple
## Description
Create a straight edge between two points.
Create a straight edge between two points. When `tag_prefix` is provided, the
edge receives the topology tag `<tag_prefix>.edge`. Downstream profile and
feature operations may preserve that tag when kernel history proves the
correspondence.
@@ -3,7 +3,15 @@
## API Definition
```python
def make_rectangle_rface(width: ScalarLike, height: ScalarLike, center: Tuple[ScalarLike, ScalarLike, ScalarLike] = (0, 0, 0), normal: Tuple[ScalarLike, ScalarLike, ScalarLike] = (0, 0, 1)) -> Face
def make_rectangle_rface(
width: ScalarLike,
height: ScalarLike,
center: Tuple[ScalarLike, ScalarLike, ScalarLike] = (0, 0, 0),
normal: Tuple[ScalarLike, ScalarLike, ScalarLike] = (0, 0, 1),
*,
tag_prefix: Optional[str] = None,
edge_tags: Optional[Sequence[str]] = None,
) -> Face
```
*Source: operations.py*
@@ -14,4 +22,9 @@ def make_rectangle_rface(width: ScalarLike, height: ScalarLike, center: Tuple[Sc
## Description
Create a rectangular face.
Create a rectangular face. `tag_prefix` creates `<tag_prefix>.face`, and
`edge_tags` supplies one tag for each of its four boundary Edges. With
`tag_prefix`, each is a local segment under `<tag_prefix>.edge`; without it,
each is a complete Edge tag. These topology tags can be projected to proven
feature Faces and queried with the same `list_tags(...)` and `ql.tag(...)`
surfaces as other tags.
@@ -3,7 +3,15 @@
## API Definition
```python
def make_rectangle_rwire(width: ScalarLike, height: ScalarLike, center: Tuple[ScalarLike, ScalarLike, ScalarLike] = (0, 0, 0), normal: Tuple[ScalarLike, ScalarLike, ScalarLike] = (0, 0, 1)) -> Wire
def make_rectangle_rwire(
width: ScalarLike,
height: ScalarLike,
center: Tuple[ScalarLike, ScalarLike, ScalarLike] = (0, 0, 0),
normal: Tuple[ScalarLike, ScalarLike, ScalarLike] = (0, 0, 1),
*,
tag_prefix: Optional[str] = None,
edge_tags: Optional[Sequence[str]] = None,
) -> Wire
```
*Source: operations.py*
@@ -14,4 +22,9 @@ def make_rectangle_rwire(width: ScalarLike, height: ScalarLike, center: Tuple[Sc
## Description
Create a rectangular wire.
Create a rectangular wire. `tag_prefix` creates `<tag_prefix>.wire`.
`edge_tags` must contain one tag for each generated profile Edge, in kernel
construction order. With `tag_prefix`, each value is the local segment of
`<tag_prefix>.edge.<edge_tag>`; without it, each value is the complete Edge tag.
These topology tags are stable anchors for operations such as `extrude_rsolid`
when correspondence is proven.
@@ -17,4 +17,5 @@ def make_sketch_rsketch(name: Optional[str] = None, *, plane: Any = 'XY', sketch
Create an empty declarative sketch document.
Use this API, not concrete edge/wire constructors, when the intent is to
build a sketch profile with constraints.
build a sketch profile with constraints. The sketch name and explicit entity
IDs are stable local identifiers used by constrained profile promotion.
@@ -3,7 +3,7 @@
## API Definition
```python
def make_wire_from_edges_rwire(edges: List[Edge]) -> Wire
def make_wire_from_edges_rwire(edges: List[Edge], *, tag_prefix: Optional[str] = None) -> Wire
```
*Source: operations.py*
@@ -14,4 +14,6 @@ def make_wire_from_edges_rwire(edges: List[Edge]) -> Wire
## Description
Create a wire from a list of connected edges.
Create a wire from a list of connected edges. Existing proven Edge topology
tags are preserved by exact topology identity; `tag_prefix` optionally adds
`<tag_prefix>.wire` to the resulting wire.
@@ -14,4 +14,10 @@ def make_wire_from_sketch_rwire(sketch: Sketch, profile: int | str = 0, *, requi
## Description
Promote a sketch profile to a concrete wire, solving internally.
Promote a sketch profile to a concrete wire, solving internally. The promotion
map preserves exact ordered entity-to-Edge correspondence and creates tags with
`topology_name` evidence, such as `sketch.rect.profile.bottom` and
`sketch.rect.entity.right`.
Promotion fails when the generated Edge count does not match the promotion map;
the SDK does not infer identity from geometry or enumeration heuristics.
@@ -0,0 +1,44 @@
# model
## API Definition
```python
def model(
func=None,
*,
graph_id: Optional[str] = None,
export_dir: Optional[str | Path] = None,
) -> Callable
```
*Source: graph.py*
## Import Surface
- top-level: `from simplecadapi import model`
## Description
Decorate the single top-level entry point of a replayable model. Each invocation
creates and owns exactly one `GraphSession`, activates it while the function
runs, captures model/session JSON in memory, and returns a `ModelResult`. When
`export_dir` is provided, explicitly captured geometry/product values produce
one `<graph_id>.scene.zip` in that directory. The package embeds model JSON,
mapped project-relative Python source files, and render/selection assets; it
does not create adjacent model/session JSON, STEP, STL, or FCStd files.
```python
@scad.model(graph_id="bracket")
def build_bracket():
body = scad.make_box_rsolid(width=20.0, height=10.0, depth=3.0)
scad.capture_result(value=body)
return body
```
Use `result.artifact_paths["scene"]` to locate the package, or call
`result.export_artifacts(output_dir=...)` after a model has run without an
export directory. The explicit `export_dir` opt-in avoids unexpected filesystem
writes for library callers and tests.
Do not nest `@model` functions or create another `GraphSession` inside a model
function. Use `@requires_session` for child builders.
@@ -0,0 +1,23 @@
# output_role
## API Definition
```python
def output_role(role_name: str) -> SerializablePredicate
```
*Source: ql.py*
## Import Surface
- submodule: `from simplecadapi import ql`
## Description
Return a serializable predicate matching a kernel-proven operation output role
in `metadata["track"]`. Role matching never falls back to face order, geometry,
or flat tags. Use it with a typed selector, for example:
```python
end = ql.faces().where(ql.output_role(role_name="extrusion.end")).exactly(1)
```
@@ -3,7 +3,7 @@
## API Definition
```python
def render_screenshot_rpath(shapes: Union[Solid, Sequence[Solid]], output_path: str, highlight_tags: Optional[Sequence[str]] = None, tag_labels: Optional[Dict[str, str]] = None, image_size: Tuple[int, int] = (1400, 900), view: Union[Tuple[float, float], str] = 'auto', show_axes: bool = True, show_legend: bool = True, zoom: float = 4.0) -> str
def render_screenshot_rpath(shapes: Union[Solid, Sequence[Solid]], output_path: str, highlight_tags: Optional[Sequence[str]] = None, tag_labels: Optional[Dict[str, str]] = None, image_size: Tuple[int, int] = (1400, 900), view: Union[Tuple[float, float], str] = 'auto', show_axes: bool = True, show_legend: bool = True, zoom: float = 4.0, show_callouts: bool = True) -> str
```
*Source: operations.py*
@@ -14,4 +14,6 @@ def render_screenshot_rpath(shapes: Union[Solid, Sequence[Solid]], output_path:
## Description
Render a screenshot of shapes and save it to a file.
Render a screenshot of shapes and save it to a file. Set `show_callouts=False`
to retain highlighted material colors and the legend without placing tag labels
over the model.
@@ -0,0 +1,22 @@
# requires_session
## API Definition
```python
def requires_session(func=None) -> Callable
```
*Source: graph.py*
## Import Surface
- top-level: `from simplecadapi import requires_session`
## Description
Decorate a reusable graph-producing builder that must run inside the caller's
active `GraphSession`. It reuses the session owned by the enclosing `@model`
function and validates returned graph values against that session.
Calling a `@requires_session` builder without an active session raises
`RuntimeError`. Builders must not create their own `GraphSession`.
@@ -3,7 +3,18 @@
## API Definition
```python
def revolve_rsolid(profile: Union[Wire, Face], axis: Tuple[float, float, float] = (0, 0, 1), angle: ScalarLike = 360, origin: Tuple[float, float, float] = (0, 0, 0)) -> Solid
def revolve_rsolid(
profile: Union[Wire, Face],
axis: Tuple[float, float, float] = (0, 0, 1),
angle: ScalarLike = 360,
origin: Tuple[float, float, float] = (0, 0, 0),
*,
tag_prefix: Optional[str] = None,
result_tag: Optional[str] = None,
start_face_tag: Optional[str] = None,
end_face_tag: Optional[str] = None,
side_faces_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +25,10 @@ def revolve_rsolid(profile: Union[Wire, Face], axis: Tuple[float, float, float]
## Description
Create a solid by revolving a profile around an axis.
Create a solid by revolving a profile around an axis. Kernel history assigns
`revolution.start`, `revolution.end`, and `revolution.side` output roles.
Start and end roles require exactly one proven face; side tags apply to every
proven side face. A full 360-degree revolve normally has no separate start or end
face, so requesting either cap tag raises a capability error rather than guessing.
`result_tag` tags the resulting solid. Role tags are replayable semantic nodes.
@@ -15,3 +15,15 @@ def select(items: Iterable[Any]) -> Query
## Description
Start a QL query over a shape collection or selector scope.
For topology-aware selection, use `ql.faces()`, `ql.edges()`, `ql.wires()`,
`ql.vertices()`, or `ql.solids()`. `ShapeSelector.intersection(other)` forms a
serializable set intersection. `selector.shared_boundary(other,
to_kind="edge")` intersects the boundaries of two selectors. Edge selectors
also support `incident_to(face_selector, ..., distinct=True)` and
`incident_face_count(exactly=2)` to select edges by exact incident Face
witnesses and reject open or non-manifold edges.
These selectors resolve by topology identity, not enumeration order, area,
normal, or position heuristics. Their `to_dict()` payloads can be restored with
`ql.selector_from_dict(...)`.
@@ -3,7 +3,11 @@
## API Definition
```python
def select_edges_by_tag(shape: Union[Face, Solid], tag: str) -> List[Edge]
def select_edges_by_tag(
shape: Union[Face, Solid],
tag: str,
scope: str | TagScope = TagScope.EFFECTIVE,
) -> List[Edge]
```
*Source: operations.py*
@@ -14,4 +18,6 @@ def select_edges_by_tag(shape: Union[Face, Solid], tag: str) -> List[Edge]
## Description
Select edges by tag.
Select edges by an exact normalized tag in the requested semantic scope.
`effective` does not include lineage; request `scope="lineage"` explicitly when
selection depends on complete topology-history evidence.
@@ -3,7 +3,11 @@
## API Definition
```python
def select_faces_by_tag(solid: Solid, tag: str) -> List[Face]
def select_faces_by_tag(
solid: Solid,
tag: str,
scope: str | TagScope = TagScope.EFFECTIVE,
) -> List[Face]
```
*Source: operations.py*
@@ -14,4 +18,6 @@ def select_faces_by_tag(solid: Solid, tag: str) -> List[Face]
## Description
Select faces by tag.
Select faces by an exact normalized tag in the requested semantic scope.
`effective` does not include lineage; request `scope="lineage"` explicitly when
selection depends on complete topology-history evidence.
@@ -3,7 +3,17 @@
## API Definition
```python
def shell_rsolid(solid: Solid, faces_to_remove: Union[Sequence[Face], ShapeSelector], thickness: ScalarLike) -> Solid
def shell_rsolid(
solid: Solid,
faces_to_remove: Union[Sequence[Face], ShapeSelector],
thickness: ScalarLike,
*,
result_tag: Optional[str] = None,
body_faces_tag: Optional[str] = None,
offset_faces_tag: Optional[str] = None,
closing_faces_tag: Optional[str] = None,
wall_edges_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +24,16 @@ def shell_rsolid(solid: Solid, faces_to_remove: Union[Sequence[Face], ShapeSelec
## Description
Shell a solid to create a hollow part.
Shell a solid to create a hollow part. The operation can expose these exact
kernel roles:
- `shell.body_face`: surviving or modified source body faces.
- `shell.offset_face`: generated offset faces.
- `shell.closing_descendant`: descendants of removed closing faces.
- `shell.wall`: generated closing-boundary edges.
The named arguments map directly to those roles. A role is available only when
OCC provides a complete witness;
requesting an unavailable role fails instead of deriving one from enumeration or
geometry. `result_tag` tags the resulting solid. Recorded assignments replay as
semantic nodes and preserve face versus edge target kinds.
@@ -0,0 +1,19 @@
# solids
## API Definition
```python
def solids() -> ShapeSelector
```
*Source: ql.py*
## Import Surface
- submodule: `from simplecadapi import ql`
## Description
Create a serializable selector over Solid topology. Solid selectors can be
traversed to boundary Edges and combined with `intersection(...)` or
`shared_boundary(...)` to find topology common to two named Solid selectors.
@@ -0,0 +1,19 @@
# source_binding
## API Definition
```python
def source_binding(binding_id: str) -> SerializablePredicate
```
*Source: ql.py*
## Import Surface
- submodule: `from simplecadapi import ql`
## Description
Match a local projected `TagBinding` whose topology-change evidence preserves the
exact source `binding_id`. Objects without canonical local binding evidence raise
an unsupported-query capability error instead of consulting flat tags.
@@ -0,0 +1,19 @@
# source_topology
## API Definition
```python
def source_topology(topo_id: str) -> SerializablePredicate
```
*Source: ql.py*
## Import Surface
- submodule: `from simplecadapi import ql`
## Description
Match a local projected `TagBinding` by the exact source topology identity stored
in its kernel-history evidence. This predicate queries source-preserving evidence;
it does not infer ancestry from geometry.
@@ -3,7 +3,17 @@
## API Definition
```python
def sweep_rsolid(profile: Face, path: Wire, is_frenet: bool = False) -> Solid
def sweep_rsolid(
profile: Face,
path: Wire,
is_frenet: bool = False,
*,
tag_prefix: Optional[str] = None,
result_tag: Optional[str] = None,
start_face_tag: Optional[str] = None,
end_face_tag: Optional[str] = None,
side_faces_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
@@ -14,4 +24,10 @@ def sweep_rsolid(profile: Face, path: Wire, is_frenet: bool = False) -> Solid
## Description
Create a solid by sweeping a profile along a path.
Create a solid by sweeping a profile along a path. Kernel history assigns
`sweep.start`, `sweep.end`, and `sweep.side` roles. Start and end tags require one
proven face each; side tags apply to all proven side faces. `result_tag` targets
the solid, and recorded assignments are replayable semantic nodes.
Profiles with inner wires are rejected because the current PipeShell operation
receives only the outer wire; silently dropping profile holes is not allowed.
@@ -0,0 +1,46 @@
# twisted_sweep_rsolid
## API Definition
```python
def twisted_sweep_rsolid(
profile: Face,
distance: ScalarLike,
twist_angle: ScalarLike,
axis: Tuple[float, float, float] = (0.0, 0.0, 1.0),
origin: Tuple[float, float, float] = (0.0, 0.0, 0.0),
*,
guide_radius: ScalarLike = 1.0,
tag_prefix: Optional[str] = None,
result_tag: Optional[str] = None,
start_face_tag: Optional[str] = None,
end_face_tag: Optional[str] = None,
side_faces_tag: Optional[str] = None,
) -> Solid
```
*Source: operations.py*
## Import Surface
- top-level: `from simplecadapi import twisted_sweep_rsolid`
## Description
Sweep a planar profile along a straight axis while rotating it linearly by the
signed total `twist_angle` in degrees. The profile must lie at the sweep start,
be planar, and be normal to `axis`.
The OCP implementation uses a one-edge straight spine and a one-edge
cylindrical auxiliary spine. This normally creates one continuous side face per
profile edge rather than splitting every side at intermediate loft sections.
Profiles with inner wires are rejected.
Kernel history assigns `twisted_sweep.start`, `twisted_sweep.end`, and
`twisted_sweep.side` roles. The operation records one canonical
`make_twisted_sweep_rsolid` graph node containing `axis`, `origin`, `distance`,
`twist_angle`, and `guide_radius`; strict replay invokes the same public
operation with the recorded parameters.
`guide_radius` controls only the auxiliary orientation guide and must be a
positive finite value. It does not set the swept profile radius.
@@ -3,7 +3,13 @@
## API Definition
```python
def union_rsolid(*solids: Union[Solid, Sequence[Solid]], clean: bool = True, glue: bool = _DEFAULT_UNION_GLUE, tol: Optional[float] = None) -> Solid
def union_rsolid(
*solids: Union[Solid, Sequence[Solid]],
clean: bool = True,
glue: bool = _DEFAULT_UNION_GLUE,
tol: Optional[float] = None,
tracking_policy: TrackingPolicy | str = TrackingPolicy.FULL,
) -> Solid
```
*Source: operations.py*
@@ -40,6 +46,10 @@ returning multiple pieces.
- **Type**: `Optional fuzzy-boolean tolerance used by the OCC union kernel. When`
- **Description**: omitted, SimpleCAD chooses a conservative scale-aware tolerance.
### tracking_policy
- **Description**: `TrackingPolicy.FULL` computes topology history and lineage. `TrackingPolicy.GRAPH` preserves the canonical union node, parameters, inputs, result topology references, and replay while omitting `TopoDelta` and history-derived topology lineage. Geometry options `clean`, `glue`, and `tol` are unchanged.
## Returns
Solid: The merged union result.
@@ -3,7 +3,7 @@
## API Definition
```python
def var(name: str, default: int | float, comment: str | None = None) -> Var
def var(name: str, default: int | float, comment: str | None = None, tolerance: ToleranceLike | None = None, *, unit: UnitLike | None = None, tolerance_unit: UnitLike | None = None) -> Var
```
*Source: expr.py*
@@ -14,4 +14,13 @@ def var(name: str, default: int | float, comment: str | None = None) -> Var
## Description
Create a named variable node for v2 expression-driven parameters.
Create a physical or legacy scalar variable.
``tolerance=0.1`` declares a symmetric ``+/-0.1`` tolerance. Use a
``(lower_deviation, upper_deviation)`` pair for an asymmetric tolerance.
``tolerance_unit`` defaults to ``unit`` when a nominal unit is declared.
Values are converted to canonical CAD units only when evaluated, so the
declaration and serialized expression node preserve the user's units.
Variables without ``unit`` retain legacy unitless behavior. A unit-aware
expression cannot mix declared-unit variables with legacy variables.