Compare commits

..
3 Commits
58 changed files with 114 additions and 1447 deletions

No files matched your search

+7 -7
View File
@@ -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. 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"> <p align="center">
<img src="./gallery/platypus.png" alt="A platypus / Perry the Platypus meme made with colored rounded rectangles"> <img src="./gallery/platypus.png" alt="Perry the platypus">
</p> </p>
## Examples ## Examples
@@ -11,17 +11,17 @@ Circuiteria is a [Typst](https://typst.app) package for drawing block circuit di
<tr> <tr>
<td colspan="2"> <td colspan="2">
<a href="./gallery/test.typ"> <a href="./gallery/test.typ">
<img src="./gallery/test.png" width="500px" alt="Block diagram of a multi-cycle RISC-V FPGA processor"> <img src="./gallery/test.png" width="500px">
</a> </a>
</td> </td>
</tr> </tr>
<tr> <tr>
<td colspan="2">A bit of everything</td> <td colspan="2">A bit of eveything</td>
</tr> </tr>
<tr> <tr>
<td colspan="2"> <td colspan="2">
<a href="./gallery/test5.typ"> <a href="./gallery/test5.typ">
<img src="./gallery/test5.png" width="500px" alt="Block diagram of a single-cycle RISC-V processor"> <img src="./gallery/test5.png" width="500px">
</a> </a>
</td> </td>
</tr> </tr>
@@ -31,12 +31,12 @@ Circuiteria is a [Typst](https://typst.app) package for drawing block circuit di
<tr> <tr>
<td> <td>
<a href="./gallery/test4.typ"> <a href="./gallery/test4.typ">
<img src="./gallery/test4.png" width="250px" alt="Top-level block diagram of a single-cycle RISC-V processor"> <img src="./gallery/test4.png" width="250px">
</a> </a>
</td> </td>
<td> <td>
<a href="./gallery/test6.typ"> <a href="./gallery/test6.typ">
<img src="./gallery/test6.png" width="250px" alt="Block diagram of a simple single-cycle RISC-V ALU"> <img src="./gallery/test6.png" width="250px">
</a> </a>
</td> </td>
</tr> </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: To use this package, simply import [circuiteria](https://typst.app/universe/package/circuiteria) and call the `circuit` function:
```typ ```typ
#import "@preview/circuiteria:0.2.1" #import "@preview/circuiteria:0.3.0"
#circuiteria.circuit({ #circuiteria.circuit({
import circuiteria: * import circuiteria: *
... ...
+1 -1
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "../src/circuit.typ": circuit #import "../src/circuit.typ": circuit
#import "../src/util.typ" #import "../src/util.typ"
+2 -180
View File
@@ -56,7 +56,7 @@ for i in range(3) {
```) ```)
#let wires = example(``` #let wires = example(```
for i in range(4) { for i in range(3) {
draw.circle((i * 3, 0), radius: .1, name: "p" + str(i * 2)) draw.circle((i * 3, 0), radius: .1, name: "p" + str(i * 2))
draw.circle((i * 3 + 2, 1), radius: .1, name: "p" + str(i * 2 + 1)) draw.circle((i * 3 + 2, 1), radius: .1, name: "p" + str(i * 2 + 1))
draw.content((i * 3 + 1, -1), raw(wire.wire-styles.at(i))) draw.content((i * 3 + 1, -1), raw(wire.wire-styles.at(i)))
@@ -65,10 +65,6 @@ wire.wire("w1", ("p0", "p1"), style: "direct")
wire.wire("w2", ("p2", "p3"), style: "zigzag") wire.wire("w2", ("p2", "p3"), style: "zigzag")
wire.wire("w3", ("p4", "p5"), style: "dodge", wire.wire("w3", ("p4", "p5"), style: "dodge",
dodge-y: -0.5, dodge-margins: (0.5, 0.5)) dodge-y: -0.5, dodge-margins: (0.5, 0.5))
wire.wire("w4", ("p6","p7"), style: "guided",
guided-center:(20%, 40%), guided-margins: (90%,87%),
guided-sides: ("north","south"))
```, vertical: true) ```, vertical: true)
#let stub = example(``` #let stub = example(```
@@ -119,46 +115,6 @@ gates.gate-xnor(x: 0, y: 0, w: 1.5, h: 1.5)
gates.gate-xnor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all") gates.gate-xnor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true) ```, vertical: true)
#let iec-gate-and = example(```
gates.iec-gate-and(x: 0, y: 0, w: 1.5, h: 1.5)
gates.iec-gate-and(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true)
#let iec-gate-nand = example(```
gates.iec-gate-nand(x: 0, y: 0, w: 1.5, h: 1.5)
gates.iec-gate-nand(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true)
#let iec-gate-or = example(```
gates.iec-gate-or(x: 0, y: 0, w: 1.5, h: 1.5)
gates.iec-gate-or(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true)
#let iec-gate-nor = example(```
gates.iec-gate-nor(x: 0, y: 0, w: 1.5, h: 1.5)
gates.iec-gate-nor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true)
#let iec-gate-xor = example(```
gates.iec-gate-xor(x: 0, y: 0, w: 1.5, h: 1.5)
gates.iec-gate-xor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true)
#let iec-gate-xnor = example(```
gates.iec-gate-xnor(x: 0, y: 0, w: 1.5, h: 1.5)
gates.iec-gate-xnor(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true)
#let iec-gate-buf = example(```
gates.iec-gate-buf(x: 0, y: 0, w: 1.5, h: 1.5)
gates.iec-gate-buf(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true)
#let iec-gate-not = example(```
gates.iec-gate-not(x: 0, y: 0, w: 1.5, h: 1.5)
gates.iec-gate-not(x: 3, y: 0, w: 1.5, h: 1.5, inverted: "all")
```, vertical: true)
#let group = example(``` #let group = example(```
element.group( element.group(
id: "g1", name: "Group 1", stroke: (dash: "dashed"), id: "g1", name: "Group 1", stroke: (dash: "dashed"),
@@ -186,143 +142,9 @@ wire.wire("w2", ("b2-port-out", "b3-port-in2"),
style: "zigzag") style: "zigzag")
```) ```)
#let group-ports = example(```
// outside-port-names: true (default) — labels outside the border
element.group(
id: "g1", name: "outside (default)",
stroke: (dash: "dashed"),
fill: util.colors.blue.lighten(60%),
padding: 2em,
outside-port-names: true,
port-name-padding: 4pt,
ports: (
west: ((id: "in", name: "D"),),
east: ((id: "out", name: "Q"),),
),
{ element.block(id: "b1", w: 2, h: 1.5, x: 0, y: 0,
fill: util.colors.green,
ports: (west: ((id: "d", name: "d"),),
east: ((id: "q", name: "q"),))) }
)
wire.wire("wG1in", ("g1-port-in", "b1-port-d"), directed: true)
wire.wire("wG1out", ("b1-port-q", "g1-port-out"), directed: true)
// outside-port-names: false — labels inside the border (block style)
// with extra padding via port-name-padding
element.group(
id: "g2", name: "inside",
stroke: (dash: "dashed"),
fill: util.colors.orange.lighten(60%),
padding: 2em,
outside-port-names: false,
port-name-padding: 0.4em,
ports: (
west: ((id: "in", name: "D"),),
east: ((id: "out", name: "Q"),),
),
{ element.block(id: "b2", w: 2, h: 1.5, x: 6, y: 0,
fill: util.colors.green,
ports: (west: ((id: "d"),), east: ((id: "q"),))) }
)
wire.stub("g2-port-in", "west")
wire.stub("g2-port-out", "east")
```, vertical: true)
#let port-names-outside = example(```
element.block(
x: 0, y: 0, w: 2, h: 2, id: "block",
port-names-outside: true,
port-name-padding: 4pt,
ports: (
north: ((id: "clk", name: "CLK", clock: true),),
west: ((id: "in1", name: "A"),
(id: "in2", name: "B")),
east: ((id: "out", name: "Y"),)
)
)
```)
#let port-shape = example(```
// Block with pentagon-shaped ports.
// - port-shape / port-kind / port-size are element-level defaults.
// - Any port field (shape, kind, size, stroke, fill) overrides per port.
// - kind: "in" → tip points into the block (default)
// kind: "out" → tip points away from the block
// - clock ports with shape: "pentagon" drop their triangle and default
// to a gray fill.
element.block(
id: "b", w: 3, h: 3, x: 0, y: 0,
fill: util.colors.yellow.lighten(60%),
port-shape: "pentagon",
port-size: 1em,
ports: (
// west: default input
west: ((id: "in", name: "D"),),
// east: output — tip points away
east: ((id: "out", name: "Q", kind: "out"),),
// north: clock port — pentagon replaces the triangle, gray fill
north: ((id: "clk", name: "CLK", clock: true),),
// south: styled output with per-port fill and stroke
south: ((id: "rdy", name: "RDY", kind: "out",
fill: util.colors.blue, stroke: red + 1.5pt),),
),
)
// Wires connect at the outer end of each pentagon.
wire.stub("b-port-in", "west")
wire.stub("b-port-out", "east")
wire.stub("b-port-clk", "north")
wire.stub("b-port-rdy", "south")
```)
#let shell = example(```
// A shell block acts as a container: port name labels are drawn
// outside by default, and wires attach at the *inside* tip of
// pentagon-shaped ports so child elements can sit within.
element.block(
id: "sh", w: 5, h: 3, x: 0, y: 0,
shell: true,
port-shape: "pentagon",
fill: util.colors.blue.lighten(80%),
ports: (
west: ((id: "in", name: "IN"),),
east: ((id: "out", name: "OUT", kind: "out"),),
),
{
element.block(id: "inner", w: 2, h: 1.5, x: 1.5, y: 0.75,
fill: util.colors.yellow,
ports: (west: ((id: "a"),), east: ((id: "b"),)))
}
)
wire.wire("w-in", ("sh-port-in", "inner-port-a"))
wire.wire("w-out", ("inner-port-b", "sh-port-out"))
```)
#let intersection = example(``` #let intersection = example(```
wire.wire("w1", ((0, 0), (1, 1)), style: "zigzag") wire.wire("w1", ((0, 0), (1, 1)), style: "zigzag")
wire.wire("w2", ((0, 0), (1, -.5)), wire.wire("w2", ((0, 0), (1, -.5)),
style: "zigzag", zigzag-ratio: 80%) style: "zigzag", zigzag-ratio: 80%)
wire.intersection("w1.zig") wire.intersection("w1.zig")
```) ```)
#let port-shape-attach = example(
```
// Pentagon ports expose `.east`, `.west`, `.north`,
// `.south` sub-anchors on the pentagon boundary,
// letting wires attach to any face.
element.block(x: 0, y: 0, w: 2, h: 2, id: "a",
port-shape: "pentagon",
ports: (west: ((id: "p", name: "P"),),))
draw.circle((-2, 0.5), radius: .05, name: "L")
draw.circle(( 3, 1.5), radius: .05, name: "R")
draw.circle((-1, 2.5), radius: .05, name: "T")
// .west = outer flat base
wire.wire("w1", ("L", "a-port-p.west"), style: "direct")
// .east = tip inside the block
wire.wire("w2", ("R", "a-port-p.east"),
style: "direct", color: red)
// .north = top edge midpoint
wire.wire("w3", ("T", "a-port-p.north"),
style: "direct", color: blue)
```,
vertical: true,
)
Binary file not shown.
Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 45 KiB

