Skip to content

Commit 6ba7335

Browse files
committed
bodies: Add a prism function
1 parent e931c83 commit 6ba7335

File tree

7 files changed

+172
-0
lines changed

7 files changed

+172
-0
lines changed

manual.pdf

-187 KB
Binary file not shown.

manual.typ

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -311,6 +311,10 @@ $ M_"world" = M_"world" dot M_"local" $
311311

312312
#doc-style.parse-show-module("/src/draw/projection.typ")
313313

314+
== Bodies
315+
316+
#doc-style.parse-show-module("/src/draw/bodies.typ")
317+
314318
= Coordinate Systems <coordinate-systems>
315319
A _coordinate_ is a position on the canvas on which the picture is drawn. They take the form of dictionaries and the following sub-sections define the key value pairs for each system. Some systems have a more implicit form as an array of values and `CeTZ` attempts to infer the system based on the element types.
316320

src/draw.typ

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,6 @@
22
#import "draw/transformations.typ": set-transform, rotate, translate, scale, set-origin, move-to, set-viewport
33
#import "draw/styling.typ": set-style, fill, stroke
44
#import "draw/shapes.typ": circle, circle-through, arc, arc-through, mark, line, grid, content, rect, bezier, bezier-through, catmull, hobby, merge-path
5+
#import "draw/bodies.typ": prism
56
#import "draw/projection.typ": ortho, on-xy, on-xz, on-yz
67
#import "draw/util.typ": assert-version

src/draw/bodies.typ

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
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+
}

src/styles.typ

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,10 @@
129129
fill: auto,
130130
stroke: auto,
131131
),
132+
prism: (
133+
stroke: auto,
134+
fill: auto,
135+
),
132136
)
133137

134138
/// You can use this to combine the style in `ctx`, the style given by a user for a single element and an element's default style.

tests/bodies/ref/1.png

19.5 KB
Loading

tests/bodies/test.typ

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
#set page(width: auto, height: auto)
2+
#import "/src/lib.typ": *
3+
#import "/tests/helper.typ": *
4+
5+
#let h-test-case = test-case
6+
#let test-case(body) = h-test-case({
7+
draw.set-style(stroke: (join: "round"))
8+
body
9+
})
10+
11+
#test-case({
12+
import draw: *
13+
prism({ rect((-1, -1), (1, 1)) }, 1)
14+
})
15+
16+
#test-case({
17+
import draw: *
18+
prism({
19+
circle((0,0))
20+
}, samples: 3, 1)
21+
})
22+
23+
#test-case({
24+
import draw: *
25+
set-style(prism: (
26+
fill-back: blue,
27+
fill-front: red,
28+
fill-side: yellow,
29+
))
30+
ortho(cull-face: "cw", {
31+
prism({
32+
line((-1, -1), (1, -1), (0, 1), close: true)
33+
}, -2)
34+
translate((3, 0, 0))
35+
rotate(y: 160deg)
36+
prism({
37+
line((-1, -1), (1, -1), (0, 0), close: true)
38+
}, -2)
39+
})
40+
})
41+
42+
#test-case({
43+
import draw: *
44+
ortho(x: 10deg, y: 30deg, {
45+
prism({
46+
translate((1,0,0))
47+
rect((-1, -1), (1, 1))
48+
}, 2)
49+
prism({
50+
translate((-2,0,0))
51+
rect((-1, -1), (1, 1))
52+
}, 2)
53+
prism({
54+
translate((1,0,-3))
55+
rect((-1, -1), (1, 1))
56+
}, 2)
57+
prism({
58+
translate((-2,0,-3))
59+
rect((-1, -1), (1, 1))
60+
}, 2)
61+
})
62+
})

0 commit comments

Comments
 (0)