# SCAD → Cordial Translation Reference Every SCAD operation has a Cordial equivalent. Where the operation can be parallelized, the conditions and a Cordial example are shown. --- ## Primitives ### sphere **SCAD** ```scad sphere(r=5); sphere(5); ``` **Cordial** ```rust sphere(5.0) ``` Parallelism: n/a — leaf node; always evaluable at any point independently. --- ### cube **SCAD** ```scad cube([10, 20, 30]); cube(5); cube([10, 20, 30], center=true); ``` **Cordial** ```rust box3(5.0, 10.0, 15.0) // half-extents, always centered cube(5.0) // equal half-extents ``` Note: SCAD `cube()` uses full sizes and defaults to corner-aligned. Cordial uses half-extents and is always centered. The lowerer handles the translation offset automatically when ingesting SCAD. --- ### cylinder **SCAD** ```scad cylinder(h=10, r=3); cylinder(h=10, r=3, center=true); ``` **Cordial** ```rust cylinder(3.0, 10.0) // always centered on Z ``` --- ## Transforms ### translate **SCAD** ```scad translate([10, 0, 0]) sphere(1); ``` **Cordial** ```rust sphere(1.0).translate(10.0, 0.0, 0.0) ``` Parallelism: a translation wraps its child — the child subtree is independently evaluable. Multiple translates on independent shapes are always parallel. --- ### rotate **SCAD** ```scad rotate([45, 0, 0]) cube(5); rotate([0, 90, 0]) cube(5); ``` **Cordial** ```rust cube(5.0).rotate_x(45.0) cube(5.0).rotate_y(90.0) ``` SCAD `rotate([x,y,z])` decomposes into sequential X, Y, Z rotations. Cordial exposes each axis independently. --- ### scale **SCAD** ```scad scale([2, 1, 1]) sphere(1); scale(3) sphere(1); ``` **Cordial** ```rust sphere(1.0).scale(2.0, 1.0, 1.0) sphere(1.0).scale_uniform(3.0) ``` --- ## Boolean Operations ### union **SCAD** ```scad union() { sphere(1); cube(2); } ``` **Cordial** ```rust sphere(1.0) | cube(2.0) // or explicitly: sphere(1.0).union(cube(2.0)) // or variadic: Shape::union_all([sphere(1.0), cube(2.0), cylinder(1.0, 3.0)]) ``` **Parallelism: always parallelizable.** Condition: union children share no intermediate state. In an SDF, every child is a separate distance field — `min(d_a, d_b)` evaluates `d_a` and `d_b` independently. ```rust // Parallel union — each branch evaluates on its own thread par::branch() .add(sphere(1.0)) .add(cube(2.0).translate(5.0, 0.0, 0.0)) .add(cylinder(1.0, 3.0).rotate_x(90.0)) .union() ``` --- ### difference **SCAD** ```scad difference() { cube(10, center=true); sphere(5); } ``` **Cordial** ```rust cube(10.0) - sphere(5.0) // or explicitly: cube(10.0).difference(sphere(5.0)) // or multiple subtractions: cube(10.0).difference_all([sphere(5.0), cylinder(2.0, 20.0)]) ``` **Parallelism: parallelizable when operands are independent subtrees.** Condition: the base shape and the subtracted shapes share no intermediate nodes. The base evaluates independently from the subtracted shapes. The subtracted shapes themselves are a union of independent evaluations (each contributes to `max(base, -sub)`). ```rust // The base and each subtracted shape are independent branches par::branch() .add(cube(10.0)) .add(sphere(5.0)) .add(cylinder(2.0, 20.0)) .intersection() // difference = intersection with complement ``` --- ### intersection **SCAD** ```scad intersection() { sphere(5); cube(4, center=true); } ``` **Cordial** ```rust sphere(5.0) & cube(4.0) ``` **Parallelism: parallelizable when operands are independent subtrees.** Same condition as difference — `max(d_a, d_b)` evaluates both sides independently. ```rust par::branch() .add(sphere(5.0)) .add(cube(4.0)) .intersection() ``` --- ## Control Flow ### for loop **SCAD** ```scad for (i = [0:5]) translate([i*10, 0, 0]) sphere(1); for (i = [0:2:10]) translate([i, 0, 0]) sphere(1); for (x = [1, 5, 10]) translate([x, 0, 0]) cube(2); ``` **Cordial** (`.crd` source) ``` // Linear array — 6 spheres spaced 10 apart map(i, 0..6) { translate(sphere(1), i * 10, 0, 0) } // 8 bolts around a circle map(i, 0..8) { rotate_z(translate(cylinder(0.5, 2), 5, 0, 0), i * pi/4) } ``` **Cordial** (Rust DSL) ```rust pattern::linear_array(&sphere(1.0), 6, [10.0, 0.0, 0.0]) par::polar(&cylinder(0.5, 2.0).translate(5.0, 0.0, 0.0), 8) ``` **Parallelism: always parallelizable when bounds are constant.** `map` unrolls at parse time into N independent branches joined by union. Each iteration is independent — no iteration reads state written by another. This is the fundamental serial-to-parallel transformation: what looks like a sequential loop is actually N independent geometric evaluations. --- ### if / else **SCAD** ```scad if (use_sphere) sphere(5); else cube(5, center=true); x = 10; if (x > 5) sphere(x); ``` **Cordial** — direct conditional geometry isn't needed because Rust has native `if`: ```rust let shape = if use_sphere { sphere(5.0) } else { cube(5.0) }; ``` **Parallelism: constant conditions → dead code elimination.** Condition: if the condition evaluates to a constant at lowering time, only the taken branch produces geometry. The other branch is eliminated entirely — zero cost. When the condition is variable (unknown at compile time), both branches are included as a union. This is conservative but correct — the SDF field is defined everywhere. --- ### Ternary **SCAD** ```scad r = big ? 10 : 1; sphere(r); ``` **Cordial** — native Rust: ```rust let r = if big { 10.0 } else { 1.0 }; sphere(r) ``` Evaluated at lowering time when all inputs are constant. --- ## Patterns (Cordial-only) These have no direct SCAD equivalent — they're higher-level abstractions that compile to parallel-friendly structures. ### linear_array ```rust // 5 spheres along X, spaced 3 units apart pattern::linear_array(&sphere(1.0), 5, [3.0, 0.0, 0.0]) ``` Always parallel — each instance is independent. ### polar_array ```rust // 12 bolts around Z pattern::polar_array(&cylinder(0.3, 2.0).translate(5.0, 0.0, 0.0), 12) ``` Always parallel — equivalent to N rotations of the same shape. ### grid_array ```rust // 4x6 grid of cylinders pattern::grid_array(&cylinder(0.5, 1.0), 4, 6, 3.0, 3.0) ``` Always parallel — N×M independent instances. ### mirror ```rust pattern::mirror_x(&sphere(1.0).translate(3.0, 0.0, 0.0)) // Original at (3,0,0) + mirror at (-3,0,0) ``` Always parallel — 2 branches, one original, one reflected. --- ## Parallel Composition (Cordial-only) ### par::branch — explicit parallel grouping ```rust // N independent shapes, explicitly grouped for parallel evaluation let part = par::branch() .add(sphere(2.0)) .add(cylinder(1.0, 5.0).translate(0.0, 0.0, 1.0)) .add(cube(1.5).rotate_z(45.0).translate(3.0, 0.0, 0.0)) .union(); ``` Each `.add()` is an independent branch. The join operation (`.union()`, `.intersection()`, `.smooth_union(k)`) combines results after all branches complete. ### par::map — multiplicative parallelism ```rust // Same shape, N different transforms — all independent par::map(&sphere(0.5), (0..20).map(|i| { let t = i as f64 / 20.0; let x = (t * std::f64::consts::TAU).cos() * 5.0; let y = (t * std::f64::consts::TAU).sin() * 5.0; let z = t * 10.0; move |s: Shape| s.translate(x, y, z) })) ``` ### par::symmetric — mirror parallelism ```rust par::symmetric_x(&part) // 2 branches par::symmetric_xyz(&part) // 8 branches (all octants) ``` ### par::polar — rotational parallelism ```rust par::polar(&fin, 6) // 6 branches around Z ``` --- ## Parallelism Summary | Operation | Parallelizable? | Condition | |-----------|----------------|-----------| | Primitive (sphere, cube, etc.) | Always | Leaf node — independent by definition | | Transform (translate, rotate, scale) | Always | Wraps child; child evaluates independently | | Union | Always | `min(a, b)` — operands share no state | | Difference | Yes | Operands are independent subtrees | | Intersection | Yes | Operands are independent subtrees | | For loop (constant bounds) | Always | Unrolls to N independent branches | | For loop (variable bounds) | No | Cannot unroll at compile time | | If/else (constant condition) | n/a | Dead code eliminated; only one branch exists | | If/else (variable condition) | Yes | Both branches included as union | | `par::branch` | Always | Explicit parallel grouping | | `par::map` | Always | Same shape, N transforms | | `par::polar` | Always | N rotations around axis | | `pattern::*` | Always | Compile to union of independent instances | The threshold: an operation becomes parallelizable when it crosses into calculus — when accumulated structure becomes continuous and differentiable, every point in the field is independently evaluable. SDFs are inherently in this territory: the distance function is defined at every point in space, and evaluating it at point A tells you nothing about point B. Serial operations that build up an SDF tree are just describing the function — once described, evaluation is embarrassingly parallel.