+1 -1
View File
@@ -1,4 +1,4 @@
#import "@preview/circuiteria:0.2.1": * #import "../src/lib.typ": *
#set page(width: auto, height: auto, margin: .5cm) #set page(width: auto, height: auto, margin: .5cm)
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 142 KiB

+4 -4
View File
@@ -1,4 +1,4 @@
#import "@preview/circuiteria:0.2.1": circuit, element, util, wire #import "../src/lib.typ": circuit, element, util, wire
#set page(width: auto, height: auto, margin: .5cm) #set page(width: auto, height: auto, margin: .5cm)
@@ -117,7 +117,7 @@
wire.wire( wire.wire(
"wExtender-ImmSrc", ( "wExtender-ImmSrc", (
"Extender.north", "Extender.north",
(18, -2) (18, -2, 0)
), ),
style: "zigzag", style: "zigzag",
zigzag-ratio: 0%, zigzag-ratio: 0%,
@@ -138,8 +138,8 @@
) )
wire.wire( wire.wire(
"wBus", ( "wBus", (
(v => (v.at(0), -3.5), mid), (v => (v.at(0), -3.5, 0), mid),
(horizontal: (), vertical: (0, 3.5)), (horizontal: (), vertical: (0, 3.5, 0)),
), ),
bus: true bus: true
) )
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 53 KiB

After

Width:  |  Height:  |  Size: 142 KiB

+4 -4
View File
@@ -1,4 +1,4 @@
#import "@preview/circuiteria:0.2.1": circuit, element, util, wire #import "../src/lib.typ": circuit, element, util, wire
#set page(width: auto, height: auto, margin: .5cm) #set page(width: auto, height: auto, margin: .5cm)
@@ -124,7 +124,7 @@
wire.wire( wire.wire(
"wExtender-ImmSrc", ( "wExtender-ImmSrc", (
"Extender.north", "Extender.north",
(18, -2) (18, -2, 0)
), ),
style: "zigzag", style: "zigzag",
zigzag-ratio: 0%, zigzag-ratio: 0%,
@@ -145,8 +145,8 @@
) )
wire.wire( wire.wire(
"wBus", ( "wBus", (
(v => (v.at(0), -3.5), mid), (v => (v.at(0), -3.5, 0), mid),
(horizontal: (), vertical: (0, 3.5)), (horizontal: (), vertical: (0, 3.5, 0)),
), ),
bus: true bus: true
) )
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 66 KiB

+2 -1
View File
@@ -1,4 +1,5 @@
#import "@preview/circuiteria:0.2.1": circuit, element, util, wire #import "@preview/cetz:0.5.2": draw
#import "../src/lib.typ": circuit, element, util, wire
#set page(width: auto, height: auto, margin: .5cm) #set page(width: auto, height: auto, margin: .5cm)
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 159 KiB

+2 -2
View File
@@ -1,5 +1,5 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "@preview/circuiteria:0.2.1": * #import "../src/lib.typ": *
#set page(width: auto, height: auto, margin: .5cm) #set page(width: auto, height: auto, margin: .5cm)
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 93 KiB

After

Width:  |  Height:  |  Size: 275 KiB

+2 -2
View File
@@ -1,5 +1,5 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "@preview/circuiteria:0.2.1": * #import "../src/lib.typ": *
#set page(width: auto, height: auto, margin: .5cm) #set page(width: auto, height: auto, margin: .5cm)
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

After

Width:  |  Height:  |  Size: 76 KiB

+2 -2
View File
@@ -1,5 +1,5 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw, vector
#import "@preview/circuiteria:0.2.1": * #import "../src/lib.typ": *
#set page(width: auto, height: auto, margin: .5cm) #set page(width: auto, height: auto, margin: .5cm)
BIN
View File
Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

-97
View File
@@ -1,97 +0,0 @@
#import "@preview/circuiteria:0.2.1": circuit, element, util, wire
#set page(width: auto, height: auto, margin: .5cm)
#circuit({
element.iec-gate-buf(
x: 0,
y: 0,
w: 2,
h: 2,
id: "iec-buf",
inputs: 1,
)
wire.stub("iec-buf-port-in0", "west")
element.iec-gate-not(
x: 3,
y: 0,
w: 2,
h: 2,
id: "iec-not",
inputs: 1,
)
wire.stub("iec-not-port-in0", "west")
element.iec-gate-and(
id: "iec-and",
x: 0,
y: -3,
w: 2,
h: 2,
inputs: 2,
)
for i in range(2) {
wire.stub("iec-and-port-in" + str(i), "west")
}
element.iec-gate-nand(
id: "iec-nand",
x: 3,
y: -3,
w: 2,
h: 2,
inputs: 2,
)
for i in range(2) {
wire.stub("iec-nand-port-in" + str(i), "west")
}
element.iec-gate-or(
id: "iec-or",
x: 0,
y: -6,
w: 2,
h: 2,
inputs: 2,
)
for i in range(2) {
wire.stub("iec-or-port-in" + str(i), "west")
}
element.iec-gate-nor(
id: "iec-nor",
x: 3,
y: -6,
w: 2,
h: 2,
inputs: 2,
)
for i in range(2) {
wire.stub("iec-nor-port-in" + str(i), "west")
}
element.iec-gate-xor(
id: "iec-xor",
x: 0,
y: -9,
w: 2,
h: 2,
inputs: 2,
)
for i in range(2) {
wire.stub("iec-xor-port-in" + str(i), "west")
}
element.iec-gate-xnor(
id: "iec-nxor",
x: 3,
y: -9,
w: 2,
h: 2,
inputs: 2,
)
for i in range(2) {
wire.stub("iec-nxor-port-in" + str(i), "west")
}
})
Binary file not shown.

Before

Width:  |  Height:  |  Size: 23 KiB

-86
View File
@@ -1,86 +0,0 @@
// Demonstrates ports on a group element.
// outside-port-names: true (default) — labels outside the group border
// outside-port-names: false — labels inside (block-style)
#import "/src/lib.typ": circuit, element, util, wire
#set page(width: auto, height: auto, margin: .5cm)
#circuit({
// --- Group with port labels INSIDE (outside-port-names: false) ---
element.group(
id: "cpu",
name: "CPU (labels outside)",
name-anchor: "north",
stroke: (dash: "dashed"),
fill: util.colors.yellow.lighten(60%),
padding: 1em,
port-name-padding: .5em,
outside-port-names: true,
ports: (
west: (
(id: "in1", name: "D1"),
(id: "in2", name: "D2"),
),
east: ((id: "out", name: "Q"),),
south: (
(id: "rst", name: "RST", vertical: true),
(id: "done", name: "DONE", vertical: true),
),
),
{
element.block(
id: "reg2",
w: 2.5,
h: 3,
x: 0,
y: 0,
fill: util.colors.green,
ports: (
west: ((id: "d1"), (id: "d2")),
east: ((id: "q"),),
north: ((id: "clk", clock: true),),
),
)
},
)
// --- Group with port labels INSIDE (outside-port-names: false) ---
element.group(
id: "cpu2",
name: "CPU (labels inside)",
name-anchor: "north",
stroke: (dash: "dashed"),
fill: util.colors.yellow.lighten(60%),
padding: 4em,
outside-port-names: false,
port-name-padding: 0.5em,
ports: (
west: (
(id: "in1", name: "D1"),
(id: "in2", name: "D2"),
),
east: ((id: "out", name: "Q"),),
south: (
(id: "rst", name: "RST", vertical: true),
(id: "done", name: "DONE", vertical: true),
),
),
{
element.block(
id: "reg2",
w: 2.5,
h: 3,
x: 10,
y: 0,
fill: util.colors.green,
ports: (
west: ((id: "d1"), (id: "d2")),
east: ((id: "q"),),
north: ((id: "clk", clock: true),),
),
)
},
)
wire.stub("cpu2-port-in1", "west", name: "A")
wire.stub("cpu2-port-in2", "west", name: "B")
wire.stub("cpu2-port-out", "east", name: "Q")
})
Binary file not shown.

Before

Width:  |  Height:  |  Size: 39 KiB

