|
| 1 | +#import "/src/coordinate.typ" |
| 2 | +#import "/src/drawable.typ" |
| 3 | +#import "/src/styles.typ" |
| 4 | +#import "/src/path-util.typ" |
| 5 | +#import "/src/util.typ" |
| 6 | +#import "/src/vector.typ" |
| 7 | +#import "/src/matrix.typ" |
| 8 | +#import "/src/process.typ" |
| 9 | +#import "/src/polygon.typ" |
| 10 | + |
| 11 | +/// Draw a prism by extending a single element |
| 12 | +/// into a direction. |
| 13 | +/// |
| 14 | +/// Curved shapes get sampled into linear ones. |
| 15 | +/// |
| 16 | +/// = parameters |
| 17 | +/// |
| 18 | +/// = Styling |
| 19 | +/// *Root:* `prism` |
| 20 | +/// == Keys |
| 21 | +/// #show-parameter-block("front-stroke", ("stroke", "none"), [Front-face stroke], default: auto) |
| 22 | +/// #show-parameter-block("front-fill", ("fill", "none"), [Front-face fill], default: auto) |
| 23 | +/// #show-parameter-block("back-stroke", ("stroke", "none"), [Back-face stroke], default: auto) |
| 24 | +/// #show-parameter-block("back-fill", ("fill", "none"), [Back-face fill], default: auto) |
| 25 | +/// #show-parameter-block("side-stroke", ("stroke", "none"), [Side stroke], default: auto) |
| 26 | +/// #show-parameter-block("side-fill", ("fill", "none"), [Side fill], default: auto) |
| 27 | +/// |
| 28 | +/// ```example |
| 29 | +/// ortho({ |
| 30 | +/// // Draw a cube with and edge length of 2 |
| 31 | +/// prism({ |
| 32 | +/// rect((-1, -1), (rel: (2, 2))) |
| 33 | +/// }, 2) |
| 34 | +/// }) |
| 35 | +/// ``` |
| 36 | +/// |
| 37 | +/// - front-face (elements): A single element to use as front-face |
| 38 | +/// - dir (number,vector): Z-distance or direction vector to extend |
| 39 | +/// the front-face along |
| 40 | +/// - samples (int): Number of samples to use for sampling curves |
| 41 | +#let prism(front-face, dir, samples: 10, ..style) = { |
| 42 | + assert.eq(style.pos(), (), |
| 43 | + message: "Prism takes no positional arguments") |
| 44 | + |
| 45 | + let style = style.named() |
| 46 | + (ctx => { |
| 47 | + let transform = ctx.transform |
| 48 | + ctx.transform = matrix.ident() |
| 49 | + let (ctx, drawables, bounds) = process.many(ctx, util.resolve-body(ctx, front-face)) |
| 50 | + ctx.transform = transform |
| 51 | + |
| 52 | + assert.eq(drawables.len(), 1, |
| 53 | + message: "Prism shape must be a single drawable.") |
| 54 | + |
| 55 | + let points = polygon.from-segments(drawables.first().segments, samples: samples) |
| 56 | + |
| 57 | + let style = styles.resolve(ctx.style, merge: style, root: "prism") |
| 58 | + |
| 59 | + // Normal to extend the front face along |
| 60 | + let n = if type(dir) == array { |
| 61 | + dir.map(util.resolve-number.with(ctx)) |
| 62 | + } else { |
| 63 | + (0, 0, util.resolve-number(ctx, dir)) |
| 64 | + } |
| 65 | + |
| 66 | + let stroke = (:) |
| 67 | + let fill = (:) |
| 68 | + for face in ("front", "back", "side") { |
| 69 | + stroke.insert(face, style.at("stroke-" + face, default: style.stroke)) |
| 70 | + fill.insert(face, style.at("fill-" + face, default: style.fill)) |
| 71 | + } |
| 72 | + |
| 73 | + let drawables = () |
| 74 | + let back-points = util.apply-transform(matrix.transform-translate(..n), ..points) |
| 75 | + |
| 76 | + // Back |
| 77 | + let back = drawable.path(path-util.line-segment(back-points.rev()), |
| 78 | + close: true, stroke: stroke.back, fill: fill.back) |
| 79 | + drawables.push(back) |
| 80 | + |
| 81 | + // Sides |
| 82 | + for i in range(0, points.len()) { |
| 83 | + let k = calc.rem(i + 1, points.len()) |
| 84 | + |
| 85 | + let quad = (points.at(i), back-points.at(i), back-points.at(k), points.at(k)) |
| 86 | + let side = drawable.path(path-util.line-segment(quad), |
| 87 | + close: true, stroke: stroke.side, fill: fill.side) |
| 88 | + drawables.push(side) |
| 89 | + } |
| 90 | + |
| 91 | + // Front |
| 92 | + let front = drawable.path(path-util.line-segment(points), |
| 93 | + close: true, stroke: stroke.front, fill: fill.front) |
| 94 | + drawables.push(front) |
| 95 | + |
| 96 | + return ( |
| 97 | + ctx: ctx, |
| 98 | + drawables: drawable.apply-transform(ctx.transform, drawables), |
| 99 | + ) |
| 100 | + },) |
| 101 | +} |
0 commit comments