Skip to content

Commit

Permalink
Streamline Angle API Behaviour (#729)
Browse files Browse the repository at this point in the history
* angle: Streamline behaviour

* angle: Change inner to direction
  • Loading branch information
johannes-wolf authored Oct 29, 2024
1 parent 98ac77a commit 90f6935
Show file tree
Hide file tree
Showing 3 changed files with 53 additions and 40 deletions.
53 changes: 26 additions & 27 deletions src/lib/angle.typ
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
mark: auto,
)

/// Draw an angle between `a` and `b` through origin `origin`
/// Draw an angle counter-clock-wise between `a` and `b` through origin `origin`
///
/// ```typc example
/// line((0,0), (1,1.5), name: "a")
Expand All @@ -25,13 +25,13 @@
/// cetz.angle.angle("a.start", "a.end", "b.end", label: $ alpha $,
/// mark: (end: ">"), radius: 1.5)
/// cetz.angle.angle("a.start", "b.end", "a.end", label: $ alpha' $,
/// radius: 50%, inner: false)
/// radius: 50%, direction: "cw")
/// ```
///
/// - origin (coordinate): Angle origin
/// - a (coordinate): Coordinate of side `a`, containing an angle between `origin` and `b`.
/// - b (coordinate): Coordinate of side `b`, containing an angle between `origin` and `a`.
/// - inner (bool): Draw the smaller (inner) angle if true, otherwise the outer angle gets drawn.
/// - direction (string): Direction of the angle. Accepts "cw" (clockwise) and "ccw" (counter-clockwise), the latter being the default.
/// - 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. The function must be of the format `angle => content`.
/// - name (none,str): Element name, used for querying anchors.
/// - ..style (style): Style key-value pairs.
Expand All @@ -53,7 +53,7 @@
origin,
a,
b,
inner: true,
direction: "ccw",
label: none,
name: none,
..style
Expand All @@ -65,32 +65,31 @@
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")

let (s, e, ss) = {
assert(direction in ("cw", "ccw"),
message: "Invalid angle direction " + repr(direction))

let (start, delta, ccw) = {
let ccw = direction == "ccw"

let s = vector.angle2(origin, a)
if s < 0deg { s += 360deg }

let e = vector.angle2(origin, b)
if e < 0deg { e += 360deg }

if s > e {
(s, e) = (e, s)
if e < s {
e += 360deg
}

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 ccw {
(s, (e - s), ccw)
} else {
(s, -(360deg - (e - s)), ccw)
}
(s, e, (s + e) / 2)
}

let mid = start + delta / 2

// Radius can be relative to the min-distance between origin-a and origin-b
if type(style.radius) == ratio {
style.radius = style.radius * calc.min(vector.dist(origin, a), vector.dist(origin, b)) / 100%
Expand All @@ -103,28 +102,28 @@
}
let (ra, _) = util.resolve-radius(style.label-radius).map(util.resolve-number.with(ctx))

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))
let label-pt = vector.add(origin, (calc.cos(mid) * ra, calc.sin(mid) * ra, 0))
let start-pt = vector.add(origin, (calc.cos(start) * r, calc.sin(start) * r, 0))
let end-pt = vector.add(origin, (calc.cos(start + delta) * r, calc.sin(start + delta) * 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 delta != 0deg {
if style.fill != none {
draw.arc(origin, start: s, stop: e, anchor: "origin",
draw.arc(origin, start: start, delta: delta, anchor: "origin",
name: "arc", ..style, radius: r, mode: "PIE", mark: none, stroke: none)
}
if style.stroke != none {
draw.arc(origin, start: s, stop: e, anchor: "origin",
draw.arc(origin, start: start, delta: delta, anchor: "origin",
name: "arc", ..style, radius: r, fill: none)
}
}

let label = if type(label) == function { label(e - s) } else { label }
let label = if type(label) == function { label(calc.abs(delta)) } else { label }
if label != none {
draw.content(label-pt, label)
}
Expand Down
Binary file modified tests/angle/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.
40 changes: 27 additions & 13 deletions tests/angle/test.typ
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
#set page(width: auto, height: auto)
#import "/src/lib.typ": *
#import "/tests/helper.typ": *

#box(stroke: 2pt + red, canvas(length: 1cm, {
#test-case({
import draw: *
import angle: angle

Expand All @@ -11,12 +12,12 @@
group({
let (o, a, b) = ((0,0), (1,0), (calc.cos(a), calc.sin(a)))
line(a, o, b)
angle(o, a, b, label: $alpha$, inner: true)
angle(o, a, b, label: $alpha$)
})
}
}))

#box(stroke: 2pt + red, canvas(length: 1cm, {
#test-case({
import draw: *
import angle: angle

Expand All @@ -26,12 +27,12 @@
group({
let (o, a, b) = ((0,0), (1,0), (calc.cos(a), calc.sin(a)))
line(a, o, b)
angle(o, a, b, label: $alpha$, inner: false)
angle(o, a, b, label: $alpha$, direction: "cw")
})
}
}))

#box(stroke: 2pt + red, canvas(length: 1cm, {
#test-case({
import draw: *
import angle: angle

Expand All @@ -41,12 +42,12 @@
group({
let (o, a, b) = ((0,0), (calc.cos(a+90deg), calc.sin(a+90deg)), (calc.cos(a), calc.sin(a)))
line(a, o, b)
angle(o, b, a, label: $alpha$, inner: true)
angle(o, b, a, label: $alpha$)
})
}
}))

#box(stroke: 2pt + red, canvas(length: 1cm, {
#test-case({
import draw: *
import angle: angle

Expand All @@ -56,33 +57,46 @@
group({
let (o, a, b) = ((0,0), (calc.cos(a+90deg), calc.sin(a+90deg)), (calc.cos(a), calc.sin(a)))
line(a, o, b)
angle(o, b, a, label: $alpha$, inner: false)
angle(o, b, a, label: $alpha$, direction: "cw")
})
}
}))

#box(stroke: 2pt + red, canvas(length: 1cm, {
#test-case({
import draw: *
import angle: angle

let (a, b, c) = ((-1, 1), (0, 0), (1, 2))

line(a, b, c)
set-style(angle: (stroke: red, label-radius: 1))
angle(b, a, c, mark: (start: ">", end: ">"),
inner: true, label: $omega$)
angle(b, c, a, mark: (start: ">", end: ">"), label: $omega$)

translate((2,0,0))

line(a, b, c)
set-style(stroke: blue)
set-style(angle: (stroke: auto, radius: 1, label-radius: .5))
angle(b, c, a, mark: (start: ">", end: ">"),
inner: false, label: $alpha$, name: "alpha")
angle(b, c, a, mark: (start: "|", end: ">"),
direction: "cw", label: $alpha$, name: "alpha")

set-style(stroke: black)
circle("alpha.origin", radius: .15)
circle("alpha.label", radius: .25)
circle("alpha.start", radius: .25)
circle("alpha.end", radius: .25)
}))

#test-case({
import draw: *
import angle: *

angle((0,0), (1,0), (0,1), mark: (end: ">"))
})

#test-case({
import draw: *
import angle: *

angle((0,0), (1,0), (0,1), mark: (end: ">"), direction: "cw")
})

0 comments on commit 90f6935

Please sign in to comment.