Files
circuiteria/src/util.typ
T
David Stadelmann 77eb4fa946 deps: update CeTZ 0.3.4 to 0.5.2 with coordinate fixes
CeTZ 0.5.2 requires 3D coordinate vectors (x, y, z) for raw
coordinate tuples passed to coordinate.resolve(). Update internal
wire computations (dodge, guided) to use 3-element tuples, fix
.last() to .at(1) for y-component access on resolved coordinates,
and add a normalize-coord utility that automatically pads user-
provided 2D points (x, y) to (x, y, 0) so users do not need to
specify the z dimension.
2026-10-21 23:39:59 +02:00

117 lines
3.0 KiB
Typst

/// Predefined color palette
/// #let w = 4
/// #box(width: 100%, align(center)[
/// #canvas(length: 2em, {
/// for (i, color) in util.colors.pairs().enumerate() {
/// let x = calc.rem(i, w) * 2
/// let y = calc.floor(i / w) * 2
/// draw.rect((x, -y), (x + 1, -y - 1), fill: color.last(), stroke: none)
/// draw.content((x + 0.5, -y - 1.25), color.first())
/// }
/// })
/// ])
#let colors = (
orange: rgb(245, 180, 147),
yellow: rgb(250, 225, 127),
green: rgb(127, 200, 172),
pink: rgb(236, 127, 178),
purple: rgb(189, 151, 255),
blue: rgb(127, 203, 235)
)
/// Pads a string on the left with 0s to the given length
///
/// #example(`#util.lpad("0100", 8)`, mode: "markup")
///
/// - string (str): The string to pad
/// - len (int): The target length
/// -> str
#let lpad(string, len) = {
let res = "0" * len + string
return res.slice(-len)
}
/// Returns the anchor on the opposite side of the given one
///
/// #example(`#util.opposite-anchor("west")`, mode: "markup")
///
/// - anchor (str): The input anchor
/// -> str
#let opposite-anchor(anchor) = {
return (
north: "south",
east: "west",
south: "north",
west: "east",
north-west: "south-east",
north-east: "south-west",
south-east: "north-west",
south-west: "north-east"
).at(anchor)
}
/// Returns the anchor rotated 90 degrees clockwise relative to the given one
///
/// #example(`#util.rotate-anchor("west")`, mode: "markup")
/// - anchor (str): The anchor to rotate
/// -> str
#let rotate-anchor(anchor) = {
return (
north: "east",
east: "south",
south: "west",
west: "north",
north-west: "north-east",
north-east: "south-east",
south-east: "south-west",
south-west: "north-west"
).at(anchor)
}
#let valid-anchors = (
"center", "north", "east", "west", "south",
"north-east", "north-west", "south-east", "south-west"
)
/// Normalizes a coordinate so that 2D points (x, y) are padded
/// to (x, y, 0) as required by CeTZ's coordinate resolver.
/// Also handles function-based and dictionary-based coordinates
/// recursively.
///
/// - coord (any): A CeTZ-compatible coordinate
/// -> any
#let normalize-coord(coord) = {
if type(coord) == array {
if coord.len() == 2 {
let (a, b) = coord
// Raw 2D point: (x, y) -> (x, y, 0)
if type(a) in (int, float) and type(b) in (int, float) {
return (a, b, 0)
}
// Function-based coordinate: (fn, point)
if type(a) == function {
let orig = a
return (v => {
let result = orig(v)
if type(result) == array and result.len() == 2 {
let (rx, ry) = result
if type(rx) in (int, float) and type(ry) in (int, float) {
return (rx, ry, 0)
}
}
return result
}, b)
}
}
}
if type(coord) == dictionary {
let result = (:)
for (key, value) in coord {
result.insert(key, normalize-coord(value))
}
return result
}
return coord
}