Compare commits
8 Commits
v0.1.0
...
26231b2f48
Author | SHA1 | Date | |
---|---|---|---|
26231b2f48
|
|||
5616544707
|
|||
358de4825d
|
|||
2bb7e3b5a9 | |||
371caf094c
|
|||
841f53e76c | |||
ff0b91e683
|
|||
e1e561bb6c
|
@ -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.1.0"
|
#import "@preview/circuiteria:0.2.0"
|
||||||
#circuiteria.circuit({
|
#circuiteria.circuit({
|
||||||
import circuiteria: *
|
import circuiteria: *
|
||||||
...
|
...
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "../src/circuit.typ": circuit
|
#import "../src/circuit.typ": circuit
|
||||||
#import "../src/util.typ"
|
#import "../src/util.typ"
|
||||||
|
|
||||||
|
40
gallery.bash
@ -1,40 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
PDFS=false
|
|
||||||
|
|
||||||
while getopts "p" flag
|
|
||||||
do
|
|
||||||
case "${flag}" in
|
|
||||||
p) PDFS=true;;
|
|
||||||
esac
|
|
||||||
done
|
|
||||||
|
|
||||||
echo "Generating gallery images"
|
|
||||||
|
|
||||||
set -- ./gallery/*.typ
|
|
||||||
cnt="$#"
|
|
||||||
i=1
|
|
||||||
for f
|
|
||||||
do
|
|
||||||
f2="${f/typ/png}"
|
|
||||||
echo "($i/$cnt) $f -> $f2"
|
|
||||||
typst c --root ./ "$f" "$f2"
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
|
|
||||||
if [ "$PDFS" = true ]
|
|
||||||
then
|
|
||||||
echo
|
|
||||||
echo "Generating gallery PDFs"
|
|
||||||
|
|
||||||
set -- ./gallery/*.typ
|
|
||||||
cnt="$#"
|
|
||||||
i=1
|
|
||||||
for f
|
|
||||||
do
|
|
||||||
f2="${f/typ/pdf}"
|
|
||||||
echo "($i/$cnt) $f -> $f2"
|
|
||||||
typst c --root ./ "$f" "$f2"
|
|
||||||
i=$((i+1))
|
|
||||||
done
|
|
||||||
fi
|
|
Before Width: | Height: | Size: 45 KiB After Width: | Height: | Size: 45 KiB |
BIN
gallery/target_api.pdf
Normal file
283
gallery/target_api.typ
Normal file
@ -0,0 +1,283 @@
|
|||||||
|
#import "../src/lib.typ": *
|
||||||
|
#import "@preview/cetz:0.3.4": draw
|
||||||
|
#circuit({
|
||||||
|
element.block(
|
||||||
|
size: (1.5, 2.2),
|
||||||
|
id: "PCBuf",
|
||||||
|
fill: util.colors.orange,
|
||||||
|
ports: (
|
||||||
|
west: "PCNext",
|
||||||
|
north: (id: "CLK", clock: true),
|
||||||
|
east: "PC",
|
||||||
|
south: (("EN", "EN"),)
|
||||||
|
),
|
||||||
|
debug: (ports: true)
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.stub("PCBuf.CLK", name: "CLK")
|
||||||
|
wire.stub("PCBuf.EN", name: "PCWrite")
|
||||||
|
|
||||||
|
/*
|
||||||
|
element.multiplexer(
|
||||||
|
pos: (
|
||||||
|
3, (align: "in0", with: "PCBuf.PC")
|
||||||
|
),
|
||||||
|
size: (1, 2),
|
||||||
|
id: "AdrSrc-MP",
|
||||||
|
fill: util.colors.orange,
|
||||||
|
entries: 2
|
||||||
|
)
|
||||||
|
wire.wire(
|
||||||
|
"PCBuf.PC",
|
||||||
|
"AdrSrc-MP.in0",
|
||||||
|
id: "wPCBuf-InstDataMgr",
|
||||||
|
name: "PC",
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
wire.stub("AdrSrc-MP.north", name: "AdrSrc")
|
||||||
|
|
||||||
|
element.block(
|
||||||
|
pos: (
|
||||||
|
6, (align: "A", with: "AdrSrc-MP.out")
|
||||||
|
),
|
||||||
|
size: (3, 4),
|
||||||
|
id: "InstDataMgr",
|
||||||
|
fill: util.colors.yellow,
|
||||||
|
ports: (
|
||||||
|
west: (
|
||||||
|
("A", "A"),
|
||||||
|
("WD", "WD")
|
||||||
|
),
|
||||||
|
north: (
|
||||||
|
(id: "CLK", clock: true),
|
||||||
|
(id: "WE", name: "WE", vertical: true),
|
||||||
|
(id: "IRWrite", name: "IRWrite", vertical: true)
|
||||||
|
),
|
||||||
|
east: (
|
||||||
|
("Instr", "Instr."),
|
||||||
|
("RD", "RD")
|
||||||
|
)
|
||||||
|
),
|
||||||
|
ports-margins: (
|
||||||
|
west: (30%, 0%),
|
||||||
|
east: (40%, 0%)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
wire.wire(
|
||||||
|
"AdrSrc-MP.out",
|
||||||
|
"InstDataMgr.A",
|
||||||
|
id: "wAdrSrcMP-InstDataMgr",
|
||||||
|
name: (none, "Adr"),
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.stub("InstDataMgr.CLK", name: "CLK")
|
||||||
|
wire.stub("InstDataMgr.WE")
|
||||||
|
wire.stub("InstDataMgr.IRWrite")
|
||||||
|
wire.stub("InstDataMgr.WD")
|
||||||
|
|
||||||
|
element.block(
|
||||||
|
pos: (
|
||||||
|
15, (align: "WD3", with: "InstDataMgr.RD")
|
||||||
|
),
|
||||||
|
size: (3, 4),
|
||||||
|
id: "RegFile",
|
||||||
|
fill: util.colors.pink,
|
||||||
|
ports: (
|
||||||
|
west: (
|
||||||
|
("A1", "A1"),
|
||||||
|
("A2", "A2"),
|
||||||
|
("A3", "A3"),
|
||||||
|
("WD3", "WD3"),
|
||||||
|
),
|
||||||
|
north: (
|
||||||
|
(id: "CLK", clock: true),
|
||||||
|
(id: "WE3", name: "WE3", vertical: true)
|
||||||
|
),
|
||||||
|
east: (
|
||||||
|
("RD1", "RD1"),
|
||||||
|
("RD2", "RD2"),
|
||||||
|
)
|
||||||
|
),
|
||||||
|
ports-margins: (
|
||||||
|
east: (20%, 20%)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
wire.stub("RegFile.CLK", name: "CLK")
|
||||||
|
wire.stub("RegFile.WE3", name: "Regwrite", name-offset: 0.6)
|
||||||
|
wire.stub("RegFile.A2")
|
||||||
|
wire.stub("RegFile.RD2")
|
||||||
|
|
||||||
|
element.extender(
|
||||||
|
pos: (15, -3.5),
|
||||||
|
size: (3, 1),
|
||||||
|
id: "Extender",
|
||||||
|
fill: util.colors.green
|
||||||
|
)
|
||||||
|
wire.wire(
|
||||||
|
"Extender.north",
|
||||||
|
(18, -2),
|
||||||
|
id: "wExtender-ImmSrc",
|
||||||
|
style: "zigzag",
|
||||||
|
zigzag-ratio: 0%,
|
||||||
|
name: (none, "ImmSrc"),
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
let mid = ("InstDataMgr.east", 50%, "RegFile.west")
|
||||||
|
wire.wire(
|
||||||
|
"InstDataMgr.Instr",
|
||||||
|
(vertical: (), horizontal: mid),
|
||||||
|
id: "wInstDataMgr-Bus"
|
||||||
|
name: ("Instr", none),
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
wire.wire(
|
||||||
|
(v => (v.at(0), -3.5), mid),
|
||||||
|
(horizontal: (), vertical: (0, 3.5)),
|
||||||
|
id: "wBus",
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
wire.wire(
|
||||||
|
"RegFile.A1",
|
||||||
|
(horizontal: mid, vertical: ()),
|
||||||
|
id: "wBus-RegFile-A1"
|
||||||
|
name: (none, "RS1"),
|
||||||
|
slice: (19, 15),
|
||||||
|
reverse: true,
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
wire.wire(
|
||||||
|
"RegFile.A3",
|
||||||
|
(horizontal: mid, vertical: ()),
|
||||||
|
id: "wBus-RegFile-A3"
|
||||||
|
name: (none, "RD"),
|
||||||
|
slice: (11, 7),
|
||||||
|
reverse: true,
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
wire.wire(
|
||||||
|
"Extender.in",
|
||||||
|
(horizontal: mid, vertical: ()),
|
||||||
|
id: "wBus-Extender"
|
||||||
|
slice: (31, 7),
|
||||||
|
reverse: true,
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
element.alu(
|
||||||
|
pos: (
|
||||||
|
22, (align: "in1", with: "RegFile.RD1")
|
||||||
|
),
|
||||||
|
size: (1, 2),
|
||||||
|
id: "ALU",
|
||||||
|
fill: util.colors.purple
|
||||||
|
)
|
||||||
|
wire.wire(
|
||||||
|
"RegFile.RD1",
|
||||||
|
"ALU.in1",
|
||||||
|
id: "wRegFile-ALU"
|
||||||
|
name: ("A", "SrcA"),
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
element.block(
|
||||||
|
pos: (
|
||||||
|
26, (align: "in", with: "ALU.out")
|
||||||
|
),
|
||||||
|
size: (1.5, 2),
|
||||||
|
id: "OutBuf",
|
||||||
|
fill: util.colors.orange,
|
||||||
|
ports: (
|
||||||
|
west: "in",
|
||||||
|
north: (id: "CLK", clock: true),
|
||||||
|
east: "out"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
wire.stub("OutBuf.CLK", name: "CLK")
|
||||||
|
wire.wire(
|
||||||
|
"ALU.out",
|
||||||
|
"OutBuf.in",
|
||||||
|
id: "wALU-OutBuf"
|
||||||
|
name: "ALUResult",
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
element.multiplexer(
|
||||||
|
pos: (
|
||||||
|
30, (align: "in0", with: "OutBuf.out")
|
||||||
|
),
|
||||||
|
size: (1, 2.5),
|
||||||
|
id: "Res-MP",
|
||||||
|
fill: util.colors.orange,
|
||||||
|
entries: 3
|
||||||
|
)
|
||||||
|
wire.stub("Res-MP.north", name: "ResultSrc")
|
||||||
|
wire.stub("Res-MP.in2")
|
||||||
|
wire.wire(
|
||||||
|
"OutBuf.out",
|
||||||
|
"Res-MP.in0",
|
||||||
|
id: "wOutBuf-ResMP"
|
||||||
|
name: "ALUOut",
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.wire(
|
||||||
|
"Extender.out",
|
||||||
|
"ALU.in2",
|
||||||
|
id: "wExt-ALU"
|
||||||
|
name: ("ImmExt", "SrcB"),
|
||||||
|
bus: true,
|
||||||
|
style: "zigzag",
|
||||||
|
zigzag-ratio: 60%
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.wire(
|
||||||
|
"InstDataMgr.RD",
|
||||||
|
"Res-MP.in1",
|
||||||
|
id: "wInstDataMgr-ResMP"
|
||||||
|
style: "dodge",
|
||||||
|
dodge-y: -4,
|
||||||
|
dodge-sides: ("east", "west"),
|
||||||
|
name: ("Data", none),
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.wire(
|
||||||
|
"Res-MP.out",
|
||||||
|
"AdrSrc-MP.in1",
|
||||||
|
id: "wResMP-AdrSrc"
|
||||||
|
style: "dodge",
|
||||||
|
dodge-y: -5,
|
||||||
|
dodge-sides: ("east", "west"),
|
||||||
|
dodge-margins: (0.5, 1),
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.wire(
|
||||||
|
"Res-MP.out",
|
||||||
|
"RegFile.WD3",
|
||||||
|
id: "wResMP-RegFile"
|
||||||
|
style: "dodge",
|
||||||
|
dodge-y: -5,
|
||||||
|
dodge-sides: ("east", "west"),
|
||||||
|
dodge-margins: (0.5, 1),
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.wire(
|
||||||
|
"Res-MP.out",
|
||||||
|
"PCBuf.PCNext",
|
||||||
|
id: "wResMP-PCBuf"
|
||||||
|
style: "dodge",
|
||||||
|
dodge-y: -5,
|
||||||
|
dodge-sides: ("east", "west"),
|
||||||
|
dodge-margins: (0.5, 1.5),
|
||||||
|
name: (none, "PCNext"),
|
||||||
|
bus: true
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.intersection("wResMP-RegFile.dodge-end", radius: .2)
|
||||||
|
wire.intersection("wResMP-AdrSrc.dodge-end", radius: .2)
|
||||||
|
*/
|
||||||
|
})
|
BIN
gallery/test.png
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 142 KiB After Width: | Height: | Size: 142 KiB |
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 66 KiB |
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "../src/lib.typ": 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)
|
||||||
|
Before Width: | Height: | Size: 159 KiB After Width: | Height: | Size: 159 KiB |
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "../src/lib.typ": *
|
#import "../src/lib.typ": *
|
||||||
|
|
||||||
#set page(width: auto, height: auto, margin: .5cm)
|
#set page(width: auto, height: auto, margin: .5cm)
|
||||||
|
Before Width: | Height: | Size: 276 KiB After Width: | Height: | Size: 275 KiB |
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "../src/lib.typ": *
|
#import "../src/lib.typ": *
|
||||||
|
|
||||||
#set page(width: auto, height: auto, margin: .5cm)
|
#set page(width: auto, height: auto, margin: .5cm)
|
||||||
|
Before Width: | Height: | Size: 76 KiB After Width: | Height: | Size: 76 KiB |
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw, vector
|
#import "@preview/cetz:0.3.2": draw, vector
|
||||||
#import "../src/lib.typ": *
|
#import "../src/lib.typ": *
|
||||||
|
|
||||||
#set page(width: auto, height: auto, margin: .5cm)
|
#set page(width: auto, height: auto, margin: .5cm)
|
||||||
|
11
justfile
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
# Local Variables:
|
||||||
|
# mode: makefile
|
||||||
|
# End:
|
||||||
|
gallery_dir := "./gallery"
|
||||||
|
set shell := ["bash", "-uc"]
|
||||||
|
|
||||||
|
manual:
|
||||||
|
typst c manual.typ manual.pdf
|
||||||
|
|
||||||
|
gallery:
|
||||||
|
for f in "{{gallery_dir}}"/*.typ; do typst c --root . "$f" "${f%typ}png"; done
|
BIN
manual.pdf
41
manual.typ
@ -1,5 +1,5 @@
|
|||||||
#import "@preview/tidy:0.3.0"
|
#import "@preview/tidy:0.4.1"
|
||||||
#import "@preview/cetz:0.2.2": draw, canvas
|
#import "@preview/cetz:0.3.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
|
||||||
@ -12,7 +12,7 @@
|
|||||||
numbering("1.1", ..num)
|
numbering("1.1", ..num)
|
||||||
})
|
})
|
||||||
#{
|
#{
|
||||||
outline(indent: true, depth: 3)
|
outline(indent: auto, depth: 3)
|
||||||
}
|
}
|
||||||
|
|
||||||
#show link: set text(blue)
|
#show link: set text(blue)
|
||||||
@ -47,7 +47,7 @@
|
|||||||
|
|
||||||
#set page(numbering: "1/1", header: align(right)[circuiteria #sym.dash.em v#lib.version])
|
#set page(numbering: "1/1", header: align(right)[circuiteria #sym.dash.em v#lib.version])
|
||||||
#set page(
|
#set page(
|
||||||
header: locate(loc => {
|
header: context {
|
||||||
let txt = [circuiteria #sym.dash.em v#lib.version]
|
let txt = [circuiteria #sym.dash.em v#lib.version]
|
||||||
let cnt = counter(heading)
|
let cnt = counter(heading)
|
||||||
let cnt-val = cnt.get()
|
let cnt-val = cnt.get()
|
||||||
@ -65,8 +65,8 @@
|
|||||||
#rect(width: 100%, height: .5em, radius: .25em, stroke: none, fill: util.colors.values().at(i))
|
#rect(width: 100%, height: .5em, radius: .25em, stroke: none, fill: util.colors.values().at(i))
|
||||||
]
|
]
|
||||||
)
|
)
|
||||||
}),
|
},
|
||||||
footer: locate(loc => {
|
footer: context {
|
||||||
let cnt = counter(heading)
|
let cnt = counter(heading)
|
||||||
let cnt-val = cnt.get()
|
let cnt-val = cnt.get()
|
||||||
if cnt-val.len() < 2 { return }
|
if cnt-val.len() < 2 { return }
|
||||||
@ -80,12 +80,12 @@
|
|||||||
],
|
],
|
||||||
counter(page).display("1/1", both: true)
|
counter(page).display("1/1", both: true)
|
||||||
)
|
)
|
||||||
})
|
}
|
||||||
)
|
)
|
||||||
|
|
||||||
#let doc-ref(target, full: false, var: false) = {
|
#let doc-ref(target, full: false, var: false) = {
|
||||||
let (module, func) = target.split(".")
|
let (module, func) = target.split(".")
|
||||||
let label-name = module + func
|
let label-name = module + "-" + func
|
||||||
let display-name = func
|
let display-name = func
|
||||||
if full {
|
if full {
|
||||||
display-name = target
|
display-name = target
|
||||||
@ -94,7 +94,7 @@
|
|||||||
label-name += "()"
|
label-name += "()"
|
||||||
display-name += "()"
|
display-name += "()"
|
||||||
}
|
}
|
||||||
link(label(label-name))[#display-name]
|
link(label(label-name), raw(display-name))
|
||||||
}
|
}
|
||||||
|
|
||||||
= Introduction
|
= Introduction
|
||||||
@ -103,11 +103,21 @@ This package provides a way to make beautiful block circuit diagrams using the C
|
|||||||
|
|
||||||
= Usage
|
= Usage
|
||||||
|
|
||||||
Simply import #link("src/lib.typ") and call the `circuit` function:
|
Simply import Circuiteria and call the `circuit` function:
|
||||||
#pad(left: 1em)[```typ
|
#pad(left: 1em)[```typ
|
||||||
#import "src/lib.typ"
|
#import "@preview/circuiteria:0.2.0"
|
||||||
#lib.circuit({
|
#circuiteria.circuit({
|
||||||
import lib: *
|
import circuiteria: *
|
||||||
|
...
|
||||||
|
})
|
||||||
|
```]
|
||||||
|
|
||||||
|
== Project installation
|
||||||
|
If you have installed Circuiteria directly in your project, import #link("src/lib.typ") and call the `circuit` function:
|
||||||
|
#pad(left: 1em)[```typ
|
||||||
|
#import "src/lib.typ" as circuiteria
|
||||||
|
#circuiteria.circuit({
|
||||||
|
import circuiteria: *
|
||||||
...
|
...
|
||||||
})
|
})
|
||||||
```]
|
```]
|
||||||
@ -117,6 +127,7 @@ Simply import #link("src/lib.typ") and call the `circuit` function:
|
|||||||
#let circuit-docs = tidy.parse-module(
|
#let circuit-docs = tidy.parse-module(
|
||||||
read("src/circuit.typ"),
|
read("src/circuit.typ"),
|
||||||
name: "circuit",
|
name: "circuit",
|
||||||
|
old-syntax: true,
|
||||||
require-all-parameters: true
|
require-all-parameters: true
|
||||||
)
|
)
|
||||||
#tidy.show-module(circuit-docs)
|
#tidy.show-module(circuit-docs)
|
||||||
@ -126,6 +137,7 @@ Simply import #link("src/lib.typ") and call the `circuit` function:
|
|||||||
#let util-docs = tidy.parse-module(
|
#let util-docs = tidy.parse-module(
|
||||||
read("src/util.typ"),
|
read("src/util.typ"),
|
||||||
name: "util",
|
name: "util",
|
||||||
|
old-syntax: true,
|
||||||
require-all-parameters: true,
|
require-all-parameters: true,
|
||||||
scope: (
|
scope: (
|
||||||
util: util,
|
util: util,
|
||||||
@ -140,6 +152,7 @@ Simply import #link("src/lib.typ") and call the `circuit` function:
|
|||||||
#let wire-docs = tidy.parse-module(
|
#let wire-docs = tidy.parse-module(
|
||||||
read("src/wire.typ"),
|
read("src/wire.typ"),
|
||||||
name: "wire",
|
name: "wire",
|
||||||
|
old-syntax: true,
|
||||||
require-all-parameters: true,
|
require-all-parameters: true,
|
||||||
scope: (
|
scope: (
|
||||||
wire: wire,
|
wire: wire,
|
||||||
@ -161,6 +174,7 @@ Simply import #link("src/lib.typ") and call the `circuit` function:
|
|||||||
read("src/elements/multiplexer.typ") + "\n" +
|
read("src/elements/multiplexer.typ") + "\n" +
|
||||||
read("src/elements/group.typ"),
|
read("src/elements/group.typ"),
|
||||||
name: "element",
|
name: "element",
|
||||||
|
old-syntax: true,
|
||||||
scope: (
|
scope: (
|
||||||
element: element,
|
element: element,
|
||||||
circuit: circuit,
|
circuit: circuit,
|
||||||
@ -183,6 +197,7 @@ Simply import #link("src/lib.typ") and call the `circuit` function:
|
|||||||
read("src/elements/logic/or.typ") + "\n" +
|
read("src/elements/logic/or.typ") + "\n" +
|
||||||
read("src/elements/logic/xor.typ"),
|
read("src/elements/logic/xor.typ"),
|
||||||
name: "gates",
|
name: "gates",
|
||||||
|
old-syntax: true,
|
||||||
scope: (
|
scope: (
|
||||||
element: element,
|
element: element,
|
||||||
circuit: circuit,
|
circuit: circuit,
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": canvas
|
#import "@preview/cetz:0.3.2": canvas
|
||||||
#import "@preview/tidy:0.3.0"
|
#import "@preview/tidy:0.3.0"
|
||||||
|
|
||||||
/// Draws a block circuit diagram
|
/// Draws a block circuit diagram
|
||||||
@ -9,6 +9,52 @@
|
|||||||
/// - 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")
|
let next-id = 0
|
||||||
canvas(length: length, body)
|
let elements = (:)
|
||||||
|
let ids = ()
|
||||||
|
for e in body {
|
||||||
|
if type(e) == dictionary and "id" in e {
|
||||||
|
ids.push(e.id)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for element in body {
|
||||||
|
let internal = type(element) == dictionary and "id" in element
|
||||||
|
let eid = if internal {element.id} else {auto}
|
||||||
|
if eid == auto {
|
||||||
|
while str(next-id) in ids {
|
||||||
|
next-id += 1
|
||||||
|
}
|
||||||
|
eid = str(next-id)
|
||||||
|
ids.push(eid)
|
||||||
|
if internal {
|
||||||
|
element.id = eid
|
||||||
|
}
|
||||||
|
next-id += 1
|
||||||
|
}
|
||||||
|
if eid in elements {
|
||||||
|
panic("An element with the id '" + eid + "' already exists. Please use a different id")
|
||||||
|
}
|
||||||
|
elements.insert(eid, element)
|
||||||
|
}
|
||||||
|
|
||||||
|
for element in elements.values() {
|
||||||
|
if type(element) == dictionary and "pre-process" in element {
|
||||||
|
elements = (element.pre-process)(elements, element)
|
||||||
|
assert(
|
||||||
|
type(elements) == dictionary,
|
||||||
|
message: "The `pre-process` method of element '" + element.id + "' did not return the elements dictionary"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
canvas(length: length, {
|
||||||
|
for element in elements.values() {
|
||||||
|
if type(element) == dictionary and "draw" in element {
|
||||||
|
(element.draw)(element)
|
||||||
|
} else {
|
||||||
|
(element,)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "element.typ"
|
#import "element.typ"
|
||||||
#import "ports.typ": add-port
|
#import "ports.typ": add-port
|
||||||
|
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "element.typ"
|
#import "element.typ"
|
||||||
|
|
||||||
#let draw-shape(id, tl, tr, br, bl, fill, stroke) = {
|
#let draw-shape(elmt, bounds) = {
|
||||||
let f = draw.rect(
|
let f = draw.rect(
|
||||||
radius: 0.5em,
|
radius: 0.5em,
|
||||||
inset: 0.5em,
|
inset: 0.5em,
|
||||||
fill: fill,
|
fill: elmt.fill,
|
||||||
stroke: stroke,
|
stroke: elmt.stroke,
|
||||||
name: id,
|
bounds.bl, bounds.tr
|
||||||
bl, tr
|
|
||||||
)
|
)
|
||||||
return (f, tl, tr, br, bl)
|
return (f, bounds)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws a block element
|
/// Draws a block element
|
||||||
@ -18,32 +17,8 @@
|
|||||||
/// #examples.block
|
/// #examples.block
|
||||||
/// For parameters description, see #doc-ref("element.elmt")
|
/// For parameters description, see #doc-ref("element.elmt")
|
||||||
#let block(
|
#let block(
|
||||||
x: none,
|
..args
|
||||||
y: none,
|
|
||||||
w: none,
|
|
||||||
h: none,
|
|
||||||
name: none,
|
|
||||||
name-anchor: "center",
|
|
||||||
ports: (),
|
|
||||||
ports-margins: (),
|
|
||||||
fill: none,
|
|
||||||
stroke: black + 1pt,
|
|
||||||
id: "",
|
|
||||||
debug: (
|
|
||||||
ports: false
|
|
||||||
)
|
|
||||||
) = element.elmt(
|
) = element.elmt(
|
||||||
draw-shape: draw-shape,
|
draw-shape: draw-shape,
|
||||||
x: x,
|
..args
|
||||||
y: y,
|
|
||||||
w: w,
|
|
||||||
h: h,
|
|
||||||
name: name,
|
|
||||||
name-anchor: name-anchor,
|
|
||||||
ports: ports,
|
|
||||||
ports-margins: ports-margins,
|
|
||||||
fill: fill,
|
|
||||||
stroke: stroke,
|
|
||||||
id: id,
|
|
||||||
debug: debug
|
|
||||||
)
|
)
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw, coordinate
|
#import "@preview/cetz:0.3.2": draw, coordinate, matrix, vector
|
||||||
#import "ports.typ": add-ports, add-port
|
#import "ports.typ": add-ports, add-port
|
||||||
#import "../util.typ"
|
#import "../util.typ"
|
||||||
|
|
||||||
@ -13,10 +13,175 @@
|
|||||||
panic("Could not find port with id " + str(id))
|
panic("Could not find port with id " + str(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
#let default-draw-shape(id, tl, tr, br, bl, fill, stroke) = {
|
#let local-to-global(origin, u, v, points) = {
|
||||||
return ({}, tl, tr, br, bl)
|
return points-real = points.map(p => {
|
||||||
|
let (pu, pv) = p
|
||||||
|
return vector.add(
|
||||||
|
origin,
|
||||||
|
vector.add(
|
||||||
|
vector.scale(u, pu),
|
||||||
|
vector.scale(v, pv)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#let default-draw-shape(elmt, bounds) = {
|
||||||
|
return ({}, bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let default-pre-process(elements, element) = {
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
|
||||||
|
#let resolve-offset(ctx, offset, from, axis) = {
|
||||||
|
let (ctx, pos) = coordinate.resolve(
|
||||||
|
ctx,
|
||||||
|
(rel: offset, to: from)
|
||||||
|
)
|
||||||
|
return pos.at(axis)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let resolve-align(ctx, elmt, align, with, axis) = {
|
||||||
|
let (align-side, i) = find-port(elmt.ports, align)
|
||||||
|
let margins = (0%, 0%)
|
||||||
|
if align-side in elmt.ports-margins {
|
||||||
|
margins = elmt.ports-margins.at(align-side)
|
||||||
|
}
|
||||||
|
|
||||||
|
let parallel-sides = (
|
||||||
|
("north", "south"),
|
||||||
|
("west", "east")
|
||||||
|
).at(axis)
|
||||||
|
|
||||||
|
let ortho-sides = (
|
||||||
|
("west", "east"),
|
||||||
|
("north", "south")
|
||||||
|
).at(axis)
|
||||||
|
|
||||||
|
let dl
|
||||||
|
let start-margin
|
||||||
|
let len = elmt.size.at(axis)
|
||||||
|
if align-side in parallel-sides {
|
||||||
|
let used-pct = 100% - margins.at(0) - margins.at(1)
|
||||||
|
let used-len = len * used-pct / 100%
|
||||||
|
start-margin = len * margins.at(0) / 100%
|
||||||
|
|
||||||
|
dl = used-len * (i + 1) / (elmt.ports.at(align-side).len() + 1)
|
||||||
|
|
||||||
|
if not elmt.auto-ports {
|
||||||
|
start-margin = 0
|
||||||
|
dl = elmt.ports-pos.at(with)(len)
|
||||||
|
}
|
||||||
|
} else if align-side == ortho-sides.first() {
|
||||||
|
dl = 0
|
||||||
|
start-margin = 0
|
||||||
|
} else {
|
||||||
|
dl = len
|
||||||
|
start-margin = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
if axis == 1 {
|
||||||
|
dl = len - dl
|
||||||
|
}
|
||||||
|
|
||||||
|
let (ctx, with-pos) = coordinate.resolve(ctx, with)
|
||||||
|
return with-pos.at(axis) - dl + start-margin
|
||||||
|
}
|
||||||
|
|
||||||
|
#let resolve-coordinate(ctx, elmt, coord, axis) = {
|
||||||
|
if type(coord) == dictionary {
|
||||||
|
let offset = coord.at("offset", default: none)
|
||||||
|
let from = coord.at("from", default: none)
|
||||||
|
let align = coord.at("align", default: none)
|
||||||
|
let with = coord.at("with", default: none)
|
||||||
|
|
||||||
|
if none not in (offset, from) {
|
||||||
|
if type(offset) != array {
|
||||||
|
let a = (0, 0)
|
||||||
|
a.at(axis) = offset
|
||||||
|
offset = a
|
||||||
|
}
|
||||||
|
return resolve-offset(ctx, offset, from, axis)
|
||||||
|
|
||||||
|
} else if none not in (align, with) {
|
||||||
|
return resolve-align(ctx, elmt, align, with, axis)
|
||||||
|
} else {
|
||||||
|
panic("Dictionnary must either provide both 'offset' and 'from', or 'align' and 'with'")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if type(coord) not in (int, float, length) {
|
||||||
|
panic("Invalid " + "xy".at(axis) + " coordinate: " + repr(coord))
|
||||||
|
}
|
||||||
|
return coord
|
||||||
|
}
|
||||||
|
|
||||||
|
#let make-bounds(x, y, w, h) = {
|
||||||
|
let w2 = w / 2
|
||||||
|
let h2 = h / 2
|
||||||
|
|
||||||
|
return (
|
||||||
|
bl: (x, y),
|
||||||
|
tl: (x, y + h),
|
||||||
|
tr: (x + w, y + h),
|
||||||
|
br: (x + w, y),
|
||||||
|
center: (x + w2, y + h2),
|
||||||
|
b: (x + w2, y),
|
||||||
|
t: (x + w2, y + h),
|
||||||
|
l: (x, y + h2),
|
||||||
|
r: (x + w, y + h2),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#let render(draw-shape, elmt) = draw.group(name: elmt.id, ctx => {
|
||||||
|
let width = elmt.size.first()
|
||||||
|
let height = elmt.size.last()
|
||||||
|
|
||||||
|
let x = elmt.pos.first()
|
||||||
|
let y = elmt.pos.last()
|
||||||
|
|
||||||
|
x = resolve-coordinate(ctx, elmt, x, 0)
|
||||||
|
y = resolve-coordinate(ctx, elmt, y, 1)
|
||||||
|
|
||||||
|
let bounds = make-bounds(x, y, width, height)
|
||||||
|
|
||||||
|
// Workaround because CeTZ needs to have all draw functions in the body
|
||||||
|
let func = {}
|
||||||
|
let res = draw-shape(elmt, bounds)
|
||||||
|
assert(
|
||||||
|
type(res) == array and res.len() == 2,
|
||||||
|
message: "The drawing function of element '" + elmt.id + "' did not return a function and new bounds"
|
||||||
|
)
|
||||||
|
(func, bounds) = res
|
||||||
|
if type(func) == function {
|
||||||
|
func = (func,)
|
||||||
|
}
|
||||||
|
assert(
|
||||||
|
type(bounds) == dictionary,
|
||||||
|
message: "The drawing function of element '" + elmt.id + "' did not return the correct bounds dictionary"
|
||||||
|
)
|
||||||
|
func
|
||||||
|
|
||||||
|
if elmt.name != none {
|
||||||
|
draw.content(
|
||||||
|
(name: elmt.id, anchor: elmt.name-anchor),
|
||||||
|
anchor: if elmt.name-anchor in util.valid-anchors {elmt.name-anchor} else {"center"},
|
||||||
|
padding: 0.5em,
|
||||||
|
align(center)[*#elmt.name*]
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if elmt.auto-ports {
|
||||||
|
add-ports(
|
||||||
|
elmt.id,
|
||||||
|
bounds,
|
||||||
|
elmt.ports,
|
||||||
|
elmt.ports-margins,
|
||||||
|
debug: elmt.debug.ports
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
/// Draws an element
|
/// Draws an element
|
||||||
/// - draw-shape (function): Draw function
|
/// - draw-shape (function): Draw function
|
||||||
/// - x (number, dictionary): The x position (bottom-left corner).
|
/// - x (number, dictionary): The x position (bottom-left corner).
|
||||||
@ -46,89 +211,57 @@
|
|||||||
/// - `ports`: if true, shows dots on all ports of the element
|
/// - `ports`: if true, shows dots on all ports of the element
|
||||||
#let elmt(
|
#let elmt(
|
||||||
draw-shape: default-draw-shape,
|
draw-shape: default-draw-shape,
|
||||||
x: none,
|
pre-process: default-pre-process,
|
||||||
y: none,
|
pos: (0, 0),
|
||||||
w: none,
|
size: (1, 1),
|
||||||
h: none,
|
|
||||||
name: none,
|
name: none,
|
||||||
name-anchor: "center",
|
name-anchor: "center",
|
||||||
ports: (:),
|
ports: (:),
|
||||||
ports-margins: (:),
|
ports-margins: (:),
|
||||||
fill: none,
|
fill: none,
|
||||||
stroke: black + 1pt,
|
stroke: black + 1pt,
|
||||||
id: "",
|
id: auto,
|
||||||
auto-ports: true,
|
auto-ports: true,
|
||||||
ports-y: (:),
|
ports-y: (:),
|
||||||
debug: (
|
debug: (
|
||||||
ports: false
|
ports: false
|
||||||
)
|
)
|
||||||
) = draw.get-ctx(ctx => {
|
) = {
|
||||||
let width = w
|
for (key, side-ports) in ports.pairs() {
|
||||||
let height = h
|
if type(side-ports) == str {
|
||||||
|
side-ports = ((id: side-ports),)
|
||||||
let x = x
|
} else if type(side-ports) == dictionary {
|
||||||
let y = y
|
side-ports = (side-ports,)
|
||||||
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 (to-side, i) = find-port(ports, to)
|
|
||||||
let margins = (0%, 0%)
|
|
||||||
if to-side in ports-margins {
|
|
||||||
margins = ports-margins.at(to-side)
|
|
||||||
}
|
|
||||||
let used-pct = 100% - margins.at(0) - margins.at(1)
|
|
||||||
let used-height = height * used-pct / 100%
|
|
||||||
let top-margin = height * margins.at(0) / 100%
|
|
||||||
|
|
||||||
let dy = used-height * (i + 1) / (ports.at(to-side).len() + 1)
|
|
||||||
|
|
||||||
if not auto-ports {
|
|
||||||
top-margin = 0
|
|
||||||
dy = ports-y.at(to)(height)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let (ctx, from-pos) = coordinate.resolve(ctx, from)
|
for (i, port) in side-ports.enumerate() {
|
||||||
y = from-pos.at(1) + dy - height + top-margin
|
if type(port) == array {
|
||||||
|
side-ports.at(i) = (
|
||||||
|
id: port.at(0, default: ""),
|
||||||
|
name: port.at(1, default: "")
|
||||||
|
)
|
||||||
|
} else if type(port) == str {
|
||||||
|
side-ports.at(i) = (id: port)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ports.at(key) = side-ports
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
return ((
|
||||||
let func = {}
|
id: id,
|
||||||
(func, tl, tr, br, bl) = draw-shape(id, tl, tr, br, bl, fill, stroke)
|
draw: render.with(draw-shape),
|
||||||
func
|
pre-process: pre-process,
|
||||||
|
pos: pos,
|
||||||
if (name != none) {
|
size: size,
|
||||||
draw.content(
|
name: name,
|
||||||
(name: id, anchor: name-anchor),
|
name-anchor: name-anchor,
|
||||||
anchor: if name-anchor in util.valid-anchors {name-anchor} else {"center"},
|
ports: ports,
|
||||||
padding: 0.5em,
|
ports-margins: ports-margins,
|
||||||
align(center)[*#name*]
|
fill: fill,
|
||||||
)
|
stroke: stroke,
|
||||||
}
|
auto-ports: auto-ports,
|
||||||
|
ports-y: ports-y,
|
||||||
if auto-ports {
|
debug: debug
|
||||||
add-ports(
|
),)
|
||||||
id,
|
}
|
||||||
tl, tr, br, bl,
|
|
||||||
ports,
|
|
||||||
ports-margins,
|
|
||||||
debug: debug.ports
|
|
||||||
)
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "element.typ"
|
#import "element.typ"
|
||||||
#import "ports.typ": add-port
|
#import "ports.typ": add-port
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw, coordinate
|
#import "@preview/cetz:0.3.2": draw, coordinate
|
||||||
#import "../util.typ"
|
#import "../util.typ"
|
||||||
|
|
||||||
/// Draws a group of elements
|
/// Draws a group of elements
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.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,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.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,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw, coordinate
|
#import "@preview/cetz:0.3.2": draw, coordinate
|
||||||
#import "../ports.typ": add-ports, add-port
|
#import "../ports.typ": add-ports, add-port
|
||||||
#import "../element.typ"
|
#import "../element.typ"
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.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,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "gate.typ"
|
#import "gate.typ"
|
||||||
|
|
||||||
#let space = 10%
|
#let space = 10%
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "../util.typ"
|
#import "../util.typ"
|
||||||
#import "element.typ"
|
#import "element.typ"
|
||||||
#import "ports.typ": add-port
|
#import "ports.typ": add-port
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "../util.typ": rotate-anchor
|
#import "../util.typ": rotate-anchor
|
||||||
|
|
||||||
#let add-port(
|
#let add-port(
|
||||||
@ -34,12 +34,10 @@
|
|||||||
angle: if name-rotate {90deg} else {0deg},
|
angle: if name-rotate {90deg} else {0deg},
|
||||||
name
|
name
|
||||||
)
|
)
|
||||||
let id = elmt-id + "-port-" + port.at("id")
|
|
||||||
|
|
||||||
if debug {
|
if debug {
|
||||||
draw.circle(
|
draw.circle(
|
||||||
pos,
|
pos,
|
||||||
name: id,
|
|
||||||
radius: .1,
|
radius: .1,
|
||||||
stroke: none,
|
stroke: none,
|
||||||
fill: red
|
fill: red
|
||||||
@ -49,24 +47,24 @@
|
|||||||
draw.hide(draw.circle(
|
draw.hide(draw.circle(
|
||||||
pos,
|
pos,
|
||||||
radius: 0,
|
radius: 0,
|
||||||
stroke: none,
|
stroke: none
|
||||||
name: id
|
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
draw.anchor(port.id, pos)
|
||||||
}
|
}
|
||||||
|
|
||||||
#let add-ports(
|
#let add-ports(
|
||||||
elmt-id,
|
elmt-id,
|
||||||
tl, tr, br, bl,
|
bounds,
|
||||||
ports,
|
ports,
|
||||||
ports-margins,
|
ports-margins,
|
||||||
debug: false
|
debug: false
|
||||||
) = {
|
) = {
|
||||||
let sides = (
|
let sides = (
|
||||||
"north": (tl, tr),
|
"north": (bounds.tl, bounds.tr),
|
||||||
"east": (tr, br),
|
"east": (bounds.tr, bounds.br),
|
||||||
"south": (bl, br),
|
"south": (bounds.bl, bounds.br),
|
||||||
"west": (tl, bl)
|
"west": (bounds.tl, bounds.bl)
|
||||||
)
|
)
|
||||||
|
|
||||||
if type(ports) != dictionary {
|
if type(ports) != dictionary {
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#let version = version(0, 1, 0)
|
#let version = version(0, 2, 0)
|
||||||
|
|
||||||
#import "circuit.typ": circuit
|
#import "circuit.typ": circuit
|
||||||
#import "element.typ"
|
#import "element.typ"
|
||||||
|
11
src/util.typ
@ -74,3 +74,14 @@
|
|||||||
"center", "north", "east", "west", "south",
|
"center", "north", "east", "west", "south",
|
||||||
"north-east", "north-west", "south-east", "south-west"
|
"north-east", "north-west", "south-east", "south-west"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
#let get-port-side(element, port) = {
|
||||||
|
for (side, ports) in element.ports {
|
||||||
|
for p in ports {
|
||||||
|
if p.id == port {
|
||||||
|
return side
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
panic("Unknown port " + port + " on element " + element.id)
|
||||||
|
}
|
105
src/wire.typ
@ -1,5 +1,6 @@
|
|||||||
#import "@preview/cetz:0.2.2": draw, coordinate
|
#import "@preview/cetz:0.3.2": draw, coordinate
|
||||||
#import "util.typ": opposite-anchor
|
#import "util.typ": opposite-anchor, get-port-side
|
||||||
|
#import "elements/element.typ"
|
||||||
|
|
||||||
/// List of valid wire styles
|
/// List of valid wire styles
|
||||||
/// #examples.wires
|
/// #examples.wires
|
||||||
@ -267,40 +268,70 @@
|
|||||||
/// - vertical (bool): Whether the name should be displayed vertically
|
/// - vertical (bool): Whether the name should be displayed vertically
|
||||||
/// - length (number): The length of the stub
|
/// - length (number): The length of the stub
|
||||||
/// - name-offset (number): The name offset, perpendicular to the stub
|
/// - 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 stub(anchor, name: none, vertical: false, length: 1em, name-offset: 0) = {
|
||||||
let end-offset = (
|
if "." not in anchor {
|
||||||
north: (0, length),
|
panic("`anchor` must be a valid anchor of an element")
|
||||||
east: (length, 0),
|
|
||||||
south: (0, -length),
|
|
||||||
west: (-length, 0)
|
|
||||||
).at(side)
|
|
||||||
|
|
||||||
let name-offset = (
|
|
||||||
north: (name-offset, length),
|
|
||||||
east: (length, name-offset),
|
|
||||||
south: (name-offset, -length),
|
|
||||||
west: (-length, name-offset)
|
|
||||||
).at(side)
|
|
||||||
|
|
||||||
draw.line(
|
|
||||||
port-id,
|
|
||||||
(rel: end-offset, to: port-id)
|
|
||||||
)
|
|
||||||
if name != none {
|
|
||||||
let text-anchor = if vertical {
|
|
||||||
(
|
|
||||||
"north": "west",
|
|
||||||
"south": "east",
|
|
||||||
"west": "south",
|
|
||||||
"east": "north"
|
|
||||||
).at(side)
|
|
||||||
} else { opposite-anchor(side) }
|
|
||||||
draw.content(
|
|
||||||
anchor: text-anchor,
|
|
||||||
padding: 0.2em,
|
|
||||||
angle: if vertical {90deg} else {0deg},
|
|
||||||
(rel: name-offset, to: port-id),
|
|
||||||
name
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
let parts = anchor.split(".")
|
||||||
|
let port-id = parts.last()
|
||||||
|
let port-elmt-id = parts.slice(0, -1).join(".")
|
||||||
|
|
||||||
|
let pre-process = (elements, elmt) => {
|
||||||
|
let eid = elmt.id
|
||||||
|
|
||||||
|
if port-elmt-id not in elements {
|
||||||
|
panic("Unknown element " + port-elmt-id)
|
||||||
|
}
|
||||||
|
let port-elmt = elements.at(port-elmt-id)
|
||||||
|
let side = get-port-side(port-elmt, port-id)
|
||||||
|
elements.at(eid).insert("side", side)
|
||||||
|
return elements
|
||||||
|
}
|
||||||
|
|
||||||
|
let draw-func(elmt, bounds) = {
|
||||||
|
let side = elmt.side
|
||||||
|
let end-offset = (
|
||||||
|
north: (0, length),
|
||||||
|
east: (length, 0),
|
||||||
|
south: (0, -length),
|
||||||
|
west: (-length, 0)
|
||||||
|
).at(side)
|
||||||
|
|
||||||
|
let name-offset = (
|
||||||
|
north: (name-offset, length),
|
||||||
|
east: (length, name-offset),
|
||||||
|
south: (name-offset, -length),
|
||||||
|
west: (-length, name-offset)
|
||||||
|
).at(side)
|
||||||
|
|
||||||
|
let shapes = ()
|
||||||
|
shapes += draw.line(
|
||||||
|
anchor,
|
||||||
|
(rel: end-offset, to: anchor)
|
||||||
|
)
|
||||||
|
if name != none {
|
||||||
|
let text-anchor = if vertical {
|
||||||
|
(
|
||||||
|
"north": "west",
|
||||||
|
"south": "east",
|
||||||
|
"west": "south",
|
||||||
|
"east": "north"
|
||||||
|
).at(side)
|
||||||
|
} else { opposite-anchor(side) }
|
||||||
|
shapes += draw.content(
|
||||||
|
anchor: text-anchor,
|
||||||
|
padding: 0.2em,
|
||||||
|
angle: if vertical {90deg} else {0deg},
|
||||||
|
(rel: name-offset, to: anchor),
|
||||||
|
name
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
return (shapes, bounds)
|
||||||
|
}
|
||||||
|
|
||||||
|
return element.elmt(
|
||||||
|
draw-shape: draw-func,
|
||||||
|
pre-process: pre-process
|
||||||
|
)
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "circuiteria"
|
name = "circuiteria"
|
||||||
version = "0.1.0"
|
version = "0.2.0"
|
||||||
compiler = "0.11.0"
|
compiler = "0.13.0"
|
||||||
repository = "https://git.kb28.ch/HEL/circuiteria"
|
repository = "https://git.kb28.ch/HEL/circuiteria"
|
||||||
entrypoint = "src/lib.typ"
|
entrypoint = "src/lib.typ"
|
||||||
authors = [
|
authors = [
|
||||||
@ -11,4 +11,4 @@ categories = [ "visualization" ]
|
|||||||
license = "Apache-2.0"
|
license = "Apache-2.0"
|
||||||
description = "Drawing block circuits with Typst made easy, using CeTZ"
|
description = "Drawing block circuits with Typst made easy, using CeTZ"
|
||||||
keywords = [ "circuit", "block", "draw" ]
|
keywords = [ "circuit", "block", "draw" ]
|
||||||
exclude = [ "gallery", "gallery.bash", "doc" ]
|
exclude = [ "gallery", "justfile", "doc" ]
|