diff --git a/CHANGES.md b/CHANGES.md index aca22b109..28ad408c2 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -22,6 +22,10 @@ package called `cetz-plot`. ## Draw - Added `floating` function for drawing elements without affecting bounding boxes. +- The `ortho` function gained a `sorted` and `cull-face` argument to enable + depth ordering and face culling of drawables. Ordering is enabled by default. +- **BREAKING** Elements changed to counter clock-wise drawing order. This can + lead to changed path anchors, as the direction has changed! ## Marks - Added support for mark `anchor` style key, to adjust mark placement and @@ -45,6 +49,10 @@ package called `cetz-plot`. ## Anchors - `copy-anchors` no longer requires copied anchors to have a default, allowing the copying of an element's anchors from a group as expected. +## 3D +- Added a `prism` function that allows extending a supplied front-face + along a vector. + # 0.2.2 ## Anchors diff --git a/manual.pdf b/manual.pdf index 857e5f868..6741dc318 100644 Binary files a/manual.pdf and b/manual.pdf differ diff --git a/manual.typ b/manual.typ index e8b099d9e..351f1964b 100644 --- a/manual.typ +++ b/manual.typ @@ -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 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. diff --git a/src/draw.typ b/src/draw.typ index 53d84ba4f..ff98fde70 100644 --- a/src/draw.typ +++ b/src/draw.typ @@ -1,6 +1,7 @@ -#import "draw/grouping.typ": intersections, group, anchor, copy-anchors, place-anchors, set-ctx, get-ctx, for-each-anchor, on-layer, place-marks, hide, floating +#import "draw/grouping.typ": intersections, group, scope, anchor, copy-anchors, place-anchors, set-ctx, get-ctx, for-each-anchor, on-layer, place-marks, hide, floating #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 diff --git a/src/draw/bodies.typ b/src/draw/bodies.typ new file mode 100644 index 000000000..998debbb6 --- /dev/null +++ b/src/draw/bodies.typ @@ -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) +/// }) +/// ``` +/// +/// - front-face (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(front-face, 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, front-face)) + 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), + ) + },) +} diff --git a/src/draw/projection.typ b/src/draw/projection.typ index bf7f3a2eb..aef225c4f 100644 --- a/src/draw/projection.typ +++ b/src/draw/projection.typ @@ -4,11 +4,7 @@ #import "/src/matrix.typ" #import "/src/drawable.typ" #import "/src/util.typ" - -#let ortho-projection-matrix = ((1, 0, 0, 0), - (0, 1, 0, 0), - (0, 0, 0, 0), - (0, 0, 0, 1)) +#import "/src/polygon.typ" // Get an orthographic view matrix for 3 angles #let ortho-matrix(x, y, z) = matrix.mul-mat( @@ -18,25 +14,72 @@ matrix.transform-rotate-z(z), ) -// Pushes a view- and projection-matrix to transform -// all `body` elements. The current context transform is -// not modified. +#let ortho-projection-matrix = ( + (1, 0, 0, 0), + (0, 1, 0, 0), + (0, 0, 0, 0), + (0, 0, 0, 1), +) + +// Sort drawables by median or max segment z-value +#let _sort-by-distance(drawables) = { + return drawables.sorted(key: d => { + let z = none + for ((kind, ..pts)) in d.segments { + pts = pts.map(p => p.at(2)) + z = if z == none { + calc.max(..pts) + } else { + calc.max(z, ..pts) + } + } + return z + }) +} + +// Filter out all clock-wise polygons, or if `invert` is true, +// all counter clock-wise ones. +#let _filter-cw-faces(drawables, mode: "cw") = { + return drawables.filter(d => { + let poly = polygon.from-segments(d.segments) + poly.first() != poly.last() or polygon.winding-order(poly) == mode + }) +} + +// Sets up a view matrix to transform all `body` elements. The current context +// transform is not modified. // // - body (element): Elements // - view-matrix (matrix): View matrix // - projection-matrix (matrix): Projection matrix -// - reset-transform (bool): If true, override (and thus ignore) -// the current transformation with the new matrices instead -// of multiplying them. -#let _projection(body, view-matrix, projection-matrix, reset-transform: false) = { +// - reset-transform (bool): Ignore the current transformation matrix +// - sorted (bool): Sort drawables by maximum distance (front to back) +// - cull-face (none,string): Enable back-face culling if set to `"cw"` for clockwise +// or `"ccw"` for counter-clockwise. Polygons of the specified order will not get drawn. +#let _projection(body, view-matrix, projection-matrix, reset-transform: true, sorted: true, cull-face: "cw") = { (ctx => { let transform = ctx.transform - ctx.transform = matrix.mul-mat(projection-matrix, view-matrix) - if not reset-transform { - ctx.transform = matrix.mul-mat(transform, ctx.transform) - } + ctx.transform = view-matrix + let (ctx, drawables, bounds) = process.many(ctx, util.resolve-body(ctx, body)) + + if cull-face != none { + assert(cull-face in ("cw", "ccw"), + message: "cull-face must be none, cw or ccw.") + drawables = _filter-cw-faces(drawables, mode: cull-face) + } + if sorted { + drawables = _sort-by-distance(drawables) + } + + if projection-matrix != none { + drawables = drawable.apply-transform(projection-matrix, drawables) + } + ctx.transform = transform + if not reset-transform { + drawables = drawable.apply-transform(ctx.transform, drawables) + } return ( ctx: ctx, @@ -79,11 +122,16 @@ /// - x (angle): X-axis rotation angle /// - y (angle): Y-axis rotation angle /// - z (angle): Z-axis rotation angle +/// - sorted (bool): Sort drawables by maximum distance (front to back) +/// - cull-face (none,string): Enable back-face culling if set to `"cw"` for clockwise +/// or `"ccw"` for counter-clockwise. Polygons of the specified order will not get drawn. /// - reset-transform (bool): Ignore the current transformation matrix /// - body (element): Elements to draw -#let ortho(x: 35.264deg, y: 45deg, z: 0deg, reset-transform: false, body, name: none) = group(name: name, ctx => { - _projection(body, ortho-matrix(x, y, z), - ortho-projection-matrix, reset-transform: reset-transform) +#let ortho(x: 35.264deg, y: 45deg, z: 0deg, sorted: true, cull-face: none, reset-transform: false, body, name: none) = group(name: name, ctx => { + _projection(body, ortho-matrix(x, y, z), ortho-projection-matrix, + sorted: sorted, + cull-face: cull-face, + reset-transform: reset-transform) }) /// Draw elements on the xy-plane with optional z offset. diff --git a/src/draw/shapes.typ b/src/draw/shapes.typ index 057573bde..d214c8ad0 100644 --- a/src/draw/shapes.typ +++ b/src/draw/shapes.typ @@ -1069,10 +1069,10 @@ let (rx, ry) = radius if rx > 0 or ry > 0 { let m = 0.551784 - let p0 = (p0.at(0) * m * radius.at(0), - p0.at(1) * m * radius.at(1)) - let p1 = (p1.at(0) * m * radius.at(0), - p1.at(1) * m * radius.at(1)) + let p0 = (p0.at(0) * m * rx, + p0.at(1) * m * ry) + let p1 = (p1.at(0) * m * rx, + p1.at(1) * m * ry) (path-util.cubic-segment(s, e, vector.add(s, p0), vector.add(e, p1)),) @@ -1098,14 +1098,14 @@ let (p6, p7) = get-corner-pts(sw, (x1, y1, z), ( 1, 0), ( 0, 1)) let segments = () - segments += corner-arc(nw, p0, p1, (0, 1), (-1, 0)) - if p1 != p2 { segments += (path-util.line-segment((p1, p2)),) } - segments += corner-arc(ne, p2, p3, (1, 0), (0, 1)) - if p3 != p4 { segments += (path-util.line-segment((p3, p4)),) } - segments += corner-arc(se, p4, p5, (0, -1), (1, 0)) - if p5 != p6 { segments += (path-util.line-segment((p5, p6)),) } - segments += corner-arc(sw, p6, p7, (-1, 0), (0,-1)) - if p7 != p0 { segments += (path-util.line-segment((p7, p0)),) } + segments += corner-arc(nw, p1, p0, (-1,0), (0, 1)) + if p0 != p7 { segments += (path-util.line-segment((p0, p7)),) } + segments += corner-arc(sw, p7, p6, (0,-1), (-1,0)) + if p6 != p5 { segments += (path-util.line-segment((p6, p5)),) } + segments += corner-arc(se, p5, p4, (1, 0), (0,-1)) + if p4 != p3 { segments += (path-util.line-segment((p4, p3)),) } + segments += corner-arc(ne, p3, p2, (0, 1), (1, 0)) + if p2 != p1 { segments += (path-util.line-segment((p2, p1)),) } drawable.path(segments, fill: style.fill, stroke: style.stroke, close: true) } diff --git a/src/drawable.typ b/src/drawable.typ index 2c3a5de42..4e74c8a6f 100644 --- a/src/drawable.typ +++ b/src/drawable.typ @@ -81,23 +81,28 @@ ( path-util.cubic-segment( (x, top, z), - (right, y, z), - (x + m * rx, top, z), - (right, y + m * ry, z), + (left, y, z), + (x - m * rx, top, z), + (left, y + m * ry, z), ), path-util.cubic-segment( - (right, y, z), + (left, y, z), (x, bottom, z), - (right, y - m * ry, z), - (x + m * rx, bottom, z), + (left, y - m * ry, z), + (x - m * rx, bottom, z), ), path-util.cubic-segment( (x, bottom, z), - (left, y, z), - (x - m * rx, bottom, z), - (left, y - m * ry, z), + (right, y, z), + (x + m * rx, bottom, z), + (right, y - m * ry, z), + ), + path-util.cubic-segment( + (right, y, z), + (x, top, z), + (right, y + m * ry, z), + (x + m * rx, top, z) ), - path-util.cubic-segment((left, y, z), (x, top, z), (left, y + m * ry, z), (x - m * rx, top, z)), ), stroke: stroke, fill: fill, diff --git a/src/polygon.typ b/src/polygon.typ new file mode 100644 index 000000000..99955f674 --- /dev/null +++ b/src/polygon.typ @@ -0,0 +1,59 @@ +/// Returns a list of polygon points from +/// a list of segments. +/// +/// Cubic segments get linearized by sampling. +/// +/// - segment (list): List of segments +/// - samples (int): Number of samples +/// -> List of vectors +#let from-segments(segments, samples: 10) = { + import "/src/bezier.typ": cubic-point + let poly = () + for ((kind, ..pts)) in segments { + if kind == "cubic" { + poly += range(0, samples).map(t => { + cubic-point(..pts, t / (samples - 1)) + }) + } else { + poly += pts + } + } + return poly +} + +/// Computes the signed area of a 2D polygon. +/// +/// The formula used is the following: +/// $ 1/2 sum_i=0^n-1 x_i*y_i+1 - x_i+1*y_i $ +/// +/// - points (list): List of Vectors of dimension >= 2 +/// -> Signed area +#let signed-area(points) = { + let a = 0 + let n = points.len() + let (cx, cy) = (0, 0) + for i in range(0, n) { + let (x0, y0, ..) = points.at(i) + let (x1, y1, ..) = points.at(calc.rem(i + 1, n)) + cx += (x0 + x1) * (x0 * y1 - x1 * y0) + cy += (y0 + y1) * (x0 * y1 - x1 * y0) + a += x0 * y1 - x1 * y0 + } + return .5 * a +} + +/// Returns the winding order of a 2D polygon +/// by using it's signed area. +/// +/// - point (list): List of polygon points +/// -> "ccw" (counter clock-wise) or "cw" (clock-wise) or none +#let winding-order(points) = { + let area = signed-area(points) + if area > 0 { + "cw" + } else if area < 0 { + "ccw" + } else { + none + } +} diff --git a/src/styles.typ b/src/styles.typ index 72db88e4b..043447b81 100644 --- a/src/styles.typ +++ b/src/styles.typ @@ -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. diff --git a/tests/anchor/copy-anchors/ref/1.png b/tests/anchor/copy-anchors/ref/1.png index 9ce8cbe2a..25f7c59c0 100644 Binary files a/tests/anchor/copy-anchors/ref/1.png and b/tests/anchor/copy-anchors/ref/1.png differ diff --git a/tests/anchor/element-anchors/ref/1.png b/tests/anchor/element-anchors/ref/1.png index eaba7b51c..b99393bf3 100644 Binary files a/tests/anchor/element-anchors/ref/1.png and b/tests/anchor/element-anchors/ref/1.png differ diff --git a/tests/anchor/path-anchors/ref/1.png b/tests/anchor/path-anchors/ref/1.png index 12e849db6..4c01edc1b 100644 Binary files a/tests/anchor/path-anchors/ref/1.png and b/tests/anchor/path-anchors/ref/1.png differ diff --git a/tests/arc/last-pos/ref/1.png b/tests/arc/last-pos/ref/1.png index 988655e87..53573e042 100644 Binary files a/tests/arc/last-pos/ref/1.png and b/tests/arc/last-pos/ref/1.png differ diff --git a/tests/arc/ref/1.png b/tests/arc/ref/1.png index 10dcda4c5..f28cb4276 100644 Binary files a/tests/arc/ref/1.png and b/tests/arc/ref/1.png differ diff --git a/tests/bezier/ref/1.png b/tests/bezier/ref/1.png index c662ddf6b..ccd1af394 100644 Binary files a/tests/bezier/ref/1.png and b/tests/bezier/ref/1.png differ diff --git a/tests/bodies/ref/1.png b/tests/bodies/ref/1.png new file mode 100644 index 000000000..27cb924e0 Binary files /dev/null and b/tests/bodies/ref/1.png differ diff --git a/tests/bodies/test.typ b/tests/bodies/test.typ new file mode 100644 index 000000000..d1997dacf --- /dev/null +++ b/tests/bodies/test.typ @@ -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) + }) +}) diff --git a/tests/bounds/ref/1.png b/tests/bounds/ref/1.png index d50ed2242..c70727f74 100644 Binary files a/tests/bounds/ref/1.png and b/tests/bounds/ref/1.png differ diff --git a/tests/catmul/ref/1.png b/tests/catmul/ref/1.png index 9f02e6a5b..eb25c7534 100644 Binary files a/tests/catmul/ref/1.png and b/tests/catmul/ref/1.png differ diff --git a/tests/circle-through/ref/1.png b/tests/circle-through/ref/1.png index 33bc6b0e5..ad27b94e6 100644 Binary files a/tests/circle-through/ref/1.png and b/tests/circle-through/ref/1.png differ diff --git a/tests/content/intersection/ref/1.png b/tests/content/intersection/ref/1.png index e151207ca..b01c8ac81 100644 Binary files a/tests/content/intersection/ref/1.png and b/tests/content/intersection/ref/1.png differ diff --git a/tests/content/span/ref/1.png b/tests/content/span/ref/1.png index 701b15ec0..1ba67dbe6 100644 Binary files a/tests/content/span/ref/1.png and b/tests/content/span/ref/1.png differ diff --git a/tests/content/transform/ref/1.png b/tests/content/transform/ref/1.png index b769e4a05..3107f6350 100644 Binary files a/tests/content/transform/ref/1.png and b/tests/content/transform/ref/1.png differ diff --git a/tests/cube/ref/1.png b/tests/cube/ref/1.png index 1e593aaf5..0d2a5b70e 100644 Binary files a/tests/cube/ref/1.png and b/tests/cube/ref/1.png differ diff --git a/tests/decorations/path/ref/1.png b/tests/decorations/path/ref/1.png index 4789705fc..619d1068e 100644 Binary files a/tests/decorations/path/ref/1.png and b/tests/decorations/path/ref/1.png differ diff --git a/tests/decorations/ref/1.png b/tests/decorations/ref/1.png index f88cd9fa5..a7bdfa0c8 100644 Binary files a/tests/decorations/ref/1.png and b/tests/decorations/ref/1.png differ diff --git a/tests/empty/ref/1.png b/tests/empty/ref/1.png index 903f45eaf..b96d5274d 100644 Binary files a/tests/empty/ref/1.png and b/tests/empty/ref/1.png differ diff --git a/tests/floating/ref/1.png b/tests/floating/ref/1.png index 155ed7150..925095244 100644 Binary files a/tests/floating/ref/1.png and b/tests/floating/ref/1.png differ diff --git a/tests/grid/ref/1.png b/tests/grid/ref/1.png index 4e25ea682..4c049a60c 100644 Binary files a/tests/grid/ref/1.png and b/tests/grid/ref/1.png differ diff --git a/tests/group/empty/ref/1.png b/tests/group/empty/ref/1.png index 903f45eaf..b96d5274d 100644 Binary files a/tests/group/empty/ref/1.png and b/tests/group/empty/ref/1.png differ diff --git a/tests/group/none/ref/1.png b/tests/group/none/ref/1.png index 84d3a6ba3..797166170 100644 Binary files a/tests/group/none/ref/1.png and b/tests/group/none/ref/1.png differ diff --git a/tests/group/padding/ref/1.png b/tests/group/padding/ref/1.png index 5dbf01fbd..e233e677c 100644 Binary files a/tests/group/padding/ref/1.png and b/tests/group/padding/ref/1.png differ diff --git a/tests/group/transform/ref/1.png b/tests/group/transform/ref/1.png index 572692f95..78eafa4e0 100644 Binary files a/tests/group/transform/ref/1.png and b/tests/group/transform/ref/1.png differ diff --git a/tests/hobby/ref/1.png b/tests/hobby/ref/1.png index fff1fd3a8..f256f9f59 100644 Binary files a/tests/hobby/ref/1.png and b/tests/hobby/ref/1.png differ diff --git a/tests/line/element-element/ref/1.png b/tests/line/element-element/ref/1.png index 7d7d271ee..c0395f017 100644 Binary files a/tests/line/element-element/ref/1.png and b/tests/line/element-element/ref/1.png differ diff --git a/tests/local-anchor/ref/1.png b/tests/local-anchor/ref/1.png index 1e06026c1..06529ab45 100644 Binary files a/tests/local-anchor/ref/1.png and b/tests/local-anchor/ref/1.png differ diff --git a/tests/mark/anchor/ref/1.png b/tests/mark/anchor/ref/1.png index f583f1cb0..4b94d61e1 100644 Binary files a/tests/mark/anchor/ref/1.png and b/tests/mark/anchor/ref/1.png differ diff --git a/tests/mark/auto-offset/ref/1.png b/tests/mark/auto-offset/ref/1.png index 0077a92bd..d5d310943 100644 Binary files a/tests/mark/auto-offset/ref/1.png and b/tests/mark/auto-offset/ref/1.png differ diff --git a/tests/mark/offset/ref/1.png b/tests/mark/offset/ref/1.png index 3242b231c..5e09ff352 100644 Binary files a/tests/mark/offset/ref/1.png and b/tests/mark/offset/ref/1.png differ diff --git a/tests/mark/pos/ref/1.png b/tests/mark/pos/ref/1.png index 6f5b91ed2..adfcbe50e 100644 Binary files a/tests/mark/pos/ref/1.png and b/tests/mark/pos/ref/1.png differ diff --git a/tests/mark/shape-transform/ref/1.png b/tests/mark/shape-transform/ref/1.png index 0ba5a5ff2..d5c465088 100644 Binary files a/tests/mark/shape-transform/ref/1.png and b/tests/mark/shape-transform/ref/1.png differ diff --git a/tests/mark/single/ref/1.png b/tests/mark/single/ref/1.png index 9abf3e0af..5144a3464 100644 Binary files a/tests/mark/single/ref/1.png and b/tests/mark/single/ref/1.png differ diff --git a/tests/mark/z-axis/ref/1.png b/tests/mark/z-axis/ref/1.png index 481fd6414..e5561271c 100644 Binary files a/tests/mark/z-axis/ref/1.png and b/tests/mark/z-axis/ref/1.png differ diff --git a/tests/merge/ref/1.png b/tests/merge/ref/1.png index 31a03557c..ae597546a 100644 Binary files a/tests/merge/ref/1.png and b/tests/merge/ref/1.png differ diff --git a/tests/palette/ref/1.png b/tests/palette/ref/1.png index 858b4dc71..e4368156d 100644 Binary files a/tests/palette/ref/1.png and b/tests/palette/ref/1.png differ diff --git a/tests/primitives/ref/1.png b/tests/primitives/ref/1.png index 065c9a5d3..d05113357 100644 Binary files a/tests/primitives/ref/1.png and b/tests/primitives/ref/1.png differ diff --git a/tests/projection/ortho/ref/1.png b/tests/projection/ortho/ref/1.png index 44bf7cc57..cf7de379f 100644 Binary files a/tests/projection/ortho/ref/1.png and b/tests/projection/ortho/ref/1.png differ diff --git a/tests/projection/ortho/test.typ b/tests/projection/ortho/test.typ index 7c2258a33..a5949f8ea 100644 --- a/tests/projection/ortho/test.typ +++ b/tests/projection/ortho/test.typ @@ -7,14 +7,16 @@ set-style(mark: (end: ">")) - line((-l,0), (l,0), stroke: red, name: "x") - content((rel: ((name: "x", anchor: 50%), .5, "x.end"), to: "x.end"), text(red, $x$)) + on-layer(-1, { + line((-l,0), (l,0), stroke: red, name: "x") + content((rel: ((name: "x", anchor: 50%), .5, "x.end"), to: "x.end"), text(red, $x$)) - line((0,-l), (0,l), stroke: blue, name: "y") - content((rel: ((name: "y", anchor: 50%), .5, "y.end"), to: "y.end"), text(blue, $y$)) + line((0,-l), (0,l), stroke: blue, name: "y") + content((rel: ((name: "y", anchor: 50%), .5, "y.end"), to: "y.end"), text(blue, $y$)) - line((0,0,-l), (0,0,l), stroke: green, name: "z", mark: (z-up: (1,0,0))) - content((rel: ((name: "z", anchor: 50%), .5, "z.end"), to: "z.end"), text(green, $z$)) + line((0,0,-l), (0,0,l), stroke: green, name: "z", mark: (z-up: (1,0,0))) + content((rel: ((name: "z", anchor: 50%), .5, "z.end"), to: "z.end"), text(green, $z$)) + }) } #let checkerboard() = { @@ -27,6 +29,13 @@ } } +#test-case({ + import draw: * + ortho(reset-transform: false, { + line((-1, 0), (1, 0), mark: (end: ">")) + }) +}) + #test-case({ import draw: * ortho({ @@ -67,7 +76,7 @@ #test-case({ import draw: * - ortho({ + ortho(sorted: true, { axes(4) on-yz(x: -1, { checkerboard() @@ -80,3 +89,61 @@ }) }) }) + +// Ordering +#test-case({ + import draw: * + ortho(sorted: true, { + scope({ translate((0, 0, +1)); rect((-1, -1), (1, 1), fill: blue) }) + scope({ translate((0, 0, 0)); rect((-1, -1), (1, 1), fill: red) }) + scope({ translate((0, 0, -1)); rect((-1, -1), (1, 1), fill: green) }) + }) +}) + +// Fully visible +#test-case({ + import draw: * + ortho(x: 0deg, y: 0deg, cull-face: "cw", { + line((-1, -1), (1, -1), (1, 1), (-1, 1), close: true) + line((-1,-1), (1,-1), (0,1), close: true) + }) +}) + +// Nothing visible +#test-case({ + import draw: * + ortho(x: 0deg, y: 0deg, cull-face: "cw", { + line((-1, -1), (1, -1), (1, 1), (-1, 1), close: true) + rotate(y: 120deg) + line((-1,-1), (1,-1), (0,1), close: true) + }) +}) + +// Face order of library shapes +#test-case({ + import draw: * + ortho(cull-face: "cw", { + rect((-1, -1), (1, 1), radius: .5) + }) +}) + +#test-case({ + import draw: * + ortho(cull-face: "cw", { + circle((0,0)) + }) +}) + +#test-case({ + import draw: * + ortho(cull-face: "cw", { + arc((0,0), start: 0deg, stop: 270deg, mode: "PIE") + }) +}) + +#test-case({ + import draw: * + ortho(cull-face: "cw", { + content((0,0), [Text]) + }) +}) diff --git a/tests/rect/ref/1.png b/tests/rect/ref/1.png index 03f94bd02..58051b331 100644 Binary files a/tests/rect/ref/1.png and b/tests/rect/ref/1.png differ diff --git a/tests/rect/rounded/ref/1.png b/tests/rect/rounded/ref/1.png index 4e4fa9050..8a2c962fd 100644 Binary files a/tests/rect/rounded/ref/1.png and b/tests/rect/rounded/ref/1.png differ diff --git a/tests/relative-no-update/ref/1.png b/tests/relative-no-update/ref/1.png index 0f905e6b4..73d80b14d 100644 Binary files a/tests/relative-no-update/ref/1.png and b/tests/relative-no-update/ref/1.png differ diff --git a/tests/ring/ref/1.png b/tests/ring/ref/1.png index 257811949..5bc6065a5 100644 Binary files a/tests/ring/ref/1.png and b/tests/ring/ref/1.png differ diff --git a/tests/rotation/around/ref/1.png b/tests/rotation/around/ref/1.png index 8ad7b7a6d..4d4238bd0 100644 Binary files a/tests/rotation/around/ref/1.png and b/tests/rotation/around/ref/1.png differ diff --git a/tests/rotation/ref/1.png b/tests/rotation/ref/1.png index 5c5812182..78c466e11 100644 Binary files a/tests/rotation/ref/1.png and b/tests/rotation/ref/1.png differ diff --git a/tests/set-get-ctx/ref/1.png b/tests/set-get-ctx/ref/1.png index 01f5c6a1d..751725c22 100644 Binary files a/tests/set-get-ctx/ref/1.png and b/tests/set-get-ctx/ref/1.png differ diff --git a/tests/style/ref/1.png b/tests/style/ref/1.png index 0f7fe0e11..27c549942 100644 Binary files a/tests/style/ref/1.png and b/tests/style/ref/1.png differ diff --git a/tests/transform/precission/ref/1.png b/tests/transform/precission/ref/1.png index 930b6859d..4635d6cd9 100644 Binary files a/tests/transform/precission/ref/1.png and b/tests/transform/precission/ref/1.png differ