Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Update Angle Library #330

Merged
merged 6 commits into from
Nov 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions src/draw/shapes.typ
Original file line number Diff line number Diff line change
Expand Up @@ -864,6 +864,8 @@

#let merge-path(body, close: false, name: none, ..style) = {
// No extra positional arguments from the style sink
assert(type(body) in (array, function),
message: "Incorrect type for body: " + type(body))
assert.eq(
style.pos(),
(),
Expand All @@ -875,6 +877,7 @@
ctx => {
let ctx = ctx
let segments = ()
let body = if type(body) == function { body(ctx) } else { body }
for element in body {
let r = process.element(ctx, element)
if r != none {
Expand Down
171 changes: 74 additions & 97 deletions src/lib/angle.typ
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#import "../util.typ"
#import "../coordinate.typ"
#import "../anchor.typ" as anchor_
#import "/src/draw.typ"

// Angle default-style
#let default-style = (
Expand All @@ -14,6 +15,29 @@
mark: styles.default.mark,
)

/// Draw an angle between `a` and `b` through origin `origin`
///
/// *Style Root:* `angle`
///
/// *Anchors*
/// / `"a"`: Point a
/// / `"b"`: Point b
/// / `"origin"`: Origin
/// / `"label"`: Label center
/// / `"start"`: Arc start
/// / `"end"`: Arc end
///
/// You can use the `radius` and `label-radius` style-keys to set
/// the angle and label radius.
///
/// - origin (coordinate): Angle origin
/// - a (coordinate): Coordinate of side a
/// - b (coordinate): Coordinate of side b
/// - inner (bool): Draw the smaller (inner) angle
/// - label (none,content,function): Draw a label at the angles "label" anchor.
/// If label is a function, it gets the angle value passed as argument.
/// - name: (none,string): Element value
/// - ..style (style): Style
#let angle(
origin,
a,
Expand All @@ -22,112 +46,65 @@
label: none,
name: none,
..style
) = {
let style = style.named()
) = draw.group(name: name, ctx => {
let style = styles.resolve(ctx.style, style.named(), base: default-style, root: "angle")
let (ctx, origin, a, b) = coordinate.resolve(ctx, origin, a, b)

return (ctx => {
let style = styles.resolve(ctx.style, style, root: "angle", base: default-style)
let (ctx, origin, a, b) = coordinate.resolve(ctx, origin, a, b)
assert(
origin.at(2, default: 0) == 0 and
a.at(2, default: 0) == 0 and
b.at(2, default: 0) == 0,
message: "FIXME: Angle only works for 2D coordinates."
)
let (s, e, ss) = {
let s = vector.angle2(origin, a) * -1
if s < 0deg { s += 360deg }
let e = vector.angle2(origin, b) * -1
if e < 0deg { e += 360deg }
assert(origin.at(2) == a.at(2) and a.at(2) == b.at(2),
message: "Angle z coordinates of all three points must be equal")

if s > e {
(s, e) = (e, s)
}
let (s, e, ss) = {
let s = vector.angle2(origin, a) * -1
if s < 0deg { s += 360deg }
let e = vector.angle2(origin, b) * -1
if e < 0deg { e += 360deg }

if s > e {
(s, e) = (e, s)
}

if inner == true {
let d = vector.angle(a, origin, b)
if e - s > 180deg {
(s, e) = (e, e + d)
} else {
(s, e) = (s, s + d)
}
} else if inner == false {
if e - s < 180deg {
let d = 360deg - vector.angle(a, origin, b)
(s, e) = (e, e + d)
}
if inner == true {
let d = vector.angle(a, origin, b)
if e - s > 180deg {
(s, e) = (e, e + d)
} else {
(s, e) = (s, s + d)
}
} else if inner == false {
if e - s < 180deg {
let d = 360deg - vector.angle(a, origin, b)
(s, e) = (e, e + d)
}
(s, e, (s + e) / 2)
}
let (x, y, z) = origin
let (r, _) = util.resolve-radius(style.radius).map(util.resolve-number.with(ctx))
let (ra, _) = util.resolve-radius(style.label-radius).map(util.resolve-number.with(ctx))
let start = (x + r * calc.cos(s), y + r * calc.sin(s), z)
let end = (x + r * calc.cos(e), y + r * calc.sin(e), z)
let pt-label = (x + ra * calc.cos(ss), y + ra * calc.sin(ss), z)
(s, e, (s + e) / 2)
}

let drawables = ()
let (r, _) = util.resolve-radius(style.radius).map(util.resolve-number.with(ctx))
let (ra, _) = util.resolve-radius(style.label-radius).map(util.resolve-number.with(ctx))

let (marks, draw-pt, draw-s, draw-e) = if style.mark != none {
import "/src/mark.typ" as mark_
mark_.place-marks-along-arc(ctx, s, e, start, r, r, style, style.mark)
} else {
(none, start, s, e)
}
let label-pt = vector.add(origin, (calc.cos(ss) * ra, calc.sin(ss) * ra, 0))
let start-pt = vector.add(origin, (calc.cos(s) * r, calc.sin(s) * r, 0))
let end-pt = vector.add(origin, (calc.cos(e) * r, calc.sin(e) * r, 0))
draw.anchor("origin", origin)
draw.anchor("label", label-pt)
draw.anchor("start", start-pt)
draw.anchor("end", end-pt)
draw.anchor("a", a)
draw.anchor("b", b)

if s != e {
if style.fill != none {
drawables.push(
drawable.arc(..draw-pt, draw-s, draw-e, r, r, mode: "PIE", fill: style.fill, stroke: none)
)
draw.arc(origin, start: s, stop: e, anchor: "origin",
name: "arc", ..style, radius: r, mode: "PIE", mark: none, stroke: none)
}
if style.stroke != none {
drawables.push(
drawable.arc(..draw-pt, draw-s, draw-e, r, r, mode: "OPEN", fill: none, stroke: style.stroke)
)
}
if marks != none {
drawables += marks
draw.arc(origin, start: s, stop: e, anchor: "origin",
name: "arc", ..style, radius: r, fill: none)
}
}

let (x, y, z) = start
let label = if type(label) == function { label(e - s) } else { label }
if label != none {
let (lx, ly, ..) = pt-label
let (w, h) = util.measure(ctx, label)
drawables.push(
drawable.content(
(lx, ly, 0),
w,
h,
label
)
)
}

let (transform, anchors) = anchor_.setup(
anchor => {
(
origin: origin,
a: a,
b: b,
start: start,
end: end,
label: pt-label
).at(anchor)
},
("origin", "a", "b", "start", "end", "label"),
transform: ctx.transform,
name: name,
default: "label"
)

return (
ctx: ctx,
name: name,
anchors: anchors,
drawables: drawable.apply-transform(
transform,
drawables
)
)
},)
}
let label = if type(label) == function { label(e - s) } else { label }
if label != none {
draw.content(label-pt, label)
}
})
8 changes: 4 additions & 4 deletions src/lib/axes.typ
Original file line number Diff line number Diff line change
Expand Up @@ -324,10 +324,10 @@
)

let axis-settings = (
(left, "west", "east", (0, auto), ( 1, 0), "west"),
(right, "east", "west", (w, auto), (-1, 0), "east"),
(bottom, "south", "north", (auto, 0), (0, 1), "south"),
(top, "north", "south", (auto, h), (0, -1), "north"),
(left, "west", "east", (0, auto), ( 1, 0), "left"),
(right, "east", "west", (w, auto), (-1, 0), "right"),
(bottom, "south", "north", (auto, 0), (0, 1), "bottom"),
(top, "north", "south", (auto, h), (0, -1), "top"),
)

group(name: "axes", {
Expand Down
8 changes: 3 additions & 5 deletions src/mark.typ
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
// Calculate offset for a triangular mark (triangle, harpoon, ..)
#let _triangular-mark-offset(ctx, mark-width, mark-length, symbol, style) = {
let revert = symbol == "<"
let sign = if revert { 0 } else { -1 }
let sign = if revert { 1 } else { -1 }

let stroke = line(stroke: style.stroke).stroke
let (width, limit, join) = (
Expand Down Expand Up @@ -46,8 +46,6 @@
} else {
return width / 2 * sign
}

return 0
}

// Calculate the offset of a mark symbol.
Expand Down Expand Up @@ -179,7 +177,7 @@
// Offset start
if start != none and start.len() > 0 {
let off = calc-mark-offset(ctx, start.at(0), mark-style)
curve = _shorten-curve(curve, -off, style)
curve = _shorten-curve(curve, calc.max(0, -off), style)
}

let end = if type(mark-style.end) == str {
Expand All @@ -191,7 +189,7 @@
// Offset end
if end != none and end.len() > 0 {
let off = calc-mark-offset(ctx, end.at(0), mark-style)
curve = _shorten-curve(curve, off, style)
curve = _shorten-curve(curve, calc.min(0, off), style)
}

let drawables = ()
Expand Down
4 changes: 2 additions & 2 deletions src/util.typ
Original file line number Diff line number Diff line change
Expand Up @@ -233,8 +233,8 @@
let y = padding.at("y", default: rest)
if not "left" in padding { padding.left = x }
if not "right" in padding { padding.right = x }
if not "top" in padding { padding.left = y }
if not "bottom" in padding { padding.right = y }
if not "top" in padding { padding.top = y }
if not "bottom" in padding { padding.bottom = y }

return padding
} else {
Expand Down
Binary file modified tests/angle/ref.png
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The label in the top left is missing?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, this is on purpose. I think it makes no sense displaying a label for a 0 degree angle.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

… but I re-added it.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/arc/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/arrows/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions tests/arrows/test.typ
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#set page(width: auto, height: auto)
#import "../../src/lib.typ": *
#import "/src/lib.typ": *

#box(stroke: 2pt + red, canvas({
import draw: *
Expand Down Expand Up @@ -46,7 +46,7 @@

for x in range(0, 18) {
line((x * .5, -1), (x * .5, 0), mark: (start: ">", end: ">",
angle: (x + 1) * 10deg))
width: (x / 50 + .05)))
}
}))

