Skip to content

Commit 69a4359

Browse files
Smartart cycle custom angles (#178)
2 parents 792eaa8 + 75b8a55 commit 69a4359

4 files changed

Lines changed: 86 additions & 19 deletions

File tree

manual.pdf

2.11 KB
Binary file not shown.

src/smartart/cycle.typ

Lines changed: 67 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,10 @@
8282
/// - ccw (boolean): If true, steps are laid out counter-clockwise. If false, they're placed clockwise. The center of the cycle is always placed at (0, 0)
8383
/// - radius (number, length): The radius of the cycle
8484
/// - offset-angle (angle): Offset of the starting angle
85+
/// - step-angles (none,angle,array): Angles between the steps.
86+
/// - none: Steps are spaced evenly.
87+
/// - angle: Space between the steps, with the last angle (between the last step and the first one) completing the full circle.
88+
/// - array: An array of angles between the steps. For n steps, the array must contain n-1 angles. The last angle is automatically computed to complete the full circle.
8589
#let basic(
8690
steps,
8791
arrow-style: auto,
@@ -92,7 +96,8 @@
9296
radius: 2,
9397
offset-angle: 0deg,
9498
name: none,
95-
..style
99+
step-angles: none,
100+
..style,
96101
) = {
97102
draw.group(name: name, ctx => {
98103
draw.anchor("default", (0, 0))
@@ -111,17 +116,58 @@
111116
let (
112117
sizes,
113118
largest-width,
114-
highest-height
119+
highest-height,
115120
) = _get-steps-sizes(steps, ctx, style, step-style-at)
116121

117-
let angle-step = 360deg / n-steps
122+
let step-angles = if step-angles == none {
123+
steps.map(_ => 360deg / n-steps)
124+
} else if type(step-angles) == angle {
125+
assert(
126+
step-angles >= 0deg,
127+
message: "step-angles must be positive, use the ccw parameter to change the direction"
128+
)
129+
assert(
130+
(steps.len() - 1) * step-angles <= 360deg,
131+
message: "Sum of step angles is greater than 360°"
132+
)
133+
let angles = (step-angles,) * (steps.len() - 1)
134+
angles + (360deg - angles.sum(default: 0deg),)
135+
} else if type(step-angles) == array {
136+
assert(
137+
step-angles.len() == n-steps - 1,
138+
message: "There must be one less step angle as there are steps. Expected " + str(n-steps - 1) + ", got " + str(step-angles.len())
139+
)
140+
for step-angle in step-angles {
141+
assert(
142+
step-angle >= 0deg,
143+
message: "step-angles must be positive, use the ccw parameter to change the direction"
144+
)
145+
assert(
146+
type(step-angle) == angle,
147+
message: "All values in step-angles must be angles"
148+
)
149+
}
150+
assert(
151+
step-angles.sum(default: 0deg) <= 360deg,
152+
message: "Sum of step angles is greater than 360°"
153+
)
154+
step-angles + (360deg - step-angles.sum(default: 0deg),)
155+
} else {
156+
panic("step-angles must be an angle, an array or none, got " + repr(type(step-angles)))
157+
}
118158
if not ccw {
119-
angle-step *= -1
159+
step-angles = step-angles.map(x => x * -1)
120160
}
121161

162+
let angle-at = i => (
163+
step-angles.slice(0, i)
164+
.sum(default: 0deg)
165+
+ 90deg
166+
+ offset-angle
167+
)
168+
122169
for (i, step) in steps.enumerate() {
123-
let angle = angle-step * i + 90deg + offset-angle
124-
let pos = (angle, radius)
170+
let pos = (angle-at(i), radius)
125171

126172
let step-style = style.steps + step-style-at(i)
127173
let padding = resolve-number(ctx, step-style.padding)
@@ -139,8 +185,7 @@
139185
}
140186

141187
for i in range(n-steps) {
142-
let angle = angle-step * i + 90deg + offset-angle
143-
188+
let angle = angle-at(i)
144189
let arrow-style = style.arrows + arrow-style-at(i)
145190
let arrow-stroke = arrow-style.stroke
146191
let arrow-fill = arrow-style.fill
@@ -152,6 +197,7 @@
152197
arrow-fill = gradient.linear(s1.fill, s2.fill).sample(50%)
153198
}
154199

200+
let angle-step = step-angles.at(i)
155201
let start-angle = angle + angle-step * 0.2
156202
let end-angle = angle + angle-step * 0.8
157203

@@ -179,17 +225,17 @@
179225
}
180226
draw.hide(draw.arc-through(
181227
..pts,
182-
name: "arc-" + str(i)
228+
name: "arc-" + str(i),
183229
))
184230
draw.intersections(
185231
"i-" + str(i),
186232
"step-" + str(i),
187-
"arc-" + str(i)
233+
"arc-" + str(i),
188234
)
189235
draw.intersections(
190236
"j-" + str(i),
191237
"step-" + str(calc.rem(i + 1, n-steps)),
192-
"arc-" + str(i)
238+
"arc-" + str(i),
193239
)
194240

195241
draw.get-ctx(ctx => {
@@ -231,9 +277,9 @@
231277
(end-angle, radius),
232278
stroke: arrow-stroke,
233279
mark: marks,
234-
name: arrow-name
280+
name: arrow-name,
235281
)
236-
282+
237283
// Thick arrow
238284
} else {
239285
_draw-arc-arrow(
@@ -244,29 +290,31 @@
244290
arrow-fill,
245291
arrow-stroke,
246292
double: arrow-style.double,
247-
name: arrow-name
293+
name: arrow-name,
248294
)
249295
}
250-
296+
251297
// Straight
252298
} else {
253299
let p1 = (start-angle, radius)
254300
let p2 = (end-angle, radius)
255301
if arrow-thickness == none {
256302
draw.line(
257-
p1, p2,
303+
p1,
304+
p2,
258305
stroke: arrow-stroke,
259306
mark: marks,
260-
name: arrow-name
307+
name: arrow-name,
261308
)
262309
} else {
263310
_draw-arrow(
264-
p1, p2,
311+
p1,
312+
p2,
265313
arrow-thickness,
266314
arrow-fill,
267315
arrow-stroke,
268316
double: arrow-style.double,
269-
name: arrow-name
317+
name: arrow-name,
270318
)
271319
}
272320
}

tests/smartart/cycle/ref/3.png

37.8 KB
Loading

tests/smartart/cycle/test.typ

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -219,4 +219,23 @@
219219
(angle: 0deg, ccw: true),
220220
(angle: 15deg, ccw: true),
221221
(angle: -20deg, ccw: true),
222+
))
223+
224+
#let steps = ([A], [B], [C])
225+
226+
#test-case(args => {
227+
defaults()
228+
smartart.cycle.basic(
229+
steps,
230+
step-style: none,
231+
step-angles: args.step-angles,
232+
ccw: args.ccw
233+
)
234+
}, args: (
235+
(step-angles: none, ccw: false),
236+
(step-angles: none, ccw: true),
237+
(step-angles: 60deg, ccw: false),
238+
(step-angles: 60deg, ccw: true),
239+
(step-angles: (60deg, 120deg), ccw: false),
240+
(step-angles: (60deg, 120deg), ccw: true),
222241
))

0 commit comments

Comments
 (0)