Compare commits
6 Commits
26231b2f48
...
comp/elect
Author | SHA1 | Date | |
---|---|---|---|
b7dd2cb718
|
|||
ac3e577020
|
|||
ba0f138ef2
|
|||
60898d1e60
|
|||
b8a7adb58f
|
|||
cc8478a3c7
|
@ -147,4 +147,22 @@ 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 capacitor = example(```
|
||||||
|
electrical.capacitor(
|
||||||
|
x: 0, y: 0, w: 2, h: 1, id: "a",
|
||||||
|
scales: (100%, 80%), gap: 0.3
|
||||||
|
)
|
||||||
|
|
||||||
|
electrical.capacitor(
|
||||||
|
x: 4, y: -0.5, w: 1, h: 2, id: "b",
|
||||||
|
vertical: true, symbols: ([+], none)
|
||||||
|
)
|
||||||
|
```, vertical: true)
|
||||||
|
|
||||||
|
#let resistor = example(```
|
||||||
|
electrical.resistor(x: 0, y: 0, w: 2, h: 0.5, id: "a", zigzags: 8)
|
||||||
|
electrical.resistor(x: 4, y: -0.5, w: 0.5, h: 2, id: "b", vertical: true)
|
||||||
|
electrical.resistor(x: 6.5, y: 0, w: 2, h: 0.5, id: "c", zigzags: none)
|
||||||
|
```, vertical: true)
|
Binary file not shown.
@ -1,283 +0,0 @@
|
|||||||
#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)
|
|
||||||
*/
|
|
||||||
})
|
|
Binary file not shown.
Binary file not shown.
Before Width: | Height: | Size: 66 KiB After Width: | Height: | Size: 81 KiB |
@ -81,4 +81,57 @@
|
|||||||
element.gate-xnor(
|
element.gate-xnor(
|
||||||
x: 9, y: -6, w: 2, h: 2, id: "xnor"
|
x: 9, y: -6, w: 2, h: 2, id: "xnor"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
element.resistor(
|
||||||
|
x: 0, y: -8, w: 2, h: 0.5, id: "res1"
|
||||||
|
)
|
||||||
|
|
||||||
|
element.capacitor(
|
||||||
|
x: 3, y: (from: "res1-port-1", to: "0"),
|
||||||
|
w: 2, h: 0.6,
|
||||||
|
id: "cap1",
|
||||||
|
scales: (100%, 80%),
|
||||||
|
symbols: ([+], [-])
|
||||||
|
)
|
||||||
|
|
||||||
|
element.resistor(
|
||||||
|
x: (rel: 1, to: "cap1-port-1"),
|
||||||
|
y: (from: "cap1-port-1", to: "0"),
|
||||||
|
w: 0.5, h: 2,
|
||||||
|
id: "res2",
|
||||||
|
vertical: true,
|
||||||
|
zigzags: 8
|
||||||
|
)
|
||||||
|
|
||||||
|
element.capacitor(
|
||||||
|
x: (rel: 1, to: "res2.east"),
|
||||||
|
y: (from: "res2-port-1", to: "1"),
|
||||||
|
w: 0.5, h: 2,
|
||||||
|
id: "cap2",
|
||||||
|
vertical: true,
|
||||||
|
symbols: ([a], [b])
|
||||||
|
)
|
||||||
|
|
||||||
|
element.resistor(
|
||||||
|
x: (rel: 1, to: "cap2-port-0"),
|
||||||
|
y: (from: "cap2-port-0", to: "0"),
|
||||||
|
w: 2, h: 0.5,
|
||||||
|
id: "res3",
|
||||||
|
zigzags: none
|
||||||
|
)
|
||||||
|
|
||||||
|
element.resistor(
|
||||||
|
x: (rel: 1, to: "res3-port-1"),
|
||||||
|
y: (from: "res3-port-1", to: "0"),
|
||||||
|
w: 0.5, h: 2,
|
||||||
|
id: "res4",
|
||||||
|
zigzags: none,
|
||||||
|
vertical: true
|
||||||
|
)
|
||||||
|
|
||||||
|
wire.wire("w4", ("res1-port-1", "cap1-port-0"))
|
||||||
|
wire.wire("w5", ("cap1-port-1", "res2-port-0"))
|
||||||
|
wire.wire("w6", ("res2-port-1", "cap2-port-1"))
|
||||||
|
wire.wire("w7", ("cap2-port-0", "res3-port-0"))
|
||||||
|
wire.wire("w8", ("res3-port-1", "res4-port-0"))
|
||||||
})
|
})
|
BIN
manual.pdf
BIN
manual.pdf
Binary file not shown.
23
manual.typ
23
manual.typ
@ -4,6 +4,7 @@
|
|||||||
#import "doc/examples.typ"
|
#import "doc/examples.typ"
|
||||||
#import "src/circuit.typ": circuit
|
#import "src/circuit.typ": circuit
|
||||||
#import "src/element.typ"
|
#import "src/element.typ"
|
||||||
|
#import "src/electrical.typ"
|
||||||
#import "src/gates.typ"
|
#import "src/gates.typ"
|
||||||
#import "src/util.typ"
|
#import "src/util.typ"
|
||||||
#import "src/wire.typ"
|
#import "src/wire.typ"
|
||||||
@ -210,4 +211,24 @@ If you have installed Circuiteria directly in your project, import #link("src/li
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
#tidy.show-module(gates-docs, sort-functions: false)
|
#tidy.show-module(gates-docs, sort-functions: false)
|
||||||
|
|
||||||
|
#pagebreak()
|
||||||
|
|
||||||
|
#let electrical-docs = tidy.parse-module(
|
||||||
|
read("src/elements/electrical/capacitor.typ") + "\n" +
|
||||||
|
read("src/elements/electrical/resistor.typ") + "\n",
|
||||||
|
name: "electrical",
|
||||||
|
scope: (
|
||||||
|
element: element,
|
||||||
|
circuit: circuit,
|
||||||
|
electrical: electrical,
|
||||||
|
draw: draw,
|
||||||
|
wire: wire,
|
||||||
|
tidy: tidy,
|
||||||
|
examples: examples,
|
||||||
|
doc-ref: doc-ref
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
#tidy.show-module(electrical-docs, sort-functions: false)
|
@ -9,52 +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) = {
|
||||||
let next-id = 0
|
set text(font: "Source Sans 3")
|
||||||
let elements = (:)
|
canvas(length: length, body)
|
||||||
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,)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
2
src/electrical.typ
Normal file
2
src/electrical.typ
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
#import "elements/electrical/capacitor.typ": capacitor
|
||||||
|
#import "elements/electrical/resistor.typ": resistor
|
@ -12,4 +12,7 @@
|
|||||||
#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/electrical/resistor.typ": resistor
|
||||||
|
#import "elements/electrical/capacitor.typ": capacitor
|
||||||
|
|
||||||
#import "elements/group.typ": group
|
#import "elements/group.typ": group
|
@ -1,15 +1,16 @@
|
|||||||
#import "@preview/cetz:0.3.2": draw
|
#import "@preview/cetz:0.3.2": draw
|
||||||
#import "element.typ"
|
#import "element.typ"
|
||||||
|
|
||||||
#let draw-shape(elmt, bounds) = {
|
#let draw-shape(id, tl, tr, br, bl, fill, stroke) = {
|
||||||
let f = draw.rect(
|
let f = draw.rect(
|
||||||
radius: 0.5em,
|
radius: 0.5em,
|
||||||
inset: 0.5em,
|
inset: 0.5em,
|
||||||
fill: elmt.fill,
|
fill: fill,
|
||||||
stroke: elmt.stroke,
|
stroke: stroke,
|
||||||
bounds.bl, bounds.tr
|
name: id,
|
||||||
|
bl, tr
|
||||||
)
|
)
|
||||||
return (f, bounds)
|
return (f, tl, tr, br, bl)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Draws a block element
|
/// Draws a block element
|
||||||
@ -17,8 +18,32 @@
|
|||||||
/// #examples.block
|
/// #examples.block
|
||||||
/// For parameters description, see #doc-ref("element.elmt")
|
/// For parameters description, see #doc-ref("element.elmt")
|
||||||
#let block(
|
#let block(
|
||||||
..args
|
x: none,
|
||||||
|
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,
|
||||||
..args
|
x: x,
|
||||||
|
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
|
||||||
)
|
)
|
138
src/elements/electrical/capacitor.typ
Normal file
138
src/elements/electrical/capacitor.typ
Normal file
@ -0,0 +1,138 @@
|
|||||||
|
#import "@preview/cetz:0.2.2": draw
|
||||||
|
#import "../element.typ"
|
||||||
|
#import "../ports.typ": add-port
|
||||||
|
|
||||||
|
#let draw-shape(
|
||||||
|
id, tl, tr, br, bl,
|
||||||
|
fill, stroke,
|
||||||
|
vertical: false,
|
||||||
|
gap: 0.2,
|
||||||
|
scales: (100%, 100%),
|
||||||
|
symbols: (none, none)
|
||||||
|
) = {
|
||||||
|
let (x0, y0) = tl
|
||||||
|
let (x1, y1) = br
|
||||||
|
|
||||||
|
let w = x1 - x0
|
||||||
|
let h = y1 - y0
|
||||||
|
|
||||||
|
let (o0, s0) = if vertical {(y0, h)} else {(x0, w)}
|
||||||
|
let (o1, s1) = if vertical {(x0, w)} else {(y0, h)}
|
||||||
|
let m1 = o1 + s1 / 2
|
||||||
|
|
||||||
|
let pt(i, j) = if vertical {
|
||||||
|
(j, i)
|
||||||
|
} else {
|
||||||
|
(i, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
let size0 = s1 * scales.first() / 100%
|
||||||
|
let size1 = s1 * scales.last() / 100%
|
||||||
|
|
||||||
|
if type(gap) == ratio {
|
||||||
|
gap = gap / 100%
|
||||||
|
} else {
|
||||||
|
gap = gap / calc.abs(s0)
|
||||||
|
}
|
||||||
|
let r0 = 0.5 - gap / 2
|
||||||
|
let r1 = 0.5 + gap / 2
|
||||||
|
|
||||||
|
// Coordinates in (main axis, secondary axis) format
|
||||||
|
let p0 = pt(o0, m1)
|
||||||
|
let p1 = pt(o0 + r0 * s0, m1)
|
||||||
|
let p2 = pt(o0 + r1 * s0, m1)
|
||||||
|
let p3 = pt(o0 + s0, m1)
|
||||||
|
|
||||||
|
let p4 = pt(o0 + r0 * s0, m1 - size0 / 2)
|
||||||
|
let p5 = pt(o0 + r0 * s0, m1 + size0 / 2)
|
||||||
|
|
||||||
|
let p6 = pt(o0 + r1 * s0, m1 - size1 / 2)
|
||||||
|
let p7 = pt(o0 + r1 * s0, m1 + size1 / 2)
|
||||||
|
|
||||||
|
let line = draw.line.with(stroke: stroke)
|
||||||
|
let f = draw.group(name: id, {
|
||||||
|
line(p0, p1)
|
||||||
|
line(p2, p3)
|
||||||
|
line(p4, p5)
|
||||||
|
line(p6, p7)
|
||||||
|
|
||||||
|
if symbols.first() != none {
|
||||||
|
draw.content(
|
||||||
|
p1,
|
||||||
|
symbols.first(),
|
||||||
|
anchor: if vertical {"south-west"} else {"south-east"},
|
||||||
|
padding: 2pt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
if symbols.last() != none {
|
||||||
|
draw.content(
|
||||||
|
p2,
|
||||||
|
symbols.last(),
|
||||||
|
anchor: if vertical {"north-west"} else {"south-west"},
|
||||||
|
padding: 2pt
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
return (f, tl, tr, br, bl)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws a capacitor
|
||||||
|
///
|
||||||
|
/// #examples.capacitor
|
||||||
|
/// For other parameters description, see #doc-ref("element.elmt")
|
||||||
|
/// - vertical (bool): Whether the element is vertical or horizontal.
|
||||||
|
/// - If false, port 0 is placed on the west side and port 1 on the east.\
|
||||||
|
/// - If true, they are on the north, respectively the south sides
|
||||||
|
/// - gap (number, ratio): The gap between both sides
|
||||||
|
/// - if it is a number (int or float), it is interpreted as an absolute canvas-unit length
|
||||||
|
/// - if it is a ratio, it is interpreted as proportional to the capacitor's length (width if horizontal, height if vertical)
|
||||||
|
/// - scales (array): A pair of ratios, the sizes of the sides relative to the capacitor's height (width if vertical).
|
||||||
|
/// - symbols (array): A pair of content or strings (or none values) to attach on the sides of the capacitor
|
||||||
|
#let capacitor(
|
||||||
|
x: none,
|
||||||
|
y: none,
|
||||||
|
w: none,
|
||||||
|
h: none,
|
||||||
|
name: none,
|
||||||
|
name-anchor: "center",
|
||||||
|
vertical: false,
|
||||||
|
gap: 0.2,
|
||||||
|
scales: (100%, 100%),
|
||||||
|
symbols: (none, none),
|
||||||
|
fill: none,
|
||||||
|
stroke: black + 1pt,
|
||||||
|
id: "",
|
||||||
|
debug: (
|
||||||
|
ports: false
|
||||||
|
)
|
||||||
|
) = {
|
||||||
|
let ports = if vertical {(
|
||||||
|
north: ((id: "0"),),
|
||||||
|
south: ((id: "1"),)
|
||||||
|
)} else {(
|
||||||
|
west: ((id: "0"),),
|
||||||
|
east: ((id: "1"),)
|
||||||
|
)}
|
||||||
|
|
||||||
|
element.elmt(
|
||||||
|
draw-shape: draw-shape.with(
|
||||||
|
vertical: vertical,
|
||||||
|
gap: gap,
|
||||||
|
scales: scales,
|
||||||
|
symbols: symbols
|
||||||
|
),
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
w: w,
|
||||||
|
h: h,
|
||||||
|
name: name,
|
||||||
|
name-anchor: name-anchor,
|
||||||
|
ports: ports,
|
||||||
|
fill: fill,
|
||||||
|
stroke: stroke,
|
||||||
|
id: id,
|
||||||
|
debug: debug
|
||||||
|
)
|
||||||
|
}
|
106
src/elements/electrical/resistor.typ
Normal file
106
src/elements/electrical/resistor.typ
Normal file
@ -0,0 +1,106 @@
|
|||||||
|
#import "@preview/cetz:0.2.2": draw
|
||||||
|
#import "../element.typ"
|
||||||
|
#import "../ports.typ": add-port
|
||||||
|
|
||||||
|
#let draw-shape(
|
||||||
|
id, tl, tr, br, bl,
|
||||||
|
fill, stroke,
|
||||||
|
zigzags: 6,
|
||||||
|
vertical: false
|
||||||
|
) = {
|
||||||
|
let (x0, y0) = tl
|
||||||
|
let (x1, y1) = br
|
||||||
|
|
||||||
|
let w = x1 - x0
|
||||||
|
let h = y1 - y0
|
||||||
|
|
||||||
|
let (o0, s0) = if vertical {(y0, h)} else {(x0, w)}
|
||||||
|
let (o1, s1) = if vertical {(x0, w)} else {(y0, h)}
|
||||||
|
let m1 = o1 + s1 / 2
|
||||||
|
|
||||||
|
let pt(i, j) = if vertical {
|
||||||
|
(j, i)
|
||||||
|
} else {
|
||||||
|
(i, j)
|
||||||
|
}
|
||||||
|
|
||||||
|
let p0 = pt(o0, m1)
|
||||||
|
let p1 = pt(o0 + 0.2 * s0, m1)
|
||||||
|
let p2 = pt(o0 + 0.8 * s0, m1)
|
||||||
|
let p3 = pt(o0 + s0, m1)
|
||||||
|
|
||||||
|
if zigzags == none {
|
||||||
|
let p4 = pt(o0 + 0.2 * s0, o1)
|
||||||
|
let p5 = pt(o0 + 0.8 * s0, o1 + s1)
|
||||||
|
let f = draw.group(name: id, {
|
||||||
|
draw.line(p0, p1)
|
||||||
|
draw.line(p2, p3)
|
||||||
|
draw.rect(p4, p5, stroke: stroke, fill: fill)
|
||||||
|
})
|
||||||
|
return (f, tl, tr, br, bl)
|
||||||
|
}
|
||||||
|
|
||||||
|
let pts = (p0, p1)
|
||||||
|
|
||||||
|
for i in range(zigzags) {
|
||||||
|
let r = ((i+0.5) / zigzags * 0.6 + 0.2)
|
||||||
|
let pos = pt(o0 + r * s0, o1 + s1 * calc.rem(i, 2))
|
||||||
|
pts.push(pos)
|
||||||
|
}
|
||||||
|
|
||||||
|
pts += (p2, p3)
|
||||||
|
|
||||||
|
let f = draw.group(name: id, {
|
||||||
|
draw.line(..pts, stroke: stroke)
|
||||||
|
})
|
||||||
|
return (f, tl, tr, br, bl)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Draws a resistor
|
||||||
|
///
|
||||||
|
/// #examples.resistor
|
||||||
|
/// For other parameters description, see #doc-ref("element.elmt")
|
||||||
|
/// - vertical (bool): Whether the element is vertical or horizontal. If false, port 0 is placed on the west side and port 1 on the east. If true, they are on the north, respectively the south sides
|
||||||
|
/// - zigzags (number, none): Number of zigzags to draw. If none, a rectangle is drawn
|
||||||
|
#let resistor(
|
||||||
|
x: none,
|
||||||
|
y: none,
|
||||||
|
w: none,
|
||||||
|
h: none,
|
||||||
|
name: none,
|
||||||
|
name-anchor: "center",
|
||||||
|
vertical: false,
|
||||||
|
zigzags: 6,
|
||||||
|
fill: none,
|
||||||
|
stroke: black + 1pt,
|
||||||
|
id: "",
|
||||||
|
debug: (
|
||||||
|
ports: false
|
||||||
|
)
|
||||||
|
) = {
|
||||||
|
let ports = if vertical {(
|
||||||
|
north: ((id: "0"),),
|
||||||
|
south: ((id: "1"),)
|
||||||
|
)} else {(
|
||||||
|
west: ((id: "0"),),
|
||||||
|
east: ((id: "1"),)
|
||||||
|
)}
|
||||||
|
|
||||||
|
element.elmt(
|
||||||
|
draw-shape: draw-shape.with(
|
||||||
|
vertical: vertical,
|
||||||
|
zigzags: zigzags
|
||||||
|
),
|
||||||
|
x: x,
|
||||||
|
y: y,
|
||||||
|
w: w,
|
||||||
|
h: h,
|
||||||
|
name: name,
|
||||||
|
name-anchor: name-anchor,
|
||||||
|
ports: ports,
|
||||||
|
fill: fill,
|
||||||
|
stroke: stroke,
|
||||||
|
id: id,
|
||||||
|
debug: debug
|
||||||
|
)
|
||||||
|
}
|
@ -1,4 +1,4 @@
|
|||||||
#import "@preview/cetz:0.3.2": draw, coordinate, matrix, vector
|
#import "@preview/cetz:0.3.2": draw, coordinate
|
||||||
#import "ports.typ": add-ports, add-port
|
#import "ports.typ": add-ports, add-port
|
||||||
#import "../util.typ"
|
#import "../util.typ"
|
||||||
|
|
||||||
@ -13,175 +13,10 @@
|
|||||||
panic("Could not find port with id " + str(id))
|
panic("Could not find port with id " + str(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
#let local-to-global(origin, u, v, points) = {
|
#let default-draw-shape(id, tl, tr, br, bl, fill, stroke) = {
|
||||||
return points-real = points.map(p => {
|
return ({}, tl, tr, br, bl)
|
||||||
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).
|
||||||
@ -211,57 +46,100 @@
|
|||||||
/// - `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,
|
||||||
pre-process: default-pre-process,
|
x: none,
|
||||||
pos: (0, 0),
|
y: none,
|
||||||
size: (1, 1),
|
w: none,
|
||||||
|
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: auto,
|
id: "",
|
||||||
auto-ports: true,
|
auto-ports: true,
|
||||||
ports-y: (:),
|
ports-y: (:),
|
||||||
debug: (
|
debug: (
|
||||||
ports: false
|
ports: false
|
||||||
)
|
)
|
||||||
) = {
|
) = draw.get-ctx(ctx => {
|
||||||
for (key, side-ports) in ports.pairs() {
|
let width = w
|
||||||
if type(side-ports) == str {
|
let height = h
|
||||||
side-ports = ((id: side-ports),)
|
|
||||||
} else if type(side-ports) == dictionary {
|
let x = x
|
||||||
side-ports = (side-ports,)
|
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 (to-side, i) = find-port(ports, to)
|
||||||
|
let margins = (0%, 0%)
|
||||||
|
if to-side in ports-margins {
|
||||||
|
margins = ports-margins.at(to-side)
|
||||||
}
|
}
|
||||||
|
|
||||||
for (i, port) in side-ports.enumerate() {
|
let dy
|
||||||
if type(port) == array {
|
let top-margin
|
||||||
side-ports.at(i) = (
|
if to-side in ("east", "west") {
|
||||||
id: port.at(0, default: ""),
|
let used-pct = 100% - margins.at(0) - margins.at(1)
|
||||||
name: port.at(1, default: "")
|
let used-height = height * used-pct / 100%
|
||||||
)
|
top-margin = height * margins.at(0) / 100%
|
||||||
} else if type(port) == str {
|
|
||||||
side-ports.at(i) = (id: port)
|
dy = used-height * (i + 1) / (ports.at(to-side).len() + 1)
|
||||||
|
|
||||||
|
if not auto-ports {
|
||||||
|
top-margin = 0
|
||||||
|
dy = ports-y.at(to)(height)
|
||||||
}
|
}
|
||||||
|
} else if to-side == "north" {
|
||||||
|
dy = 0
|
||||||
|
top-margin = 0
|
||||||
|
} else if to-side == "south" {
|
||||||
|
dy = height
|
||||||
|
top-margin = 0
|
||||||
}
|
}
|
||||||
ports.at(key) = side-ports
|
|
||||||
|
let (ctx, from-pos) = coordinate.resolve(ctx, from)
|
||||||
|
y = from-pos.at(1) + dy - height + top-margin
|
||||||
}
|
}
|
||||||
|
|
||||||
|
let tl = (x, y + height)
|
||||||
|
let tr = (x + width, y + height)
|
||||||
|
let br = (x + width, y)
|
||||||
|
let bl = (x, y)
|
||||||
|
|
||||||
return ((
|
// Workaround because CeTZ needs to have all draw functions in the body
|
||||||
id: id,
|
let func = {}
|
||||||
draw: render.with(draw-shape),
|
(func, tl, tr, br, bl) = draw-shape(id, tl, tr, br, bl, fill, stroke)
|
||||||
pre-process: pre-process,
|
func
|
||||||
pos: pos,
|
|
||||||
size: size,
|
if (name != none) {
|
||||||
name: name,
|
draw.content(
|
||||||
name-anchor: name-anchor,
|
(name: id, anchor: name-anchor),
|
||||||
ports: ports,
|
anchor: if name-anchor in util.valid-anchors {name-anchor} else {"center"},
|
||||||
ports-margins: ports-margins,
|
padding: 0.5em,
|
||||||
fill: fill,
|
align(center)[*#name*]
|
||||||
stroke: stroke,
|
)
|
||||||
auto-ports: auto-ports,
|
}
|
||||||
ports-y: ports-y,
|
|
||||||
debug: debug
|
if auto-ports {
|
||||||
),)
|
add-ports(
|
||||||
}
|
id,
|
||||||
|
tl, tr, br, bl,
|
||||||
|
ports,
|
||||||
|
ports-margins,
|
||||||
|
debug: debug.ports
|
||||||
|
)
|
||||||
|
}
|
||||||
|
})
|
@ -34,10 +34,12 @@
|
|||||||
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
|
||||||
@ -47,24 +49,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,
|
||||||
bounds,
|
tl, tr, br, bl,
|
||||||
ports,
|
ports,
|
||||||
ports-margins,
|
ports-margins,
|
||||||
debug: false
|
debug: false
|
||||||
) = {
|
) = {
|
||||||
let sides = (
|
let sides = (
|
||||||
"north": (bounds.tl, bounds.tr),
|
"north": (tl, tr),
|
||||||
"east": (bounds.tr, bounds.br),
|
"east": (tr, br),
|
||||||
"south": (bounds.bl, bounds.br),
|
"south": (bl, br),
|
||||||
"west": (bounds.tl, bounds.bl)
|
"west": (tl, bl)
|
||||||
)
|
)
|
||||||
|
|
||||||
if type(ports) != dictionary {
|
if type(ports) != dictionary {
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
#let version = version(0, 2, 0)
|
#let version = version(0, 2, 0)
|
||||||
|
|
||||||
#import "circuit.typ": circuit
|
#import "circuit.typ": circuit
|
||||||
|
#import "electrical.typ"
|
||||||
#import "element.typ"
|
#import "element.typ"
|
||||||
#import "gates.typ"
|
#import "gates.typ"
|
||||||
#import "util.typ"
|
#import "util.typ"
|
||||||
|
13
src/util.typ
13
src/util.typ
@ -73,15 +73,4 @@
|
|||||||
#let valid-anchors = (
|
#let valid-anchors = (
|
||||||
"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)
|
|
||||||
}
|
|
101
src/wire.typ
101
src/wire.typ
@ -1,6 +1,5 @@
|
|||||||
#import "@preview/cetz:0.3.2": draw, coordinate
|
#import "@preview/cetz:0.3.2": draw, coordinate
|
||||||
#import "util.typ": opposite-anchor, get-port-side
|
#import "util.typ": opposite-anchor
|
||||||
#import "elements/element.typ"
|
|
||||||
|
|
||||||
/// List of valid wire styles
|
/// List of valid wire styles
|
||||||
/// #examples.wires
|
/// #examples.wires
|
||||||
@ -268,70 +267,40 @@
|
|||||||
/// - 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(anchor, name: none, vertical: false, length: 1em, name-offset: 0) = {
|
#let stub(port-id, side, name: none, vertical: false, length: 1em, name-offset: 0) = {
|
||||||
if "." not in anchor {
|
let end-offset = (
|
||||||
panic("`anchor` must be a valid anchor of an element")
|
north: (0, length),
|
||||||
}
|
east: (length, 0),
|
||||||
let parts = anchor.split(".")
|
south: (0, -length),
|
||||||
let port-id = parts.last()
|
west: (-length, 0)
|
||||||
let port-elmt-id = parts.slice(0, -1).join(".")
|
).at(side)
|
||||||
|
|
||||||
|
let name-offset = (
|
||||||
|
north: (name-offset, length),
|
||||||
|
east: (length, name-offset),
|
||||||
|
south: (name-offset, -length),
|
||||||
|
west: (-length, name-offset)
|
||||||
|
).at(side)
|
||||||
|
|
||||||
let pre-process = (elements, elmt) => {
|
draw.line(
|
||||||
let eid = elmt.id
|
port-id,
|
||||||
|
(rel: end-offset, to: port-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
|
|
||||||
)
|
)
|
||||||
|
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
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user