Expand All @@ -63,7 +63,7 @@

for x in range(0, 18) {
line((x * .5, -1), (x * .5, 0), mark: (start: "<", end: "<",
angle: (x + 1) * 10deg))
width: (x / 50 + .05)))
}
}))

Expand All @@ -80,7 +80,7 @@

for x in range(0, 18) {
line((x * .5, -1), (x * .5, 0), mark: (start: "<", end: ">",
angle: (x + 1) * 10deg))
width: (x / 50 + .05)))
}
}))

Expand All @@ -97,6 +97,6 @@

for x in range(0, 18) {
line((x * .5, -1), (x * .5, 0), mark: (start: "<", end: ">",
angle: (x + 1) * 10deg))
width: (x / 50 + .05)))
}
}))
Binary file modified tests/axes/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/bezier-through/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added tests/bezier/shorten/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/chart/boxwhisker/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/chart/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/circle/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 0 additions & 13 deletions tests/circle/test.typ
Original file line number Diff line number Diff line change
Expand Up @@ -29,16 +29,3 @@
circle((0,0,z))
}
}))

#box(stroke: 2pt + red, canvas(length: .5cm, {
import draw: *

circle((0, 0), radius: (5, 2), name: "c")
for-each-anchor("c", a => {
if not a in ("below", "above", "default") {
circle("c." + a, radius: .1, fill: green)
content((rel: (0, .5), to: "c." + a), [#a], frame: "rect",
fill: white, stroke: none)
}
})
}))
Binary file modified tests/content/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/intersection/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file modified tests/mark/auto-offset/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion tests/mark/auto-offset/test.typ
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
let width = (x + 1) * 1pt
let x = x * 2 + 2 * 8

set-style(stroke: width, mark: (width: w, length: 1, scale: .4, stroke: width))
set-style(stroke: width, mark: (width: w, length: 1, scale: .4, stroke: width + red))
line((x,0), (x,3), mark: (end: "<", start: "<"))

line((x - .5,3), (x + .5,3), stroke: .5pt + green)
Expand Down
Binary file added tests/mark/place-marks/ref.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading