Skip to content

Commit

Permalink
bodies: Add a prism function
Browse files Browse the repository at this point in the history
  • Loading branch information
johannes-wolf committed Jul 19, 2024
1 parent e931c83 commit d011382
Show file tree
Hide file tree
Showing 7 changed files with 172 additions and 0 deletions.
Binary file modified manual.pdf
Binary file not shown.
4 changes: 4 additions & 0 deletions manual.typ
Original file line number Diff line number Diff line change
Expand Up @@ -311,6 +311,10 @@ $ M_"world" = M_"world" dot M_"local" $

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

== Bodies

#doc-style.parse-show-module("/src/draw/bodies.typ")

= Coordinate Systems <coordinate-systems>
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.

Expand Down
1 change: 1 addition & 0 deletions src/draw.typ
Original file line number Diff line number Diff line change
Expand Up @@ -2,5 +2,6 @@
#import "draw/transformations.typ": set-transform, rotate, translate, scale, set-origin, move-to, set-viewport
#import "draw/styling.typ": set-style, fill, stroke
#import "draw/shapes.typ": circle, circle-through, arc, arc-through, mark, line, grid, content, rect, bezier, bezier-through, catmull, hobby, merge-path
#import "draw/bodies.typ": prism
#import "draw/projection.typ": ortho, on-xy, on-xz, on-yz
#import "draw/util.typ": assert-version
101 changes: 101 additions & 0 deletions src/draw/bodies.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
#import "/src/coordinate.typ"
#import "/src/drawable.typ"
#import "/src/styles.typ"
#import "/src/path-util.typ"
#import "/src/util.typ"
#import "/src/vector.typ"
#import "/src/matrix.typ"
#import "/src/process.typ"
#import "/src/polygon.typ"

/// Draw a prism by extending a single element
/// into a direction.
///
/// Curved shapes get sampled into linear ones.
///
/// = parameters
///
/// = Styling
/// *Root:* `prism`
/// == Keys
/// #show-parameter-block("front-stroke", ("stroke", "none"), [Front-face stroke], default: auto)
/// #show-parameter-block("front-fill", ("fill", "none"), [Front-face fill], default: auto)
/// #show-parameter-block("back-stroke", ("stroke", "none"), [Back-face stroke], default: auto)
/// #show-parameter-block("back-fill", ("fill", "none"), [Back-face fill], default: auto)
/// #show-parameter-block("side-stroke", ("stroke", "none"), [Side stroke], default: auto)
/// #show-parameter-block("side-fill", ("fill", "none"), [Side fill], default: auto)
///
/// ```example
/// ortho({
/// // Draw a cube with and edge length of 2
/// prism({
/// rect((-1, -1), (rel: (2, 2)))
/// }, 2)
/// })
/// ```
///
/// - body (elements): A single element to use as front-face
/// - dir (number,vector): Z-distance or direction vector to extend
/// the front-face along
/// - samples (int): Number of samples to use for sampling curves
#let prism(body, dir, samples: 10, ..style) = {
assert.eq(style.pos(), (),
message: "Prism takes no positional arguments")

let style = style.named()
(ctx => {
let transform = ctx.transform
ctx.transform = matrix.ident()
let (ctx, drawables, bounds) = process.many(ctx, util.resolve-body(ctx, body))
ctx.transform = transform

assert.eq(drawables.len(), 1,
message: "Prism shape must be a single drawable.")

let points = polygon.from-segments(drawables.first().segments, samples: samples)

let style = styles.resolve(ctx.style, merge: style, root: "prism")

// Normal to extend the front face along
let n = if type(dir) == array {
dir.map(util.resolve-number.with(ctx))
} else {
(0, 0, util.resolve-number(ctx, dir))
}

let stroke = (:)
let fill = (:)
for face in ("front", "back", "side") {
stroke.insert(face, style.at("stroke-" + face, default: style.stroke))
fill.insert(face, style.at("fill-" + face, default: style.fill))
}

let drawables = ()
let back-points = util.apply-transform(matrix.transform-translate(..n), ..points)

// Back
let back = drawable.path(path-util.line-segment(back-points.rev()),
close: true, stroke: stroke.back, fill: fill.back)
drawables.push(back)

// Sides
for i in range(0, points.len()) {
let k = calc.rem(i + 1, points.len())

let quad = (points.at(i), back-points.at(i), back-points.at(k), points.at(k))
let side = drawable.path(path-util.line-segment(quad),
close: true, stroke: stroke.side, fill: fill.side)
drawables.push(side)
}

// Front
let front = drawable.path(path-util.line-segment(points),
close: true, stroke: stroke.front, fill: fill.front)
drawables.push(front)

return (
ctx: ctx,
drawables: drawable.apply-transform(ctx.transform, drawables),
)
},)
}
4 changes: 4 additions & 0 deletions src/styles.typ
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@
fill: auto,
stroke: auto,
),
prism: (
stroke: auto,
fill: auto,
),
)

/// 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.
Expand Down
Binary file added tests/bodies/ref/1.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
62 changes: 62 additions & 0 deletions tests/bodies/test.typ
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
#set page(width: auto, height: auto)
#import "/src/lib.typ": *
#import "/tests/helper.typ": *

#let h-test-case = test-case
#let test-case(body) = h-test-case({
draw.set-style(stroke: (join: "round"))
body
})

#test-case({
import draw: *
prism({ rect((-1, -1), (1, 1)) }, 1)
})

#test-case({
import draw: *
prism({
circle((0,0))
}, samples: 3, 1)
})

#test-case({
import draw: *
set-style(prism: (
fill-back: blue,
fill-front: red,
fill-side: yellow,
))
ortho(cull-face: "cw", {
prism({
line((-1, -1), (1, -1), (0, 1), close: true)
}, -2)
translate((3, 0, 0))
rotate(y: 160deg)
prism({
line((-1, -1), (1, -1), (0, 0), close: true)
}, -2)
})
})

#test-case({
import draw: *
ortho(x: 10deg, y: 30deg, {
prism({
translate((1,0,0))
rect((-1, -1), (1, 1))
}, 2)
prism({
translate((-2,0,0))
rect((-1, -1), (1, 1))
}, 2)
prism({
translate((1,0,-3))
rect((-1, -1), (1, 1))
}, 2)
prism({
translate((-2,0,-3))
rect((-1, -1), (1, 1))
}, 2)
})
})

0 comments on commit d011382

Please sign in to comment.