|
| 1 | +# Alignment and Stacking |
| 2 | + |
| 3 | +Position geometry relative to the origin and arrange shapes along an axis. |
| 4 | + |
| 5 | +## Overview |
| 6 | + |
| 7 | +In Cadova, alignment is a way to control how geometry is positioned relative to the coordinate system's origin. Since different shapes are defined differently, some centered, some corner-based, aligning them explicitly is often the easiest way to place them where you want. |
| 8 | + |
| 9 | +For example, a `Circle(radius: 10)` is centered at the origin by default, but a `Rectangle([20, 10])` extends from the origin toward the top right. Using alignment helps you standardize and simplify placement: |
| 10 | + |
| 11 | +```swift |
| 12 | +Rectangle([20, 10]) |
| 13 | + .aligned(at: .centerX, .bottom) |
| 14 | +``` |
| 15 | + |
| 16 | +This centers the rectangle along the X-axis and aligns its bottom edge with Y = 0. |
| 17 | + |
| 18 | +## How `.aligned(at:)` works |
| 19 | + |
| 20 | +The `.aligned(at:)` method repositions geometry by translating it so that parts of its *bounding box* align to the coordinate system origin, based on the criteria you provide. The geometry isn't clipped, resized, or modified, just moved so it aligns as requested. You can align any geometry, including complex compositions, boolean operations, or custom components. |
| 21 | + |
| 22 | +You align along one or more axes: |
| 23 | + |
| 24 | +```swift |
| 25 | +Box([30, 40, 50]) |
| 26 | + .aligned(at: .centerX, .maxY, .bottom) |
| 27 | +``` |
| 28 | + |
| 29 | +This centers the box in X, moves the back to Y = 0, and aligns the bottom of the Z axis to Z = 0. If you provide multiple alignments for the same axis, the last one wins. |
| 30 | + |
| 31 | +## Alignment Presets |
| 32 | + |
| 33 | +Cadova provides a set of readable alignment constants so you don't need to manually calculate anything. These include: |
| 34 | + |
| 35 | +- `.minX`, `.centerX`, `.maxX`, `.left`, `.right` |
| 36 | +- `.minY`, `.centerY`, `.maxY` |
| 37 | +- `.minZ`, `.centerZ`, `.maxZ` |
| 38 | +- `.top`, `.bottom` (Y axis in 2D, Z axis in 3D) |
| 39 | +- `.center` (all axes), `.centerXY` |
| 40 | + |
| 41 | +## Practical Examples |
| 42 | + |
| 43 | +### Center a rectangle |
| 44 | + |
| 45 | +```swift |
| 46 | +Rectangle([20, 10]) |
| 47 | + .aligned(at: .center) |
| 48 | +``` |
| 49 | + |
| 50 | +### Align the bottom (min Y) of a circle to the origin |
| 51 | + |
| 52 | +```swift |
| 53 | +Circle(radius: 10) |
| 54 | + .aligned(at: .bottom) |
| 55 | +``` |
| 56 | + |
| 57 | +### Center a shape horizontally and align to the top |
| 58 | + |
| 59 | +```swift |
| 60 | +Rectangle([50, 20]) |
| 61 | + .aligned(at: .centerX, .top) |
| 62 | +``` |
| 63 | + |
| 64 | +## Stack |
| 65 | + |
| 66 | +``Stack`` is a container that arranges its contents one after another along a given axis like `.x`, `.y`, or `.z`. It avoids overlap by using bounding boxes, and positions items relative to the origin using alignment on the *non-stacking* axes. |
| 67 | + |
| 68 | +### Basic Usage |
| 69 | + |
| 70 | +```swift |
| 71 | +Stack(.z, spacing: 2, alignment: .centerX) { |
| 72 | + Cylinder(radius: 5, height: 1) |
| 73 | + Box([10, 10, 3]) |
| 74 | +} |
| 75 | +``` |
| 76 | + |
| 77 | +This stacks a cylinder and a box vertically. Each item is spaced 2 mm apart, centered in X, and Y positioning is left unchanged. |
| 78 | + |
| 79 | +### Axis and Alignment |
| 80 | + |
| 81 | +- `axis` determines the direction of stacking. |
| 82 | +- `spacing` is `0` by default, meaning items touch edge-to-edge. Positive values add space between them. |
| 83 | +- `alignment` applies only to *non-stacking axes you explicitly specify*. Unspecified axes are left unchanged and the stacking axis is ignored. You can use `.center`, `.left`, `.bottom`, etc., just like with `.aligned(at:)`. |
0 commit comments