Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0fb4929aca | ||
|
|
23213fabca | ||
|
|
320318a25b | ||
|
|
9bcd91131c | ||
|
|
c9aa81af2e | ||
|
|
6871053810 | ||
|
|
73b7348eed
|
||
|
|
b71e822bb8
|
||
|
|
4c1025b1eb
|
||
|
|
b35c04a7d9
|
||
|
|
0612e9b6ec
|
No files matched your search
@@ -3,7 +3,7 @@
|
||||
Circuiteria is a [Typst](https://typst.app) package for drawing block circuit diagrams using the [CeTZ](https://typst.app/universe/package/cetz) package.
|
||||
|
||||
<p align="center">
|
||||
<img src="./gallery/platypus.png" alt="Perry the platypus">
|
||||
<img src="./gallery/platypus.png" alt="A platypus / Perry the Platypus meme made with colored rounded rectangles">
|
||||
</p>
|
||||
|
||||
## Examples
|
||||
@@ -11,17 +11,17 @@ Circuiteria is a [Typst](https://typst.app) package for drawing block circuit di
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<a href="./gallery/test.typ">
|
||||
<img src="./gallery/test.png" width="500px">
|
||||
<img src="./gallery/test.png" width="500px" alt="Block diagram of a multi-cycle RISC-V FPGA processor">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">A bit of eveything</td>
|
||||
<td colspan="2">A bit of everything</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="2">
|
||||
<a href="./gallery/test5.typ">
|
||||
<img src="./gallery/test5.png" width="500px">
|
||||
<img src="./gallery/test5.png" width="500px" alt="Block diagram of a single-cycle RISC-V processor">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -31,12 +31,12 @@ Circuiteria is a [Typst](https://typst.app) package for drawing block circuit di
|
||||
<tr>
|
||||
<td>
|
||||
<a href="./gallery/test4.typ">
|
||||
<img src="./gallery/test4.png" width="250px">
|
||||
<img src="./gallery/test4.png" width="250px" alt="Top-level block diagram of a single-cycle RISC-V processor">
|
||||
</a>
|
||||
</td>
|
||||
<td>
|
||||
<a href="./gallery/test6.typ">
|
||||
<img src="./gallery/test6.png" width="250px">
|
||||
<img src="./gallery/test6.png" width="250px" alt="Block diagram of a simple single-cycle RISC-V ALU">
|
||||
</a>
|
||||
</td>
|
||||
</tr>
|
||||
@@ -56,7 +56,7 @@ For more information, see the [manual](manual.pdf)
|
||||
|
||||
To use this package, simply import [circuiteria](https://typst.app/universe/package/circuiteria) and call the `circuit` function:
|
||||
```typ
|
||||
#import "@preview/circuiteria:0.2.0"
|
||||
#import "@preview/circuiteria:0.2.1"
|
||||
#circuiteria.circuit({
|
||||
import circuiteria: *
|
||||
...
|
||||
|
||||
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 11 KiB |
@@ -1,4 +1,4 @@
|
||||
#import "../src/lib.typ": *
|
||||
#import "@preview/circuiteria:0.2.1": *
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 53 KiB |
@@ -1,4 +1,4 @@
|
||||
#import "../src/lib.typ": circuit, element, util, wire
|
||||
#import "@preview/circuiteria:0.2.1": circuit, element, util, wire
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
@@ -117,7 +117,7 @@
|
||||
wire.wire(
|
||||
"wExtender-ImmSrc", (
|
||||
"Extender.north",
|
||||
(18, -2, 0)
|
||||
(18, -2)
|
||||
),
|
||||
style: "zigzag",
|
||||
zigzag-ratio: 0%,
|
||||
@@ -138,8 +138,8 @@
|
||||
)
|
||||
wire.wire(
|
||||
"wBus", (
|
||||
(v => (v.at(0), -3.5, 0), mid),
|
||||
(horizontal: (), vertical: (0, 3.5, 0)),
|
||||
(v => (v.at(0), -3.5), mid),
|
||||
(horizontal: (), vertical: (0, 3.5)),
|
||||
),
|
||||
bus: true
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 160 KiB After Width: | Height: | Size: 53 KiB |
@@ -1,4 +1,4 @@
|
||||
#import "../src/lib.typ": circuit, element, util, wire
|
||||
#import "@preview/circuiteria:0.2.1": circuit, element, util, wire
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
wire.wire(
|
||||
"wExtender-ImmSrc", (
|
||||
"Extender.north",
|
||||
(18, -2, 0)
|
||||
(18, -2)
|
||||
),
|
||||
style: "zigzag",
|
||||
zigzag-ratio: 0%,
|
||||
@@ -145,8 +145,8 @@
|
||||
)
|
||||
wire.wire(
|
||||
"wBus", (
|
||||
(v => (v.at(0), -3.5, 0), mid),
|
||||
(horizontal: (), vertical: (0, 3.5, 0)),
|
||||
(v => (v.at(0), -3.5), mid),
|
||||
(horizontal: (), vertical: (0, 3.5)),
|
||||
),
|
||||
bus: true
|
||||
)
|
||||
|
||||
|
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 23 KiB |
@@ -1,4 +1,4 @@
|
||||
#import "../src/lib.typ": circuit, element, util, wire
|
||||
#import "@preview/circuiteria:0.2.1": circuit, element, util, wire
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 195 KiB After Width: | Height: | Size: 67 KiB |
@@ -1,5 +1,5 @@
|
||||
#import "/src/cetz.typ": draw
|
||||
#import "../src/lib.typ": *
|
||||
#import "@preview/circuiteria:0.2.1": *
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 274 KiB After Width: | Height: | Size: 93 KiB |
@@ -1,5 +1,5 @@
|
||||
#import "/src/cetz.typ": draw
|
||||
#import "../src/lib.typ": *
|
||||
#import "@preview/circuiteria:0.2.1": *
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 23 KiB |
@@ -1,5 +1,5 @@
|
||||
#import "/src/cetz.typ": draw
|
||||
#import "../src/lib.typ": *
|
||||
#import "@preview/circuiteria:0.2.1": *
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
|
||||
|
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 5.8 KiB |
@@ -1,4 +1,4 @@
|
||||
#import "../src/lib.typ": circuit, element, util, wire
|
||||
#import "@preview/circuiteria:0.2.1": circuit, element, util, wire
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 4.1 KiB |
@@ -0,0 +1,46 @@
|
||||
// Demonstrates the `(rel: <number>, to: <anchor>)` shorthand for the `y`
|
||||
// parameter (analogous to the existing shorthand for `x`).
|
||||
#import "/src/lib.typ": circuit, element, util, wire
|
||||
|
||||
#set page(width: auto, height: auto, margin: .5cm)
|
||||
|
||||
#circuit({
|
||||
// Anchor block: absolute placement.
|
||||
element.block(
|
||||
x: 0, y: 0, w: 2, h: 1.5,
|
||||
id: "A",
|
||||
fill: util.colors.orange,
|
||||
ports: (east: ((id: "out"),))
|
||||
)
|
||||
|
||||
// X relative, Y absolute (existing feature).
|
||||
element.block(
|
||||
x: (rel: 1, to: "A.east"), y: 0, w: 2, h: 1.5,
|
||||
id: "B",
|
||||
fill: util.colors.yellow,
|
||||
ports: (west: ((id: "in"),), east: ((id: "out"),))
|
||||
)
|
||||
|
||||
// Both X and Y relative to another element's anchor (new feature).
|
||||
element.block(
|
||||
x: (rel: 1, to: "B.east"),
|
||||
y: (rel: 2, to: "B.south-west"),
|
||||
w: 2, h: 1.5,
|
||||
id: "C",
|
||||
fill: util.colors.green,
|
||||
ports: (west: ((id: "in"),))
|
||||
)
|
||||
|
||||
// Y relative only, X absolute.
|
||||
element.block(
|
||||
x: 0,
|
||||
y: (rel: -2.5, to: "A.south-west"),
|
||||
w: 2, h: 1.5,
|
||||
id: "D",
|
||||
fill: util.colors.blue,
|
||||
ports: (east: ((id: "out"),))
|
||||
)
|
||||
|
||||
wire.wire("wAB", ("A-port-out", "B-port-in"))
|
||||
wire.wire("wBC", ("B-port-out", "C-port-in"), style: "zigzag")
|
||||
})
|
||||
@@ -105,7 +105,7 @@ This package provides a way to make beautiful block circuit diagrams using the C
|
||||
|
||||
Simply import Circuiteria and call the `circuit` function:
|
||||
#pad(left: 1em)[```typ
|
||||
#import "@preview/circuiteria:0.2.0"
|
||||
#import "@preview/circuiteria:0.2.1"
|
||||
#circuiteria.circuit({
|
||||
import circuiteria: *
|
||||
...
|
||||
|
||||
@@ -24,7 +24,9 @@
|
||||
/// If it is a dictionary, it should be in the format `(rel: number, to: str)`, where `rel` is the offset and `to` the base anchor
|
||||
/// - y (number, dictionary): The y position (bottom-left corner).
|
||||
///
|
||||
/// If it is a dictionary, it should be in the format `(from: str, to: str)`, where `from` is the base anchor and `to` is the id of the port to align with the anchor
|
||||
/// If it is a dictionary, it can take one of two forms:
|
||||
/// - `(rel: number, to: str)`: `rel` is the y offset and `to` the base anchor (analogous to `x`)
|
||||
/// - `(from: str, to: str)`: `from` is the base anchor and `to` is the id of the port to align with the anchor
|
||||
/// - w (number): Width of the element
|
||||
/// - h (number): Height of the element
|
||||
/// - name (none, str): Optional name of the block
|
||||
@@ -74,13 +76,12 @@
|
||||
if h == none { panic("Parameter h must be set") }
|
||||
|
||||
if (type(x) == dictionary) {
|
||||
let offset = x.rel
|
||||
let to = x.to
|
||||
let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0, 0), to: to))
|
||||
x = to-pos.at(0)
|
||||
x = util.resolve-rel-coord(ctx, x, 0)
|
||||
}
|
||||
|
||||
if (type(y) == dictionary) {
|
||||
if (type(y) == dictionary and "rel" in y) {
|
||||
y = util.resolve-rel-coord(ctx, y, 1)
|
||||
} else if (type(y) == dictionary) {
|
||||
let from = y.from
|
||||
let to = y.to
|
||||
let (to-side, i) = find-port(ports, to)
|
||||
|
||||
@@ -91,7 +91,7 @@
|
||||
debug: debug
|
||||
)
|
||||
|
||||
let in-pos = (rel: (0, h * (h-ratio / 200%), 0), to: id+".south-west")
|
||||
let in-pos = (rel: (0, h * (h-ratio / 200%)), to: id+".south-west")
|
||||
let out-pos = (id+".south-east", out-pct, id+".north-east")
|
||||
add-port(id, "west", ports.west.first(), in-pos)
|
||||
add-port(id, "east", ports.east.first(), out-pos)
|
||||
|
||||
@@ -61,8 +61,8 @@
|
||||
|
||||
draw.hide(draw.group(name: id+"-inner", body))
|
||||
draw.rect(
|
||||
(rel: (-pad-left, -pad-bottom, 0), to: id+"-inner.south-west"),
|
||||
(rel: (pad-right, pad-top, 0), to: id+"-inner.north-east"),
|
||||
(rel: (-pad-left, -pad-bottom), to: id+"-inner.south-west"),
|
||||
(rel: (pad-right, pad-top), to: id+"-inner.north-east"),
|
||||
name: id,
|
||||
radius: radius,
|
||||
stroke: stroke,
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#import "/src/cetz.typ": draw, coordinate
|
||||
#import "/src/util.typ"
|
||||
#import "../ports.typ": add-ports, add-port
|
||||
#import "../element.typ"
|
||||
|
||||
@@ -49,13 +50,12 @@
|
||||
if h == none { panic("Parameter h must be set") }
|
||||
|
||||
if (type(x) == dictionary) {
|
||||
let offset = x.rel
|
||||
let to = x.to
|
||||
let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0, 0), to: to))
|
||||
x = to-pos.at(0)
|
||||
x = util.resolve-rel-coord(ctx, x, 0)
|
||||
}
|
||||
|
||||
if (type(y) == dictionary) {
|
||||
if (type(y) == dictionary and "rel" in y) {
|
||||
y = util.resolve-rel-coord(ctx, y, 1)
|
||||
} else if (type(y) == dictionary) {
|
||||
let from = y.from
|
||||
let to = y.to
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
let port-pos = int-name + ".0"
|
||||
if inverted == "all" or port-name in inverted {
|
||||
draw.circle(port-pos, radius: inverted-radius, anchor: "east", stroke: stroke)
|
||||
port-pos = (rel: (-2 * inverted-radius, 0, 0), to: port-pos)
|
||||
port-pos = (rel: (-2 * inverted-radius, 0), to: port-pos)
|
||||
}
|
||||
add-port(
|
||||
id, "west",
|
||||
@@ -113,7 +113,7 @@
|
||||
let out-pos = id + ".east"
|
||||
if inverted == "all" or "out" in inverted {
|
||||
draw.circle(out-pos, radius: inverted-radius, anchor: "west", stroke: stroke)
|
||||
out-pos = (rel: (2 * inverted-radius, 0, 0), to: out-pos)
|
||||
out-pos = (rel: (2 * inverted-radius, 0), to: out-pos)
|
||||
}
|
||||
add-port(
|
||||
id, "east",
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
#import "/src/cetz.typ": draw, coordinate
|
||||
#import "/src/util.typ"
|
||||
#import "../ports.typ": add-ports, add-port
|
||||
#import "../element.typ"
|
||||
|
||||
@@ -60,13 +61,12 @@
|
||||
if h == none { panic("Parameter h must be set") }
|
||||
|
||||
if (type(x) == dictionary) {
|
||||
let offset = x.rel
|
||||
let to = x.to
|
||||
let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0, 0), to: to))
|
||||
x = to-pos.at(0)
|
||||
x = util.resolve-rel-coord(ctx, x, 0)
|
||||
}
|
||||
|
||||
if (type(y) == dictionary) {
|
||||
if (type(y) == dictionary and "rel" in y) {
|
||||
y = util.resolve-rel-coord(ctx, y, 1)
|
||||
} else if (type(y) == dictionary) {
|
||||
let from = y.from
|
||||
let to = y.to
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
anchor: "east",
|
||||
stroke: stroke
|
||||
)
|
||||
port-pos = (rel: (-2 * inverted-radius, 0, 0), to: port-pos)
|
||||
port-pos = (rel: (-2 * inverted-radius, 0), to: port-pos)
|
||||
}
|
||||
add-port(
|
||||
id, "west",
|
||||
@@ -115,7 +115,7 @@
|
||||
let out-pos = id + ".east"
|
||||
if inverted == "all" or "out" in inverted {
|
||||
draw.circle(out-pos, radius: inverted-radius, anchor: "west", stroke: stroke)
|
||||
out-pos = (rel: (2 * inverted-radius, 0, 0), to: out-pos)
|
||||
out-pos = (rel: (2 * inverted-radius, 0), to: out-pos)
|
||||
}
|
||||
add-port(
|
||||
id, "east",
|
||||
|
||||
@@ -17,10 +17,10 @@
|
||||
|
||||
let size = if port.at("small", default: false) {8pt} else {1em}
|
||||
let offset
|
||||
if (side == "north") { offset = ( 0, -size, 0) }
|
||||
else if (side == "east") { offset = (-size, 0, 0) }
|
||||
else if (side == "south") { offset = ( 0, size, 0) }
|
||||
else if (side == "west") { offset = ( size, 0, 0) }
|
||||
if (side == "north") { offset = ( 0, -size) }
|
||||
else if (side == "east") { offset = (-size, 0) }
|
||||
else if (side == "south") { offset = ( 0, size) }
|
||||
else if (side == "west") { offset = ( size, 0) }
|
||||
|
||||
let pos1 = (rel: offset, to: pos)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#let version = version(0, 2, 0)
|
||||
#let version = version(0, 2, 1)
|
||||
#let name = "circuiteria"
|
||||
|
||||
#import "circuit.typ": circuit
|
||||
|
||||
@@ -1,3 +1,23 @@
|
||||
#import "cetz.typ": coordinate
|
||||
|
||||
/// Resolves a relative coordinate shorthand of the form `(rel: <number>, to: <anchor>)`
|
||||
/// to a single scalar along the requested axis.
|
||||
///
|
||||
/// Used to implement the shared `(rel:, to:)` shorthand accepted by the `x` and
|
||||
/// `y` parameters of `elmt`, `gate` and `iec-gate`.
|
||||
///
|
||||
/// - ctx (dictionary): The current CeTZ context
|
||||
/// - val (dictionary): A dictionary with fields `rel` (number) and `to` (anchor)
|
||||
/// - axis (int): `0` for x, `1` for y
|
||||
/// -> number
|
||||
#let resolve-rel-coord(ctx, val, axis) = {
|
||||
let offset = val.rel
|
||||
let to = val.to
|
||||
let delta = if axis == 0 { (offset, 0) } else { (0, offset) }
|
||||
let (_, to-pos) = coordinate.resolve(ctx, (rel: delta, to: to))
|
||||
return to-pos.at(axis)
|
||||
}
|
||||
|
||||
/// Predefined color palette
|
||||
/// #let w = 4
|
||||
/// #box(width: 100%, align(center)[
|
||||
@@ -73,4 +93,45 @@
|
||||
#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
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
#import "/src/cetz.typ": draw, coordinate
|
||||
#import "util.typ": opposite-anchor
|
||||
#import "util.typ": opposite-anchor, normalize-coord
|
||||
|
||||
/// List of valid wire styles
|
||||
/// #examples.wires
|
||||
@@ -157,8 +157,8 @@
|
||||
let p3 = (center_x, center_y, 0)
|
||||
|
||||
// setting up the points for that touch the guides
|
||||
let p2 = (0,0,0)
|
||||
let p4 = (0,0,0)
|
||||
let p2 = (0, 0, 0)
|
||||
let p4 = (0, 0, 0)
|
||||
if side-start in ("north", "south") {
|
||||
p2 = (horizontal: p3, vertical: p1)
|
||||
} else {
|
||||
@@ -240,6 +240,9 @@
|
||||
if pts.len() != 2 {
|
||||
panic("Wrong number of points (got " + str(pts.len()) + " instead of 2)")
|
||||
}
|
||||
|
||||
// Normalize user-provided coordinates: (x, y) -> (x, y, 0)
|
||||
let pts = pts.map(normalize-coord)
|
||||
|
||||
let stroke = (
|
||||
paint: color,
|
||||
@@ -365,17 +368,17 @@
|
||||
/// - name-offset (number): The name offset, perpendicular to the stub
|
||||
#let stub(port-id, side, name: none, vertical: false, length: 1em, name-offset: 0) = {
|
||||
let end-offset = (
|
||||
north: (0, length, 0),
|
||||
east: (length, 0, 0),
|
||||
south: (0, -length, 0),
|
||||
west: (-length, 0, 0)
|
||||
north: (0, length),
|
||||
east: (length, 0),
|
||||
south: (0, -length),
|
||||
west: (-length, 0)
|
||||
).at(side)
|
||||
|
||||
let name-offset = (
|
||||
north: (name-offset, length, 0),
|
||||
east: (length, name-offset, 0),
|
||||
south: (name-offset, -length, 0),
|
||||
west: (-length, name-offset, 0)
|
||||
north: (name-offset, length),
|
||||
east: (length, name-offset),
|
||||
south: (name-offset, -length),
|
||||
west: (-length, name-offset)
|
||||
).at(side)
|
||||
|
||||
draw.line(
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "circuiteria"
|
||||
version = "0.2.0"
|
||||
version = "0.2.1"
|
||||
compiler = "0.15.0"
|
||||
repository = "https://git.kb28.ch/HEL/circuiteria"
|
||||
entrypoint = "src/lib.typ"
|
||||
@@ -9,6 +9,6 @@ authors = [
|
||||
]
|
||||
categories = [ "visualization" ]
|
||||
license = "Apache-2.0"
|
||||
description = "Drawing block circuits with Typst made easy, using CeTZ"
|
||||
description = "Drawing block circuits made easy, using CeTZ"
|
||||
keywords = [ "circuit", "block", "draw" ]
|
||||
exclude = [ "gallery", "justfile", "doc" ]
|
||||