pub enum ShapeOp {
Show 19 variants
Extrude(f64),
Taper(f64),
Rotate(Quat),
Translate(Vec3),
Scale(Vec3),
Split {
axis: Axis,
slots: Vec<SplitSlot>,
snap: Option<SnapBinding>,
},
Repeat {
axis: Axis,
tile_sizes: Vec<f64>,
rule: String,
},
Comp(CompTarget),
I(String),
Mat(Material),
Rule(String),
Align {
local_axis: Axis,
target: Vec3,
},
Offset {
distance: f64,
cases: Vec<OffsetCase>,
},
Roof {
config: RoofConfig,
cases: Vec<RoofCase>,
},
RegSnap(String),
IfClear {
rule: String,
},
IfOccluded {
rule: String,
},
Polygon(Vec<DVec2>),
Attach {
world_axis: Vec3,
cases: Vec<AttachCase>,
},
}Expand description
The atomic CGA operations that the interpreter executes.
Every operation transforms the current Scope into zero or more child scopes,
each tagged with a rule name that will be recursively evaluated.
Variants§
Extrude(f64)
Lifts a 2-D footprint (XZ plane) into a 3-D volume by setting the Y size.
Taper(f64)
Pyramidal taper: scales the top face toward the centroid.
amount ∈ [0, 1]: 0 = no taper, 1 = full pyramid (top collapses to a point).
Rotate(Quat)
Applies an additional rotation to the scope (cumulative with existing rotation).
Translate(Vec3)
Translates the scope origin in local space.
Scale(Vec3)
Scales the scope size along each axis (multiplicative).
Split
Divides the scope along axis into ordered slots.
When snap is Some, interior slot boundaries are snapped to the
nearest registered snap-plane along axis (see SnapBinding).
Repeat
Tiles the scope along axis with child scopes drawn from tile_sizes.
tile_sizes is a per-slot pattern that is cycled to fill the axis range.
Tiles are appended greedily (next tile from the cycle is added while it
still fits inside the remaining range), then all placed tiles are
scaled by the same factor total / Σ(placed) so they fill the scope
exactly with no gap and no overshoot.
A single-element list [t] is the legacy uniform Repeat(axis, t).
A multi-element list [a, b, c] produces an …, a, b, c, a, b, c, …
cadence where each tile’s relative width is preserved.
Comp(CompTarget)
Decomposes the scope into its geometric components (faces, edges, vertices).
I(String)
Terminal: replace the scope with the named mesh asset.
This is the “terminal symbol” — produces a Terminal node in the output model.
Mat(Material)
Sets the material on the current work item.
The material is propagated to the final Terminal, allowing downstream
renderers to apply textures / shaders and physics consumers to derive
volumetric mass properties without changing the scope.
Syntax:
Mat("Brick")/Mat(Brick)— id-only material; no density.Mat("Brick", 1800)— id + density in kg/m³; the interpreter computescrate::model::MassPropertiesfor terminals stamped with this material.
Rule(String)
Calls a named sub-rule on the current scope unchanged. Used for grammar rule references that don’t transform the scope themselves.
Align
Rotates the scope so that the specified local axis points in the given world direction.
Applies the shortest-arc rotation from the current world direction of local_axis
to target. Useful for recovering from accumulated rotations.
Syntax: Align(Y, Up), Align(Z, Forward), etc.
Named targets: Up=(0,1,0), Down=(0,-1,0), Right=(1,0,0), Left=(-1,0,0),
Forward=(0,0,-1), Back=(0,0,1).
Offset
Creates an inset (distance < 0) frame on a 2D face scope.
Produces up to two kinds of child scopes:
Inside: the inset rectangle.Border: four surrounding strips (bottom, top, left, right), each invoking the same rule.
Syntax: Offset(-0.2) { Inside: Glass | Border: Frame }
Roof
Generates a roof structure above the current scope using rich parametric configuration.
Operates on a volume scope. The config contains the roof type, primary pitch angle,
optional secondary pitch, overhang, ridge offset, fascia depth, and tier height.
Syntax examples:
Roof(Gable, 30) { Slope: Tiles | GableEnd: Bricks }— basic GableRoof(Hip, 30, 0.5) { Slope: Tiles }— Hip with overhangRoof(Gambrel, 45, 20) { LowerSlope: Shingles | UpperSlope: Tiles }— GambrelRoof(Saltbox, 45, offset=0.3) { Slope: Tiles | GableEnd: Bricks }— SaltboxRoof(DutchGable, 45, tier=0.7) { Slope: Tiles | GableEnd: Bricks }— Dutch Gable
RegSnap(String)
Registers all six face planes of the current scope as snap-planes
under the given label. Subsequent Split(snap="label") ops can align
their interior boundaries to these planes. Read-only with respect to
the scope (the scope itself passes through unchanged).
Syntax: RegSnap("bays")
IfClear
Conditionally invokes rule on the current scope only when no
already-emitted terminal occludes the scope (true OBB overlap test).
Useful for placing decorative elements that should only appear where
no structural element has already been placed.
The grammar author is responsible for ordering — terminals derived before this op participate in the test; later terminals do not.
Syntax: IfClear { Window }
IfOccluded
Inverse of ShapeOp::IfClear: invokes rule only when the current
scope is occluded by an already-emitted terminal.
Syntax: IfOccluded { Patch }
Polygon(Vec<DVec2>)
Stamps an explicit polygonal FaceProfile on the next terminal in this rule.
Mirrors how ShapeOp::Taper sets a profile override: the next I(...)
(or implicit terminal) emits a Terminal whose face_profile is
crate::model::FaceProfile::Polygon with the provided vertex list.
Vertices are 2-D points in the scope’s local floor plane (XZ), measured
in world units from the scope origin; the renderer triangulates and
extrudes along the local Y axis.
Syntax: Polygon((0,0), (4,0), (4,2), (2,2), (2,4), (0,4))
(variadic (x,y) list, capped at 256 vertices for parser DoS hardening).
Attach
Projects a new horizontal scope out of a sloped face for attaching dormers or details.
world_axis defines the “up” direction for the attached scope (usually world Y).
The resulting scope sits on the face’s surface with its Y axis aligned to world_axis,
inheriting the face’s width and height but with depth = 0.
Syntax: Attach(Up) { Surface: DormerMass }
Trait Implementations§
Source§impl<'de> Deserialize<'de> for ShapeOp
impl<'de> Deserialize<'de> for ShapeOp
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
impl StructuralPartialEq for ShapeOp
Auto Trait Implementations§
impl Freeze for ShapeOp
impl RefUnwindSafe for ShapeOp
impl Send for ShapeOp
impl Sync for ShapeOp
impl Unpin for ShapeOp
impl UnsafeUnpin for ShapeOp
impl UnwindSafe for ShapeOp
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> DeserializeOwned for Twhere
T: for<'de> Deserialize<'de>,
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more