-117
View File
@@ -1,117 +0,0 @@
// Demonstrates pentagon-shaped ports.
//
// - Element-level defaults: `port-shape`, `port-kind`, `port-size`.
// - Per-port overrides: `shape`, `kind`, `size`, `stroke`, `fill`.
// - Wire endpoints connect at the outer end of each pentagon.
// - Clock ports with pentagon shape drop the clock triangle and default
// to a gray fill.
#import "/src/lib.typ": circuit, element, util, wire
#set page(width: auto, height: auto, margin: .5cm)
#circuit({
// -----------------------------------------------------------------
// 1) All four sides × input/output
// -----------------------------------------------------------------
element.block(
id: "grid", w: 4, h: 4, x: 0, y: 0,
name: "sides × in/out", name-anchor: "center",
fill: util.colors.yellow.lighten(60%),
port-shape: "pentagon",
ports: (
west: (
(id: "wi", name: "W-in"),
(id: "wo", name: "W-out", kind: "out"),
),
east: (
(id: "ei", name: "E-in"),
(id: "eo", name: "E-out", kind: "out"),
),
north: (
(id: "ni", name: "N-in", vertical: true),
(id: "no", name: "N-out", kind: "out", vertical: true),
),
south: (
(id: "si", name: "S-in", vertical: true),
(id: "so", name: "S-out", kind: "out", vertical: true),
),
),
)
// -----------------------------------------------------------------
// 2) Per-port styling: fill and stroke overrides + size override
// -----------------------------------------------------------------
element.block(
id: "styled", w: 3, h: 3, x: 10, y: 0,
name: "per-port styling", name-anchor: "center",
fill: util.colors.green.lighten(40%),
port-shape: "pentagon",
ports: (
west: ((id: "a", name: "A", fill: util.colors.blue),),
east: ((id: "b", name: "B", kind: "out",
stroke: red + 1.5pt, fill: util.colors.pink),),
north: ((id: "c", name: "C", size: 1.5em),),
south: ((id: "d", name: "D", kind: "out",
fill: util.colors.orange),),
),
)
// -----------------------------------------------------------------
// 3) Clock port with pentagon → gray fill, no triangle
// -----------------------------------------------------------------
element.block(
id: "clk", w: 3, h: 2.5, x: 16, y: 0,
name: "clock + pentagon", name-anchor: "center",
fill: util.colors.orange.lighten(60%),
port-shape: "pentagon",
ports: (
west: ((id: "d", name: "D"),),
east: ((id: "q", name: "Q", kind: "out"),),
north: ((id: "clk", name: "CLK", clock: true),),
),
)
// -----------------------------------------------------------------
// 4) Two pentagon-ported blocks connected by a wire
// (wire terminates at outer edge of each pentagon)
// -----------------------------------------------------------------
element.block(
id: "src", w: 2, h: 1.5, x: 0, y: -5,
name: "src", name-anchor: "center",
fill: util.colors.pink,
port-shape: "pentagon",
ports: (east: ((id: "q", name: "Q", kind: "out"),)),
)
element.block(
id: "dst", w: 2, h: 1.5, x: 6, y: -5,
name: "dst", name-anchor: "center",
fill: util.colors.blue,
port-shape: "pentagon",
ports: (west: ((id: "d", name: "D"),)),
)
wire.wire("w-sd", ("src-port-q", "dst-port-d"))
// -----------------------------------------------------------------
// 5) Group with pentagon ports enclosing a child block
// -----------------------------------------------------------------
element.group(
id: "g", name: "group w/ pentagon ports", name-anchor: "north",
stroke: (dash: "dashed"),
fill: util.colors.purple.lighten(70%),
padding: 2em,
port-shape: "pentagon",
ports: (
west: ((id: "in", name: "IN"),),
east: ((id: "out", name: "OUT", kind: "out"),),
),
{
element.block(
id: "inner", w: 2, h: 1.5, x: 12, y: -5,
fill: util.colors.green,
ports: (west: ((id: "d"),), east: ((id: "q"),)),
)
},
)
wire.wire("wgi", ("g-port-in", "inner-port-d"))
wire.wire("wgo", ("inner-port-q", "g-port-out"))
})
BIN
View File
Binary file not shown.
+3 -8
View File
@@ -1,5 +1,5 @@
#import "@preview/tidy:0.4.3" #import "@preview/tidy:0.4.3"
#import "/src/cetz.typ": draw, canvas #import "@preview/cetz:0.5.2": draw, canvas
#import "src/lib.typ" #import "src/lib.typ"
#import "doc/examples.typ" #import "doc/examples.typ"
#import "src/circuit.typ": circuit #import "src/circuit.typ": circuit
@@ -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: Simply import Circuiteria and call the `circuit` function:
#pad(left: 1em)[```typ #pad(left: 1em)[```typ
#import "@preview/circuiteria:0.2.1" #import "@preview/circuiteria:0.3.0"
#circuiteria.circuit({ #circuiteria.circuit({
import circuiteria: * import circuiteria: *
... ...
@@ -195,12 +195,7 @@ If you have installed Circuiteria directly in your project, import #link("src/li
read("src/elements/logic/and.typ") + "\n" + read("src/elements/logic/and.typ") + "\n" +
read("src/elements/logic/buf.typ") + "\n" + read("src/elements/logic/buf.typ") + "\n" +
read("src/elements/logic/or.typ") + "\n" + read("src/elements/logic/or.typ") + "\n" +
read("src/elements/logic/xor.typ") + "\n" + read("src/elements/logic/xor.typ"),
read("src/elements/logic/iec_gate.typ") + "\n" +
read("src/elements/logic/iec_and.typ") + "\n" +
read("src/elements/logic/iec_buf.typ") + "\n" +
read("src/elements/logic/iec_or.typ") + "\n" +
read("src/elements/logic/iec_xor.typ"),
name: "gates", name: "gates",
old-syntax: true, old-syntax: true,
scope: ( scope: (
+2
View File
@@ -0,0 +1,2 @@
[tools]
typst = "0.15.0"
-1
View File
@@ -1 +0,0 @@
#import "@preview/cetz:0.5.2": *
+3 -2
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": canvas #import "@preview/cetz:0.5.2": canvas
#import "@preview/tidy:0.4.3" #import "@preview/tidy:0.4.3"
/// Draws a block circuit diagram /// Draws a block circuit diagram
@@ -9,5 +9,6 @@
/// - length (length, ratio): Optional base unit /// - length (length, ratio): Optional base unit
/// -> none /// -> none
#let circuit(body, length: 2em) = { #let circuit(body, length: 2em) = {
set text(font: "Source Sans 3")
canvas(length: length, body) canvas(length: length, body)
} }
-5
View File
@@ -11,10 +11,5 @@
#import "elements/logic/or.typ": gate-or, gate-nor #import "elements/logic/or.typ": gate-or, gate-nor
#import "elements/logic/xor.typ": gate-xor, gate-xnor #import "elements/logic/xor.typ": gate-xor, gate-xnor
#import "elements/logic/buf.typ": gate-buf, gate-not #import "elements/logic/buf.typ": gate-buf, gate-not
#import "elements/logic/iec_gate.typ": iec-gate
#import "elements/logic/iec_and.typ": iec-gate-and, iec-gate-nand
#import "elements/logic/iec_buf.typ": iec-gate-buf, iec-gate-not
#import "elements/logic/iec_or.typ": iec-gate-or, iec-gate-nor
#import "elements/logic/iec_xor.typ": iec-gate-xor, iec-gate-xnor
#import "elements/group.typ": group #import "elements/group.typ": group
+1 -1
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "element.typ" #import "element.typ"
#import "ports.typ": add-port #import "ports.typ": add-port
+6 -34
View File
@@ -1,9 +1,9 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "element.typ" #import "element.typ"
#let draw-shape(id, tl, tr, br, bl, fill, stroke, radius: 0.5em) = { #let draw-shape(id, tl, tr, br, bl, fill, stroke) = {
let f = draw.rect( let f = draw.rect(
radius: radius, radius: 0.5em,
inset: 0.5em, inset: 0.5em,
fill: fill, fill: fill,
stroke: stroke, stroke: stroke,
@@ -16,22 +16,8 @@
/// Draws a block element /// Draws a block element
/// ///
/// #examples.block /// #examples.block
/// /// For parameters description, see #doc-ref("element.elmt")
/// Ports can be given a pentagon shape (with configurable direction, size,
/// stroke and fill) via `port-shape` and per-port overrides:
/// #examples.port-shape
///
/// Port name labels can be placed outside the block via `port-names-outside`:
/// #examples.port-names-outside
/// For other parameters description, see #doc-ref("element.elmt")
/// - radius (number, length, ratio, dictionary): The corner radius of the block. See CeTZ documentation for more information
/// - shell (bool): If true, the block behaves like a shell/container (analogous to a group): port name labels default to being drawn outside the block, and wires attach to the inside tip of pentagon-shaped ports. See #doc-ref("element.elmt")
///
/// Use `shell: true` to wrap child elements inside a bordered container without
/// having ports overlap the interior:
/// #examples.shell
#let block( #let block(
..args,
x: none, x: none,
y: none, y: none,
w: none, w: none,
@@ -40,22 +26,14 @@
name-anchor: "center", name-anchor: "center",
ports: (), ports: (),
ports-margins: (), ports-margins: (),
port-name-padding: 2pt,
port-names-outside: auto,
port-shape: none,
port-kind: "in",
port-size: 1em,
fill: none, fill: none,
radius: 0.5em,
stroke: black + 1pt, stroke: black + 1pt,
id: "", id: "",
shell: false,
debug: ( debug: (
ports: false ports: false
) )
) = element.elmt( ) = element.elmt(
draw-shape: draw-shape.with(radius: radius), draw-shape: draw-shape,
body: if args.pos().len() > 0 { args.pos().first() } else { none },
x: x, x: x,
y: y, y: y,
w: w, w: w,
@@ -64,14 +42,8 @@
name-anchor: name-anchor, name-anchor: name-anchor,
ports: ports, ports: ports,
ports-margins: ports-margins, ports-margins: ports-margins,
port-name-padding: port-name-padding,
port-names-outside: port-names-outside,
port-shape: port-shape,
port-kind: port-kind,
port-size: port-size,
fill: fill, fill: fill,
stroke: stroke, stroke: stroke,
id: id, id: id,
shell: shell,
debug: debug debug: debug
) )
+12 -46
View File
@@ -1,5 +1,5 @@
#import "/src/cetz.typ": coordinate, draw #import "@preview/cetz:0.5.2": draw, coordinate
#import "ports.typ": add-port, add-ports #import "ports.typ": add-ports, add-port
#import "../util.typ" #import "../util.typ"
#let find-port(ports, id) = { #let find-port(ports, id) = {
@@ -34,23 +34,12 @@
/// - `name` (`str`): Optional name displayed *in* the block /// - `name` (`str`): Optional name displayed *in* the block
/// - `clock` (`bool`): Whether it is a clock port (triangle symbol) /// - `clock` (`bool`): Whether it is a clock port (triangle symbol)
/// - `vertical` (`bool`): Whether the name should be drawn vertically /// - `vertical` (`bool`): Whether the name should be drawn vertically
/// - `shape` (`none`, `str`): Optional. Per-port override of the element-level `port-shape` (e.g. `"pentagon"`). Lets a single port on a block or group opt into (or out of) a shape independently of the element default. See the `port-shape` parameter below.
/// - `kind` (`str`): Optional. Per-port override of the element-level `port-kind` (`"in"` / `"out"`). Affects pentagon orientation.
/// - `size` (length): Optional. Per-port override of the element-level `port-size` (unit size of pentagon-shaped ports).
/// - `stroke` (stroke): Optional. Per-port override of the pentagon stroke. Defaults to the element stroke.
/// - `fill` (none, color): Optional. Per-port override of the pentagon fill. Defaults to the element fill (or `gray` for clock ports with `shape: "pentagon"`).
/// - ports-margins (dictionary): Dictionary of ports margins (used with automatic port placement). They keys are cardinal directions ("north", "east", "south", "west"). The values are tuples of (`<start>`, `<end>`) margins (numbers) /// - ports-margins (dictionary): Dictionary of ports margins (used with automatic port placement). They keys are cardinal directions ("north", "east", "south", "west"). The values are tuples of (`<start>`, `<end>`) margins (numbers)
/// - port-name-padding (number, length): Padding between the port name label and the port anchor point (default `2pt`)
/// - port-names-outside (bool, auto): If true, port name labels are drawn on the outside of the block instead of the inside. When `auto` (default), follows the `shell` setting (outside if `shell: true`, inside otherwise)
/// - port-shape (none, str): Default port shape for all ports of this element. Set to `"pentagon"` to draw pentagon-shaped ports. Overridable per port via the port's `shape` field (see the ports dictionary above); a per-port `shape: none` also removes the shape for just that port. See #examples.port-shape
/// - port-kind (str): Default direction of ports (`"in"` or `"out"`). Overridable per port via the port's `kind` field
/// - port-size (length): Default unit size of pentagon-shaped ports (default `1em`). Overridable per port via the port's `size` field
/// - fill (none, color): Fill color /// - fill (none, color): Fill color
/// - stroke (stroke): Border stroke /// - stroke (stroke): Border stroke
/// - id (str): The block id (for future reference) /// - id (str): The block id (for future reference)
/// - auto-ports (bool): Whether to use auto port placements or not. If false, `draw-shape` is responsible for adding the appropiate ports /// - auto-ports (bool): Whether to use auto port placements or not. If false, `draw-shape` is responsible for adding the appropiate ports
/// - ports-y (dictionary): Dictionary of the ports y offsets (used with `auto-ports: false`) /// - ports-y (dictionary): Dictionary of the ports y offsets (used with `auto-ports: false`)
/// - shell (bool): If true, the block behaves like a shell/container (analogous to a group): port name labels default to being drawn *outside* the block border, and wires attach to the *inside* tip of pentagon-shaped ports instead of the outside base. Useful for wrapping child elements without having ports overlap them (default `false`)
/// - debug (dictionary): Dictionary of debug options. /// - debug (dictionary): Dictionary of debug options.
/// ///
/// Supported fields include: /// Supported fields include:
@@ -65,21 +54,14 @@
name-anchor: "center", name-anchor: "center",
ports: (:), ports: (:),
ports-margins: (:), ports-margins: (:),
port-name-padding: 2pt,
port-names-outside: auto,
port-shape: none,
port-kind: "in",
port-size: 1em,
fill: none, fill: none,
stroke: black + 1pt, stroke: black + 1pt,
id: "", id: "",
auto-ports: true, auto-ports: true,
ports-y: (:), ports-y: (:),
shell: false,
body: none,
debug: ( debug: (
ports: false, ports: false
), )
) = draw.get-ctx(ctx => { ) = draw.get-ctx(ctx => {
let width = w let width = w
let height = h let height = h
@@ -94,7 +76,7 @@
if (type(x) == dictionary) { if (type(x) == dictionary) {
let offset = x.rel let offset = x.rel
let to = x.to let to = x.to
let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0), to: to)) let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0, 0), to: to))
x = to-pos.at(0) x = to-pos.at(0)
} }
@@ -113,7 +95,7 @@
let used-pct = 100% - margins.at(0) - margins.at(1) let used-pct = 100% - margins.at(0) - margins.at(1)
let used-height = height * used-pct / 100% let used-height = height * used-pct / 100%
top-margin = height * margins.at(0) / 100% top-margin = height * margins.at(0) / 100%
dy = used-height * (i + 1) / (ports.at(to-side).len() + 1) dy = used-height * (i + 1) / (ports.at(to-side).len() + 1)
if not auto-ports { if not auto-ports {
@@ -127,7 +109,7 @@
dy = height dy = height
top-margin = 0 top-margin = 0
} }
let (ctx, from-pos) = coordinate.resolve(ctx, from) let (ctx, from-pos) = coordinate.resolve(ctx, from)
y = from-pos.at(1) + dy - height + top-margin y = from-pos.at(1) + dy - height + top-margin
} }
@@ -145,35 +127,19 @@
if (name != none) { if (name != none) {
draw.content( draw.content(
(name: id, anchor: name-anchor), (name: id, anchor: name-anchor),
anchor: if name-anchor in util.valid-anchors { name-anchor } else { "center" }, anchor: if name-anchor in util.valid-anchors {name-anchor} else {"center"},
padding: 0.5em, padding: 0.5em,
align(center)[*#name*], align(center)[*#name*]
) )
} }
if auto-ports { if auto-ports {
let outside-name = if port-names-outside == auto { shell } else { port-names-outside }
add-ports( add-ports(
id, id,
tl, tl, tr, br, bl,
tr,
br,
bl,
ports, ports,
ports-margins, ports-margins,
debug: debug.ports, debug: debug.ports
name-padding: port-name-padding,
outside-name: outside-name,
port-shape: port-shape,
port-kind: port-kind,
port-size: port-size,
elmt-stroke: stroke,
elmt-fill: fill,
wire-inside: shell,
) )
} }
})
if body != none {
body
}
})
+1 -1
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "element.typ" #import "element.typ"
#import "ports.typ": add-port #import "ports.typ": add-port
+2 -45
View File
@@ -1,15 +1,9 @@
#import "/src/cetz.typ": draw, coordinate #import "@preview/cetz:0.5.2": draw, coordinate
#import "../util.typ" #import "../util.typ"
#import "ports.typ": add-ports
/// Draws a group of elements /// Draws a group of elements
/// ///
/// #examples.group /// #examples.group
///
/// Ports can also be defined on a group, just like on a block. By default
/// port labels are drawn *outside* the group border so they do not overlap
/// child elements. Set `outside-port-names: false` to draw them inside.
/// #examples.group-ports
/// - body (elements, function): Elements to group /// - body (elements, function): Elements to group
/// - id (str): see #doc-ref("element.elmt") /// - id (str): see #doc-ref("element.elmt")
/// - name (str): The group's name /// - name (str): The group's name
@@ -22,14 +16,6 @@
/// - array: either (`<all>`,), (`<vertical>`, `<horizontal>`) or (`<top>`, `<right>`, `<bottom>`, `<left>`) /// - array: either (`<all>`,), (`<vertical>`, `<horizontal>`) or (`<top>`, `<right>`, `<bottom>`, `<left>`)
/// - dictionary: valid keys are "top", "right", "bottom" and "left" /// - dictionary: valid keys are "top", "right", "bottom" and "left"
/// - radius (number): The corner radius /// - radius (number): The corner radius
/// - ports (dictionary): see #doc-ref("element.elmt")
/// - ports-margins (dictionary): see #doc-ref("element.elmt")
/// - outside-port-names (bool): If `true` (default), port name labels are drawn outside the group border so they do not overlap child elements. Set to `false` to draw labels inside, matching the block behaviour
/// - port-name-padding (number, length): Padding between the port name label and the group border (default `2pt`). Accepts anything CeTZ accepts as `padding` (number or length)
/// - port-shape (none, str): see #doc-ref("element.elmt")
/// - port-kind (str): see #doc-ref("element.elmt")
/// - port-size (length): see #doc-ref("element.elmt")
/// - debug (dictionary): see #doc-ref("element.elmt")
#let group( #let group(
body, body,
id: "", id: "",
@@ -38,17 +24,7 @@
fill: none, fill: none,
stroke: black + 1pt, stroke: black + 1pt,
padding: 0.5em, padding: 0.5em,
radius: 0.5em, radius: 0.5em
ports: (:),
ports-margins: (:),
outside-port-names: true,
port-name-padding: 2pt,
port-shape: none,
port-kind: "in",
port-size: 1em,
debug: (
ports: false
)
) = { ) = {
let min-x = none let min-x = none
let max-x = none let max-x = none
@@ -92,25 +68,6 @@
stroke: stroke, stroke: stroke,
fill: fill fill: fill
) )
add-ports(
id,
id + ".north-west",
id + ".north-east",
id + ".south-east",
id + ".south-west",
ports,
ports-margins,
debug: debug.ports,
outside-name: outside-port-names,
name-padding: port-name-padding,
port-shape: port-shape,
port-kind: port-kind,
port-size: port-size,
elmt-stroke: stroke,
elmt-fill: fill,
)
if name != none { if name != none {
draw.content( draw.content(
id + "." + name-anchor, id + "." + name-anchor,
+1 -1
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "gate.typ" #import "gate.typ"
#let draw-shape(id, tl, tr, br, bl, fill, stroke) = { #let draw-shape(id, tl, tr, br, bl, fill, stroke) = {
+1 -1
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "gate.typ" #import "gate.typ"
#let draw-shape(id, tl, tr, br, bl, fill, stroke) = { #let draw-shape(id, tl, tr, br, bl, fill, stroke) = {
+2 -8
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw, coordinate #import "@preview/cetz:0.5.2": draw, coordinate
#import "../ports.typ": add-ports, add-port #import "../ports.typ": add-ports, add-port
#import "../element.typ" #import "../element.typ"
@@ -51,7 +51,7 @@
if (type(x) == dictionary) { if (type(x) == dictionary) {
let offset = x.rel let offset = x.rel
let to = x.to let to = x.to
let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0), to: to)) let (ctx, to-pos) = coordinate.resolve(ctx, (rel: (offset, 0, 0), to: to))
x = to-pos.at(0) x = to-pos.at(0)
} }
@@ -63,12 +63,6 @@
if to == "out" { if to == "out" {
dy = height / 2 dy = height / 2
} else { } else {
let all-ports = range(inputs).map(i => "in" + str(i))
let i = all-ports.position(p => p == to)
assert(
i != none,
message: "Unknown port '" + y.to + "' must be one of " + repr(all-ports)
)
dy = height * (i + 0.5) / inputs dy = height * (i + 0.5) / inputs
} }
-70
View File
@@ -1,70 +0,0 @@
#import "/src/cetz.typ": draw
// #import "iec_gate.typ" as iec-gate
#import "iec_gate.typ" as iec-gate
/// Draws an IEC-AND gate. This function is also available as `element.iec-gate-and()`
///
/// For parameters, see #doc-ref("gates.iec-gate")
/// #examples.iec-gate-and
#let iec-gate-and(
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
debug: (
ports: false
),
) = {
iec-gate.iec-gate(
x: x,
y: y,
w: w,
h: h,
inputs: inputs,
fill: fill,
stroke: stroke,
id: id,
inverted: inverted,
debug: debug,
symbol: $amp$,
)
}
/// Draws an IEC-NAND gate. This function is also available as `element.iec-gate-nand()`
///
/// For parameters, see #doc-ref("gates.iec-gate")
/// #examples.iec-gate-nand
#let iec-gate-nand(
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
debug: (
ports: false
),
) = {
iec-gate-and(
x: x,
y: y,
w: w,
h: h,
inputs: inputs,
fill: fill,
stroke: stroke,
id: id,
inverted: if inverted != "all" {inverted + ("out",)} else {inverted},
debug: debug,
)
}
-68
View File
@@ -1,68 +0,0 @@
#import "/src/cetz.typ": draw
#import "iec_gate.typ" as iec-gate
/// Draws an IEC buffer gate. This function is also available as `element.iec-gate-buf()`
///
/// For parameters, see #doc-ref("gates.iec-gate")
/// #examples.iec-gate-buf
#let iec-gate-buf(
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
debug: (
ports: false,
),
) = {
iec-gate.iec-gate(
x: x,
y: y,
w: w,
h: h,
inputs: inputs,
fill: fill,
stroke: stroke,
id: id,
inverted: inverted,
debug: debug,
symbol: "1",
)
}
/// Draws an IEC NOT gate. This function is also available as `element.iec-gate-not()`
///
/// For parameters, see #doc-ref("gates.iec-gate")
/// #examples.iec-gate-not
#let iec-gate-not(
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
debug: (
ports: false,
),
) = {
iec-gate-buf(
x: x,
y: y,
w: w,
h: h,
inputs: inputs,
fill: fill,
stroke: stroke,
id: id,
inverted: if inverted != "all" { inverted + ("out",) } else { inverted },
debug: debug,
)
}
-125
View File
@@ -1,125 +0,0 @@
#import "/src/cetz.typ": draw, coordinate
#import "../ports.typ": add-ports, add-port
#import "../element.typ"
#let default-draw-shape(id, tl, tr, br, bl, fill, stroke, symbol) = {
let shapes = draw.rect(
inset: 0.5em,
fill: fill,
stroke: stroke,
name: id,
bl, tr
)
shapes += draw.content(
id + ".center",
[*$ symbol $*]
)
return (shapes, tl, tr, br, bl)
}
/// Draws a logic gate. This function is also available as `element.iec-gate()`
///
/// - draw-shape (function): see #doc-ref("element.elmt")
/// - x (number, dictionary): see #doc-ref("element.elmt")
/// - y (number, dictionary): see #doc-ref("element.elmt")
/// - w (number): see #doc-ref("element.elmt")
/// - h (number): see #doc-ref("element.elmt")
/// - inputs (int): The number of inputs
/// - fill (none, color): see #doc-ref("element.elmt")
/// - stroke (stroke): see #doc-ref("element.elmt")
/// - id (str): see #doc-ref("element.elmt")
/// - inverted (str, array): Either "all" or an array of port ids to display as inverted
/// - inverted-radius (number): The radius of inverted ports dot
/// - debug (dictionary): see #doc-ref("element.elmt")
/// - symbol (str): The symbol to display at the center of the gate
#let iec-gate(
draw-shape: default-draw-shape,
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
inverted-radius: 0.1,
debug: (
ports: false
),
symbol: "",
) = draw.get-ctx(ctx => {
let width = w
let height = h
let x = x
let y = y
if x == none { panic("Parameter x must be set") }
if y == none { panic("Parameter y must be set") }
if w == none { panic("Parameter w must be set") }
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), to: to))
x = to-pos.at(0)
}
if (type(y) == dictionary) {
let from = y.from
let to = y.to
let dy
if to == "out" {
dy = height / 2
} else {
dy = height * (i + 0.5) / inputs
}
let (ctx, from-pos) = coordinate.resolve(ctx, from)
y = from-pos.at(1) + dy - height
}
let tl = (x, y + height)
let tr = (x + width, y + height)
let br = (x + width, y)
let bl = (x, y)
// Workaround because CeTZ needs to have all draw functions in the body
let func = {}
(func, tl, tr, br, bl) = draw-shape(id, tl, tr, br, bl, fill, stroke, symbol)
func
let space = 100% / inputs
for i in range(inputs) {
let pct = (i + 0.5) * space
let port-pos = (tl, pct, bl)
let port-name = "in" + str(i)
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), to: port-pos)
}
add-port(
id, "west",
(id: port-name), port-pos,
debug: debug.ports
)
}
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), to: out-pos)
}
add-port(
id, "east",
(id: "out"), out-pos,
debug: debug.ports
)
})
-67
View File
@@ -1,67 +0,0 @@
#import "/src/cetz.typ": draw
#import "iec_gate.typ" as iec-gate
/// Draws an IEC-OR gate. This function is also available as `element.iec-gate-or()`
///
/// For parameters, see #doc-ref("gates.iec-gate")
/// #examples.iec-gate-or
#let iec-gate-or(
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
debug: (
ports: false
)
) = {
iec-gate.iec-gate(
x: x,
y: y,
w: w,
h: h,
inputs: inputs,
fill: fill,
stroke: stroke,
id: id,
inverted: inverted,
debug: debug,
symbol: $>= 1$,
)
}
/// Draws an IEC-NOR gate. This function is also available as `element.iec-gate-nor()`
///
/// For parameters, see #doc-ref("gates.iec-gate")
/// #examples.iec-gate-nor
#let iec-gate-nor(
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
debug: (
ports: false
)
) = {
iec-gate-or(
x: x,
y: y,
w: w,
h: h,
inputs: inputs,
fill: fill,
stroke: stroke,
id: id,
inverted: if inverted != "all" {inverted + ("out",)} else {inverted},
debug: debug
)
}
-67
View File
@@ -1,67 +0,0 @@
#import "/src/cetz.typ": draw
#import "iec_gate.typ" as iec-gate
/// Draws an IEC-XOR gate. This function is also available as `element.iec-gate-xor()`
///
/// For parameters, see #doc-ref("gates.iec-gate")
/// #examples.iec-gate-xor
#let iec-gate-xor(
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
debug: (
ports: false
)
) = {
iec-gate.iec-gate(
x: x,
y: y,
w: w,
h: h,
inputs: inputs,
fill: fill,
stroke: stroke,
id: id,
inverted: inverted,
debug: debug,
symbol: $= 1$,
)
}
/// Draws an IEC-XNOR gate. This function is also available as `element.iec-gate-xnor()`
///
/// For parameters, see #doc-ref("gates.iec-gate")
/// #examples.iec-gate-xnor
#let iec-gate-xnor(
x: none,
y: none,
w: none,
h: none,
inputs: 2,
fill: none,
stroke: black + 1pt,
id: "",
inverted: (),
debug: (
ports: false
)
) = {
iec-gate-xor(
x: x,
y: y,
w: w,
h: h,
inputs: inputs,
fill: fill,
stroke: stroke,
id: id,
inverted: if inverted != "all" {inverted + ("out",)} else {inverted},
debug: debug
)
}
+1 -1
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "gate.typ" #import "gate.typ"
#let draw-shape(id, tl, tr, br, bl, fill, stroke) = { #let draw-shape(id, tl, tr, br, bl, fill, stroke) = {
+1 -1
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "gate.typ" #import "gate.typ"
#let space = 10% #let space = 10%
+1 -1
View File
@@ -1,4 +1,4 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "../util.typ" #import "../util.typ"
#import "element.typ" #import "element.typ"
#import "ports.typ": add-port #import "ports.typ": add-port
+33 -139
View File
@@ -1,170 +1,72 @@
#import "/src/cetz.typ": draw #import "@preview/cetz:0.5.2": draw
#import "../util.typ": opposite-anchor, port-shape-vertices, rotate-anchor #import "../util.typ": rotate-anchor
#let add-port( #let add-port(
elmt-id, elmt-id, side, port, pos,
side,
port,
pos,
prev: none, prev: none,
next: none, next: none,
debug: false, debug: false
outside-name: false,
name-padding: 2pt,
port-shape: none,
port-kind: "in",
port-size: 1em,
elmt-stroke: black + 1pt,
elmt-fill: none,
wire-inside: false,
) = { ) = {
let name = port.at("name", default: "") let name = port.at("name", default: "")
let name-rotate = port.at("vertical", default: false) let name-rotate = port.at("vertical", default: false)
let is-clock = port.at("clock", default: false)
// Per-port overrides fall back to element-level defaults. if (port.at("clock", default: false)) {
let shape = port.at("shape", default: port-shape)
let kind = port.at("kind", default: port-kind)
let size = port.at("size", default: port-size)
let shape-stroke = port.at("stroke", default: elmt-stroke)
// Pentagon fill defaults to the element's fill (so the pentagon covers the
// block-border segment it crosses). Clock ports default to gray. Per-port
// `fill` overrides both.
let shape-fill = port.at("fill", default: if is-clock and shape == "pentagon" { gray } else {
elmt-fill
})
// When shape is enabled, wire-connection anchor moves outside the block, and
// inside-name labels reference the inner tip/base; otherwise both collapse to
// the boundary point (unchanged behaviour).
let outer-pos = pos
let inner-pos = pos
if shape == "pentagon" {
let sh = port-shape-vertices(side, kind, size)
let v = sh.vertices.map(off => (rel: off, to: pos))
// Draw pentagon on a higher layer so it always renders on top of wires
// and neighbouring elements.
draw.on-layer(1, draw.line(
v.at(0),
v.at(1),
v.at(2),
v.at(3),
v.at(4),
close: true,
stroke: shape-stroke,
fill: shape-fill,
))
outer-pos = (rel: sh.outer, to: pos)
inner-pos = (rel: sh.inner, to: pos)
} else if is-clock {
if prev == none or next == none { if prev == none or next == none {
panic("Clock port must have previous and next positions") panic("Clock port must have previous and next positions")
} }
let csize = if port.at("small", default: false) { 8pt } else { 1em } let size = if port.at("small", default: false) {8pt} else {1em}
let offset let offset
if (side == "north") { offset = (0, -csize) } else if (side == "east") { if (side == "north") { offset = ( 0, -size) }
offset = (-csize, 0) else if (side == "east") { offset = (-size, 0) }
} else if (side == "south") { offset = (0, csize) } else if (side == "west") { else if (side == "south") { offset = ( 0, size) }
offset = (csize, 0) else if (side == "west") { offset = ( size, 0) }
}
let pos1 = (rel: offset, to: pos) let pos1 = (rel: offset, to: pos)
// TODO: use context or vectors to have the height relative to the width // TODO: use context or vectors to have the height relative to the width
draw.line(prev, pos1, next) draw.line(prev, pos1, next)
} }
// When outside-name is true (e.g. for groups) the label is placed on the
// exterior of the element border so it does not overlap child elements.
// Horizontal labels: anchor = opposite of the side (e.g. east port → west-anchored text, outside).
// Vertical labels: same opposite side but rotated 90°, keeping text readable.
let name-anchor = if outside-name {
if name-rotate { rotate-anchor(opposite-anchor(side)) } else { opposite-anchor(side) }
} else {
if name-rotate { rotate-anchor(side) } else { side }
}
// Label sits at the outer edge of the shape for outside-name, inner edge for
// inside-name. `name-padding` is thus naturally measured from the shape edge
// (or from the boundary when shape is disabled).
let label-pos = if outside-name { outer-pos } else { inner-pos }
// For "shell" containers, wires must attach at the inside of the pentagon
// (the tip that points inward), not at the exterior base.
let anchor-pos = if wire-inside and shape == "pentagon" { inner-pos } else { outer-pos }
draw.content( draw.content(
label-pos, pos,
anchor: name-anchor, anchor: if name-rotate {rotate-anchor(side)} else {side},
padding: name-padding, padding: 2pt,
angle: if name-rotate { 90deg } else { 0deg }, angle: if name-rotate {90deg} else {0deg},
name, name
) )
let id = elmt-id + "-port-" + port.at("id") let id = elmt-id + "-port-" + port.at("id")
// Cardinal sub-anchor positions.
// - Pentagon ports: the four world-cardinal midpoints of the pentagon's
// bounding box (all lie on the pentagon boundary).
// - Non-pentagon ports: all four collapse to the default attach point.
let sub-east = anchor-pos
let sub-west = anchor-pos
let sub-north = anchor-pos
let sub-south = anchor-pos
if shape == "pentagon" {
let sh = port-shape-vertices(side, kind, size)
sub-east = (rel: sh.east, to: pos)
sub-west = (rel: sh.west, to: pos)
sub-north = (rel: sh.north, to: pos)
sub-south = (rel: sh.south, to: pos)
}
// Expose the port as a CeTZ group carrying the default attach point plus
// the four cardinal sub-anchors (`.east`, `.west`, `.north`, `.south`).
// The custom anchors override CeTZ's auto-generated bbox anchors of the
// same name.
draw.group(name: id, {
draw.anchor("default", anchor-pos)
draw.anchor("east", sub-east)
draw.anchor("west", sub-west)
draw.anchor("north", sub-north)
draw.anchor("south", sub-south)
})
if debug { if debug {
draw.circle( draw.circle(
anchor-pos, pos,
name: id,
radius: .1, radius: .1,
stroke: none, stroke: none,
fill: red, fill: red
) )
} else {
draw.hide(draw.circle(
pos,
radius: 0,
stroke: none,
name: id
))
} }
} }
#let add-ports( #let add-ports(
elmt-id, elmt-id,
tl, tl, tr, br, bl,
tr,
br,
bl,
ports, ports,
ports-margins, ports-margins,
debug: false, debug: false
outside-name: false,
name-padding: 2pt,
port-shape: none,
port-kind: "in",
port-size: 1em,
elmt-stroke: black + 1pt,
elmt-fill: none,
wire-inside: false,
) = { ) = {
let sides = ( let sides = (
"north": (tl, tr), "north": (tl, tr),
"east": (tr, br), "east": (tr, br),
"south": (bl, br), "south": (bl, br),
"west": (tl, bl), "west": (tl, bl)
) )
if type(ports) != dictionary { if type(ports) != dictionary {
@@ -188,7 +90,7 @@
pt0 = a pt0 = a
pt1 = b pt1 = b
} }
let pos = (pt0, pct, pt1) let pos = (pt0, pct, pt1)
let pct-prev = (i + 0.5) * space let pct-prev = (i + 0.5) * space
let pct-next = (i + 1.5) * space let pct-next = (i + 1.5) * space
@@ -207,16 +109,8 @@
pos, pos,
prev: pos-prev, prev: pos-prev,
next: pos-next, next: pos-next,
debug: debug, debug: debug
outside-name: outside-name,
name-padding: name-padding,
port-shape: port-shape,
port-kind: port-kind,
port-size: port-size,
elmt-stroke: elmt-stroke,
elmt-fill: elmt-fill,
wire-inside: wire-inside,
) )
} }
} }
} }
+1 -6
View File
@@ -2,9 +2,4 @@
#import "elements/logic/and.typ": gate-and, gate-nand #import "elements/logic/and.typ": gate-and, gate-nand
#import "elements/logic/or.typ": gate-or, gate-nor #import "elements/logic/or.typ": gate-or, gate-nor
#import "elements/logic/xor.typ": gate-xor, gate-xnor #import "elements/logic/xor.typ": gate-xor, gate-xnor
#import "elements/logic/buf.typ": gate-buf, gate-not #import "elements/logic/buf.typ": gate-buf, gate-not
#import "elements/logic/iec_gate.typ": iec-gate
#import "elements/logic/iec_and.typ": iec-gate-and, iec-gate-nand
#import "elements/logic/iec_or.typ": iec-gate-or, iec-gate-nor
#import "elements/logic/iec_buf.typ": iec-gate-buf, iec-gate-not
#import "elements/logic/iec_xor.typ": iec-gate-xor, iec-gate-xnor
+1 -2
View File
@@ -1,5 +1,4 @@
#let version = version(0, 2, 1) #let version = version(0, 3, 0)
#let name = "circuiteria"
#import "circuit.typ": circuit #import "circuit.typ": circuit
#import "element.typ" #import "element.typ"
+6 -135
View File
@@ -16,7 +16,7 @@
green: rgb(127, 200, 172), green: rgb(127, 200, 172),
pink: rgb(236, 127, 178), pink: rgb(236, 127, 178),
purple: rgb(189, 151, 255), purple: rgb(189, 151, 255),
blue: rgb(127, 203, 235), blue: rgb(127, 203, 235)
) )
/// Pads a string on the left with 0s to the given length /// Pads a string on the left with 0s to the given length
@@ -47,7 +47,7 @@
north-west: "south-east", north-west: "south-east",
north-east: "south-west", north-east: "south-west",
south-east: "north-west", south-east: "north-west",
south-west: "north-east", south-west: "north-east"
).at(anchor) ).at(anchor)
} }
@@ -66,140 +66,11 @@
north-west: "north-east", north-west: "north-east",
north-east: "south-east", north-east: "south-east",
south-east: "south-west", south-east: "south-west",
south-west: "north-west", south-west: "north-west"
).at(anchor) ).at(anchor)
} }
/// Returns the pentagon port shape vertices and the outer/inner anchor
/// offsets for the given side and direction.
///
/// The pentagon straddles the block boundary: 1 unit outside, 1 unit inside;
/// height ±0.5 units. For `kind: "in"` the tip points into the block; for
/// `kind: "out"` it points away.
///
/// - side (str): One of `"north"`, `"east"`, `"south"`, `"west"`
/// - kind (str): `"in"` or `"out"`
/// - u (length,number): The pentagon unit size
/// -> dictionary: `(vertices: (..5 pairs..), outer: (dx, dy), inner: (dx, dy))`
#let port-shape-vertices(side, kind, u) = {
// Base case: west port, input (tip east / into block).
// Vertices as (dx, dy) offsets relative to the boundary anchor.
let base-vertices = (
(-u, -u / 2),
(-u, +u / 2),
(u / 2, +u / 2),
(u, 0), // tip east (inner side)
(u / 2, -u / 2),
)
// For output, mirror horizontally so the tip points west (outside).
if kind == "out" {
base-vertices = base-vertices.map(p => (-p.at(0), p.at(1)))
}
// Outer (wire-connection) and inner (inside-label) anchors for a west port.
// Outer is always 1u outside the boundary along the port normal; inner is 1u
// inside. Independent of `kind` (only the pentagon fill/tip direction change).
let base-outer = (-u, 0)
let base-inner = (u, 0)
// Rotation from west's frame to target side:
// west: identity (x, y)
// north: (x, y) → (y, -x)
// east: (x, y) → (-x, -y)
// south: (x, y) → (-y, x)
let rot = if side == "west" { p => p } else if side == "north" {
p => (p.at(1), -p.at(0))
} else if side == "east" { p => (-p.at(0), -p.at(1)) } else if side == "south" {
p => (-p.at(1), p.at(0))
} else { panic("Unknown side: " + side) }
// World-cardinal midpoints of the pentagon's bounding box. These are
// named in *world* coordinates (not rotated with the shape), so `.east`
// always sits at the world +x extent of the pentagon, `.north` at +y, etc.
// Consequently the tip's cardinal name follows its world direction:
// - west side, kind "in" → tip world +x → tip = .east
// - west side, kind "out" → tip world -x → tip = .west
// - east side, kind "in" → tip world -x → tip = .west
// - east side, kind "out" → tip world +x → tip = .east
// - north side, kind "in" → tip world -y → tip = .south
// - north side, kind "out" → tip world +y → tip = .north
// - south side, kind "in" → tip world +y → tip = .north
// - south side, kind "out" → tip world -y → tip = .south
//
// The pentagon bounding box extents depend only on the side's orientation
// (horizontal for west/east, vertical for north/south), not on `kind`.
let (hx, hy) = if side == "west" or side == "east" {
(u, u / 2)
} else {
(u / 2, u)
}
let world-east = (hx, 0)
let world-west = (-hx, 0)
let world-north = (0, hy)
let world-south = (0, -hy)
return (
vertices: base-vertices.map(rot),
outer: rot(base-outer),
inner: rot(base-inner),
east: world-east,
west: world-west,
north: world-north,
south: world-south,
)
}
#let valid-anchors = ( #let valid-anchors = (
"center", "center", "north", "east", "west", "south",
"north", "north-east", "north-west", "south-east", "south-west"
"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
}
+7 -106
View File
@@ -1,9 +1,9 @@
#import "/src/cetz.typ": draw, coordinate #import "@preview/cetz:0.5.2": draw, coordinate
#import "util.typ": opposite-anchor, normalize-coord #import "util.typ": opposite-anchor
/// List of valid wire styles /// List of valid wire styles
/// #examples.wires /// #examples.wires
#let wire-styles = ("direct", "zigzag", "dodge", "guided") #let wire-styles = ("direct", "zigzag", "dodge")
#let signal-width = 1pt #let signal-width = 1pt
#let bus-width = 1.5pt #let bus-width = 1.5pt
@@ -68,8 +68,8 @@
let (ctx, p0) = coordinate.resolve(ctx, start) let (ctx, p0) = coordinate.resolve(ctx, start)
let (ctx, p3) = coordinate.resolve(ctx, end) let (ctx, p3) = coordinate.resolve(ctx, end)
p0 = (x: p0.first(), y: p0.at(1)) p0 = (x: p0.at(0), y: p0.at(1))
p3 = (x: p3.first(), y: p3.at(1)) p3 = (x: p3.at(0), y: p3.at(1))
let dx1 = margin-start let dx1 = margin-start
let dx2 = margin-end let dx2 = margin-end
@@ -92,7 +92,7 @@
let points = ( let points = (
start, start,
(horizontal: p1, vertical: ()), (horizontal: p1, vertical: ()),
(horizontal: (), vertical: (0, dodge-y, 0)), (horizontal: (), vertical: (0, dodge-y, 0)),
(horizontal: p2, vertical: ()), (horizontal: p2, vertical: ()),
(horizontal: (), vertical: end), (horizontal: (), vertical: end),
end end
@@ -109,88 +109,6 @@
return (points, anchors) return (points, anchors)
} }
#let get-guided-wire(pts, margins, sides, center-guides, ctx) = {
let start = pts.first()
let end = pts.last()
let (margin-start, margin-end) = margins
let (side-start, side-end) = sides
let (center_horizontal, center_vertical) = center-guides
let (ctx, p0) = coordinate.resolve(ctx, start)
let (ctx, p6) = coordinate.resolve(ctx, end)
p0 = (x: p0.first(), y: p0.at(1))
p6 = (x: p6.first(), y: p6.at(1))
let box_width = calc.abs(p6.x - p0.x)
let box_height = calc.abs(p6.y - p0.y)
// finding correct dx and dy
let dx1 = box_width * margin-start / 100%
if side-start == "west" {
dx1 *= -1
} else if side-start == "north" or side-start == "south" { dx1 = 0}
let dx2 = box_width * margin-end / 100%
if side-end == "west" {
dx2 *= -1
} else if side-end == "north" or side-end == "south" { dx2 = 0}
let dy1 = box_height * margin-start / 100%
if side-start == "south" {
dy1 *= -1
} else if side-start == "west" or side-start == "east" { dy1 = 0}
let dy2 = box_height * margin-end / 100%
if side-end == "south" {
dy2 *= -1
} else if side-end == "west" or side-end == "east" { dy2 = 0}
// points that are closest to the edge points
let p1 = (p0.x + dx1, p0.y + dy1, 0)
let p5 = (p6.x + dx2, p6.y + dy2, 0)
// middle point
let center_x = p0.x + box_width * center_horizontal / 100%
let center_y = p0.y + box_height * center_vertical / 100%
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)
if side-start in ("north", "south") {
p2 = (horizontal: p3, vertical: p1)
} else {
p2 = (horizontal: p1, vertical: p3)
}
if side-end in ("north", "south") {
p4 = (horizontal: p3, vertical: p5)
} else if side-end in ("east", "west") {
p4 = (horizontal: p5, vertical: p3)
}
// returning
let points = (
start,
p1,
p2,
p3,
p4,
p5,
end
)
let anchors = (
"start": start,
"start2": points.at(1),
"guide-start": points.at(2),
"center": points.at(3),
"guide-end": points.at(4),
"end2": points.at(5),
"end": end
)
return (points, anchors)
}
/// Draws a wire between two points /// Draws a wire between two points
/// - id (str): The wire's id, for future reference (anchors) /// - id (str): The wire's id, for future reference (anchors)
/// - pts (array): The two points (as CeTZ compatible coordinates, i.e. XY, relative positions, ids, etc.) /// - pts (array): The two points (as CeTZ compatible coordinates, i.e. XY, relative positions, ids, etc.)
@@ -209,9 +127,6 @@
/// - dodge-y (number): Y position to dodge the wire to (only with style "dodge") /// - dodge-y (number): Y position to dodge the wire to (only with style "dodge")
/// - dodge-sides (array): The start and end sides (going out of the connected element) of the wire (only with style "dodge") /// - dodge-sides (array): The start and end sides (going out of the connected element) of the wire (only with style "dodge")
/// - dodge-margins (array): The start and end margins (i.e. space before dodging) of the wire (only with style "dodge") /// - dodge-margins (array): The start and end margins (i.e. space before dodging) of the wire (only with style "dodge")
/// - guided-center (array): the horizontal and vertical guides of the center guides (only with style "guided")
/// - guided-margins (array): the start and end of guided margins of the wire (only with style "guided")
/// - guided-sides (array): the side of start and end array (must be either "north", "south", "west", "east") (only work with style "guided")
#let wire( #let wire(
id, pts, id, pts,
bus: false, bus: false,
@@ -222,9 +137,6 @@
dashed: false, dashed: false,
style: "direct", style: "direct",
reverse: false, reverse: false,
guided-center: (50%, 50%),
guided-margins: (5%, 5%),
guided-sides: ("east", "west"),
directed: false, directed: false,
rotate-name: true, rotate-name: true,
zigzag-ratio: 50%, zigzag-ratio: 50%,
@@ -240,9 +152,6 @@
if pts.len() != 2 { if pts.len() != 2 {
panic("Wrong number of points (got " + str(pts.len()) + " instead of 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 = ( let stroke = (
paint: color, paint: color,
@@ -269,14 +178,6 @@
dodge-sides, dodge-sides,
ctx ctx
) )
} else if style == "guided" {
(points, anchors) = get-guided-wire(
pts,
guided-margins,
guided-sides,
guided-center,
ctx
)
} }
let mark = (fill: color) let mark = (fill: color)
@@ -402,4 +303,4 @@
name name
) )
} }
} }
+2 -2
View File
@@ -1,6 +1,6 @@
[package] [package]
name = "circuiteria" name = "circuiteria"
version = "0.2.1" version = "0.3.0"
compiler = "0.15.0" compiler = "0.15.0"
repository = "https://git.kb28.ch/HEL/circuiteria" repository = "https://git.kb28.ch/HEL/circuiteria"
entrypoint = "src/lib.typ" entrypoint = "src/lib.typ"
@@ -9,6 +9,6 @@ authors = [
] ]
categories = [ "visualization" ] categories = [ "visualization" ]
license = "Apache-2.0" license = "Apache-2.0"
description = "Drawing block circuits made easy, using CeTZ" description = "Drawing block circuits with Typst made easy, using CeTZ"
keywords = [ "circuit", "block", "draw" ] keywords = [ "circuit", "block", "draw" ]
exclude = [ "gallery", "justfile", "doc" ] exclude = [ "gallery", "justfile", "doc" ]