forked from HEL/circuiteria
		
	split up sources into manageable files
This commit is contained in:
		
							
								
								
									
										6
									
								
								src/circuit.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/circuit.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| #import "@preview/cetz:0.2.2": canvas | ||||
|  | ||||
| #let circuit(body, length: 2em) = { | ||||
|   set text(font: "Source Sans 3") | ||||
|   canvas(length: length, body) | ||||
| } | ||||
							
								
								
									
										7
									
								
								src/element.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								src/element.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| #import "elements/ports.typ": add-ports, add-port | ||||
| #import "elements/element.typ": elmt | ||||
|  | ||||
| #import "elements/alu.typ": alu | ||||
| #import "elements/block.typ": block | ||||
| #import "elements/extender.typ": extender | ||||
| #import "elements/multiplexer.typ": multiplexer | ||||
							
								
								
									
										84
									
								
								src/elements/alu.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										84
									
								
								src/elements/alu.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,84 @@ | ||||
| #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) = { | ||||
|   let p0 = tl | ||||
|   let p1 = (tr, 10%, br) | ||||
|   let p2 = (tr, 90%, br) | ||||
|   let p3 = bl | ||||
|   let p4 = (tl, 55%, bl) | ||||
|   let p5 = (tl, 50%, br) | ||||
|   let p6 = (tl, 45%, bl) | ||||
|    | ||||
|   let f1 = draw.group(name: id, { | ||||
|      | ||||
|     draw.merge-path( | ||||
|       inset: 0.5em, | ||||
|       fill: fill, | ||||
|       stroke: stroke, | ||||
|       close: true, | ||||
|       draw.line(p0, p1, p2, p3, p4, p5, p6) | ||||
|     ) | ||||
|     draw.anchor("north", (p0, 50%, p1)) | ||||
|     draw.anchor("south", (p2, 50%, p3)) | ||||
|     draw.anchor("west", (p0, 50%, p3)) | ||||
|     draw.anchor("east", (p1, 50%, p2)) | ||||
|   }) | ||||
|  | ||||
|   let f2 = add-port(id, "west", (id: "in1"), (p0, 50%, p6)) | ||||
|   let f3 = add-port(id, "west", (id: "in2"), (p3, 50%, p4)) | ||||
|   let f4 = add-port(id, "east", (id: "out"), (p1, 50%, p2)) | ||||
|  | ||||
|   let f = { | ||||
|     f1; f2; f3; f4 | ||||
|   } | ||||
|  | ||||
|   return (f, tl, tr, br, bl) | ||||
| } | ||||
|  | ||||
| #let alu( | ||||
|   x: none, | ||||
|   y: none, | ||||
|   w: none, | ||||
|   h: none, | ||||
|   name: none, | ||||
|   name-anchor: "center", | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   debug: ( | ||||
|     grid: false, | ||||
|     ports: false | ||||
|   ) | ||||
| ) = { | ||||
|   let ports = ( | ||||
|     west: ( | ||||
|       (id: "in1"), | ||||
|       (id: "in2"), | ||||
|     ), | ||||
|     east: ( | ||||
|       (id: "out"), | ||||
|     ) | ||||
|   ) | ||||
|    | ||||
|   element.elmt( | ||||
|     draw-shape: draw-shape, | ||||
|     x: x, | ||||
|     y: y, | ||||
|     w: w, | ||||
|     h: h, | ||||
|     name: name, | ||||
|     name-anchor: name-anchor, | ||||
|     ports: ports, | ||||
|     fill: fill, | ||||
|     stroke: stroke, | ||||
|     id: id, | ||||
|     auto-ports: false, | ||||
|     ports-y: ( | ||||
|       in1: (h) => {h * 0.225}, | ||||
|       in2: (h) => {h * 0.775}, | ||||
|     ), | ||||
|     debug: debug | ||||
|   ) | ||||
| } | ||||
							
								
								
									
										46
									
								
								src/elements/block.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										46
									
								
								src/elements/block.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,46 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "element.typ" | ||||
|  | ||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||
|   let f = draw.rect( | ||||
|     radius: 0.5em, | ||||
|     inset: 0.5em, | ||||
|     fill: fill, | ||||
|     stroke: stroke, | ||||
|     name: id, | ||||
|     bl, tr | ||||
|   ) | ||||
|   return (f, tl, tr, br, bl) | ||||
| } | ||||
|  | ||||
| #let block( | ||||
|   x: none, | ||||
|   y: none, | ||||
|   w: none, | ||||
|   h: none, | ||||
|   name: none, | ||||
|   name-anchor: "center", | ||||
|   ports: (), | ||||
|   ports-margins: (), | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   debug: ( | ||||
|     grid: false, | ||||
|     ports: false | ||||
|   ) | ||||
| ) = element.elmt( | ||||
|   draw-shape: draw-shape, | ||||
|   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 | ||||
| ) | ||||
							
								
								
									
										99
									
								
								src/elements/element.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								src/elements/element.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,99 @@ | ||||
| #import "@preview/cetz:0.2.2": draw, coordinate | ||||
| #import "ports.typ": add-ports, add-port | ||||
|  | ||||
| #let find-port(ports, id) = { | ||||
|   for (side, side-ports) in ports { | ||||
|     for (i, port) in side-ports.enumerate() { | ||||
|       if port.id == id { | ||||
|         return (side, i) | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   panic("Could not find port with id " + str(id)) | ||||
| } | ||||
|  | ||||
| #let default-draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||
|   return ({}, tl, tr, br, bl) | ||||
| } | ||||
|  | ||||
| #let elmt( | ||||
|   draw-shape: default-draw-shape, | ||||
|   x: none, | ||||
|   y: none, | ||||
|   w: none, | ||||
|   h: none, | ||||
|   name: none, | ||||
|   name-anchor: "center", | ||||
|   ports: (), | ||||
|   ports-margins: (), | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   auto-ports: true, | ||||
|   ports-y: (), | ||||
|   debug: ( | ||||
|     grid: false, | ||||
|     ports: false | ||||
|   ) | ||||
| ) = draw.get-ctx(ctx => { | ||||
|   let width = w | ||||
|   let height = h | ||||
|  | ||||
|   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(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) | ||||
|     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) | ||||
|  | ||||
|   // 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) | ||||
|   func | ||||
|  | ||||
|   if (name != none) { | ||||
|     draw.content( | ||||
|       (name: id, anchor: name-anchor), | ||||
|       anchor: name-anchor, | ||||
|       padding: 0.5em, | ||||
|       align(center)[*#name*] | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   if auto-ports { | ||||
|     add-ports( | ||||
|       id, | ||||
|       tl, tr, br, bl, | ||||
|       ports, | ||||
|       ports-margins, | ||||
|       debug: debug.ports | ||||
|     ) | ||||
|   } | ||||
| }) | ||||
							
								
								
									
										66
									
								
								src/elements/extender.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								src/elements/extender.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "element.typ" | ||||
|  | ||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||
|   let (x, y) = bl | ||||
|   let (width, height) = (tr.at(0) - x, tr.at(1) - y) | ||||
|  | ||||
|   tl = (x, y + height * 0.75) | ||||
|   let tr2 = (x + width, y + height * 0.75) | ||||
|   let br = (x + width, y) | ||||
|   (tr, tr2) = (tr2, tr) | ||||
|   let f = draw.group(name: id, { | ||||
|     draw.merge-path( | ||||
|       inset: 0.5em, | ||||
|       fill: fill, | ||||
|       stroke: stroke, | ||||
|       close: true, | ||||
|       draw.line(tl, tr2, br, bl) | ||||
|     ) | ||||
|     draw.anchor("north", (tl, 50%, tr2)) | ||||
|     draw.anchor("south", (bl, 50%, br)) | ||||
|     draw.anchor("west", (tl, 50%, bl)) | ||||
|     draw.anchor("east", (tr2, 50%, br)) | ||||
|   }) | ||||
|   return (f, tl, tr, br, bl) | ||||
| } | ||||
|  | ||||
| #let extender( | ||||
|   x: none, | ||||
|   y: none, | ||||
|   w: none, | ||||
|   h: none, | ||||
|   name: none, | ||||
|   name-anchor: "center", | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   debug: ( | ||||
|     grid: false, | ||||
|     ports: false | ||||
|   ) | ||||
| ) = { | ||||
|   let ports = ( | ||||
|     west: ( | ||||
|       (id: "in"), | ||||
|     ), | ||||
|     east: ( | ||||
|       (id: "out"), | ||||
|     ) | ||||
|   ) | ||||
|    | ||||
|   element.elmt( | ||||
|     draw-shape: draw-shape, | ||||
|     x: x, | ||||
|     y: y, | ||||
|     w: w, | ||||
|     h: h, | ||||
|     name: name, | ||||
|     name-anchor: name-anchor, | ||||
|     ports: ports, | ||||
|     fill: fill, | ||||
|     stroke: stroke, | ||||
|     id: id, | ||||
|     debug: debug | ||||
|   ) | ||||
| } | ||||
							
								
								
									
										64
									
								
								src/elements/multiplexer.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/elements/multiplexer.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,64 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "../util.typ" | ||||
| #import "element.typ" | ||||
|  | ||||
| #let draw-shape(id, tl, tr, br, bl, fill, stroke) = { | ||||
|   let tr2 = (tr, 20%, br) | ||||
|   let br2 = (tr, 80%, br) | ||||
|   let f = draw.group(name: id, { | ||||
|     draw.merge-path( | ||||
|       inset: 0.5em, | ||||
|       fill: fill, | ||||
|       stroke: stroke, | ||||
|       close: true, | ||||
|       draw.line(tl, tr2, br2, bl) | ||||
|     ) | ||||
|     draw.anchor("north", (tl, 50%, tr2)) | ||||
|     draw.anchor("south", (bl, 50%, br2)) | ||||
|     draw.anchor("west", (tl, 50%, bl)) | ||||
|     draw.anchor("east", (tr2, 50%, br2)) | ||||
|   }) | ||||
|   return (f, tl, tr, br, bl) | ||||
| } | ||||
|  | ||||
| #let multiplexer( | ||||
|   x: none, | ||||
|   y: none, | ||||
|   w: none, | ||||
|   h: none, | ||||
|   name: none, | ||||
|   name-anchor: "center", | ||||
|   entries: 2, | ||||
|   fill: none, | ||||
|   stroke: black + 1pt, | ||||
|   id: "", | ||||
|   debug: ( | ||||
|     grid: false, | ||||
|     ports: false | ||||
|   ) | ||||
| ) = { | ||||
|   let ports = () | ||||
|  | ||||
|   if (type(entries) == int) { | ||||
|     let nbits = calc.ceil(calc.log(entries, base: 2)) | ||||
|     for i in range(entries) { | ||||
|       let bits = util.lpad(str(i, base: 2), nbits) | ||||
|       ports.push((id: "in" + str(i), name: bits)) | ||||
|     } | ||||
|   } | ||||
|    | ||||
|   element.elmt( | ||||
|     draw-shape: draw-shape, | ||||
|     x: x, | ||||
|     y: y, | ||||
|     w: w, | ||||
|     h: h, | ||||
|     name: name, | ||||
|     name-anchor: name-anchor, | ||||
|     ports: (west: ports, east: ((id: "out"),)), | ||||
|     fill: fill, | ||||
|     stroke: stroke, | ||||
|     id: id, | ||||
|     debug: debug | ||||
|   ) | ||||
| } | ||||
							
								
								
									
										106
									
								
								src/elements/ports.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										106
									
								
								src/elements/ports.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,106 @@ | ||||
| #import "@preview/cetz:0.2.2": draw | ||||
| #import "../util.typ": rotate-anchor | ||||
|  | ||||
| #let add-port( | ||||
|   elmt-id, side, port, pos, | ||||
|   prev: none, | ||||
|   next: none, | ||||
|   debug: false | ||||
| ) = { | ||||
|   let name = port.at("name", default: "") | ||||
|   let name-rotate = port.at("vertical", default: false) | ||||
|  | ||||
|   if (port.at("clock", default: false)) { | ||||
|     if prev == none or next == none { | ||||
|       panic("Clock port must have previous and next positions") | ||||
|     } | ||||
|      | ||||
|     let offset | ||||
|     if      (side == "north") { offset = (   0, -1em) } | ||||
|     else if (side == "east")  { offset = (-1em,    0) } | ||||
|     else if (side == "south") { offset = (   0,  1em) } | ||||
|     else if (side == "west")  { offset = ( 1em,    0) } | ||||
|  | ||||
|     let pos1 = (rel: offset, to: pos) | ||||
|  | ||||
|     // TODO: use context or vectors to have the height relative to the width | ||||
|     draw.line(prev, pos1, next) | ||||
|   } | ||||
|   draw.content( | ||||
|     pos, | ||||
|     anchor: if name-rotate {rotate-anchor(side)} else {side}, | ||||
|     padding: 2pt, | ||||
|     angle: if name-rotate {90deg} else {0deg}, | ||||
|     name | ||||
|   ) | ||||
|   let id = elmt-id + "-port-" + port.at("id") | ||||
|  | ||||
|   if debug { | ||||
|     draw.circle( | ||||
|       pos, | ||||
|       name: id, | ||||
|       radius: .1, | ||||
|       stroke: none, | ||||
|       fill: red | ||||
|     ) | ||||
|      | ||||
|   } else { | ||||
|     draw.hide(draw.circle( | ||||
|       pos, | ||||
|       radius: 0, | ||||
|       stroke: none, | ||||
|       name: id | ||||
|     )) | ||||
|   } | ||||
| } | ||||
|  | ||||
| #let add-ports( | ||||
|   elmt-id, | ||||
|   tl, tr, br, bl, | ||||
|   ports, | ||||
|   ports-margins, | ||||
|   debug: false | ||||
| ) = { | ||||
|   let sides = ( | ||||
|     "north": (tl, tr), | ||||
|     "east": (tr, br), | ||||
|     "south": (bl, br), | ||||
|     "west": (tl, bl) | ||||
|   ) | ||||
|  | ||||
|   for (side, props) in sides { | ||||
|     let side-ports = ports.at(side, default: ()) | ||||
|     let space = 100% / (side-ports.len() + 1) | ||||
|  | ||||
|     for (i, port) in side-ports.enumerate() { | ||||
|       let pct = (i + 1) * space | ||||
|       let pt0 = props.at(0) | ||||
|       let pt1 = props.at(1) | ||||
|  | ||||
|       if side in ports-margins { | ||||
|         let (a, b) = (pt0, pt1) | ||||
|         let margins = ports-margins.at(side) | ||||
|         a = (pt0, margins.at(0), pt1) | ||||
|         b = (pt0, 100% - margins.at(1), pt1) | ||||
|         pt0 = a | ||||
|         pt1 = b | ||||
|       } | ||||
|        | ||||
|       let pos = (pt0, pct, pt1) | ||||
|       let pct-prev = (i + 0.5) * space | ||||
|       let pct-next = (i + 1.5) * space | ||||
|       let pos-prev = (pt0, pct-prev, pt1) | ||||
|       let pos-next = (pt0, pct-next, pt1) | ||||
|  | ||||
|       add-port( | ||||
|         elmt-id, | ||||
|         side, | ||||
|         port, | ||||
|         pos, | ||||
|         prev: pos-prev, | ||||
|         next: pos-next, | ||||
|         debug: debug | ||||
|       ) | ||||
|     } | ||||
|   } | ||||
| } | ||||
							
								
								
									
										6
									
								
								src/lib.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/lib.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| #let version = version((0,0,1)) | ||||
|  | ||||
| #import "circuit.typ": circuit | ||||
| #import "element.typ" | ||||
| #import "util.typ" | ||||
| #import "wire.typ" | ||||
							
								
								
									
										40
									
								
								src/util.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								src/util.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| #let colors = ( | ||||
|   orange: rgb(245, 180, 147), | ||||
|   yellow: rgb(250, 225, 127), | ||||
|   green: rgb(127, 200, 172), | ||||
|   pink: rgb(236, 127, 178), | ||||
|   purple: rgb(189, 151, 255) | ||||
| ) | ||||
|  | ||||
| #let lpad(s, len) = { | ||||
|   let res = "0" * len + s | ||||
|   return res.slice(-len) | ||||
| } | ||||
|  | ||||
| #let opposite-anchor(anchor) = { | ||||
|   return ( | ||||
|     north: "south", | ||||
|     east: "west", | ||||
|     south: "north", | ||||
|     west: "east", | ||||
|  | ||||
|     north-west: "south-east", | ||||
|     north-east: "south-west", | ||||
|     south-east: "north-west", | ||||
|     south-west: "north-east" | ||||
|   ).at(anchor) | ||||
| } | ||||
|  | ||||
| #let rotate-anchor(anchor) = { | ||||
|   return ( | ||||
|     north: "east", | ||||
|     east: "south", | ||||
|     south: "west", | ||||
|     west: "north", | ||||
|  | ||||
|     north-west: "north-east", | ||||
|     north-east: "south-east", | ||||
|     south-east: "south-west", | ||||
|     south-west: "north-west" | ||||
|   ).at(anchor) | ||||
| } | ||||
							
								
								
									
										230
									
								
								src/wire.typ
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										230
									
								
								src/wire.typ
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,230 @@ | ||||
| #import "@preview/cetz:0.2.2": draw, coordinate | ||||
| #import "util.typ": opposite-anchor | ||||
|  | ||||
| #let wire-styles = ("direct", "zigzag", "dodge") | ||||
| #let signal-width = 1pt | ||||
| #let bus-width = 1.5pt | ||||
|  | ||||
| #let intersection(pt) = { | ||||
|   draw.circle(pt, radius: .2, stroke: none, fill: black) | ||||
| } | ||||
|  | ||||
| #let get-direct-wire(pts) = { | ||||
|   let anchors = ( | ||||
|     "start": pts.first(), | ||||
|     "end": pts.last() | ||||
|   ) | ||||
|   return (pts, anchors) | ||||
| } | ||||
|  | ||||
| #let get-zigzag-wire(pts, ratio) = { | ||||
|   let start = pts.first() | ||||
|   let end = pts.last() | ||||
|   let mid = (start, ratio, end) | ||||
|  | ||||
|   let points = ( | ||||
|     start, | ||||
|     (horizontal: mid, vertical: ()), | ||||
|     (horizontal: (), vertical: end), | ||||
|     end | ||||
|   ) | ||||
|   let anchors = ( | ||||
|     "start": start, | ||||
|     "zig": points.at(1), | ||||
|     "zag": points.at(2), | ||||
|     "end": end | ||||
|   ) | ||||
|   return (points, anchors) | ||||
| } | ||||
|  | ||||
| #let get-dodge-wire(pts, dodge-y, margins, sides, ctx) = { | ||||
|   let start = pts.first() | ||||
|   let end = pts.last() | ||||
|   let (margin-start, margin-end) = margins | ||||
|   let (side-start, side-end) = sides | ||||
|  | ||||
|   let p1 = (start, margin-start, end) | ||||
|   let p2 = (end, margin-end, start) | ||||
|    | ||||
|   let (ctx, p0) = coordinate.resolve(ctx, start) | ||||
|   let (ctx, p3) = coordinate.resolve(ctx, end) | ||||
|   p0 = (x: p0.first(), y: p0.last()) | ||||
|   p3 = (x: p3.first(), y: p3.last()) | ||||
|  | ||||
|   let dx1 = margin-start | ||||
|   let dx2 = margin-end | ||||
|    | ||||
|   if type(margin-start) == ratio { | ||||
|     dx1 = calc.abs(p3.x - p0.x) * margin-start / 100% | ||||
|   } | ||||
|   if type(margin-end) == ratio { | ||||
|     dx2 = calc.abs(p3.x - p0.x) * margin-end / 100% | ||||
|   } | ||||
|   if side-start == "west" { | ||||
|     dx1 *= -1 | ||||
|   } | ||||
|   if side-end == "east" { | ||||
|     dx2 *= -1 | ||||
|   } | ||||
|   p1 = (p0.x + dx1, p0.y) | ||||
|   p2 = (p3.x - dx2, p0.y) | ||||
|  | ||||
|   let points = ( | ||||
|     start, | ||||
|     (horizontal: p1, vertical: ()), | ||||
|     (horizontal: (), vertical: (0, dodge-y)), | ||||
|     (horizontal: p2, vertical: ()), | ||||
|     (horizontal: (), vertical: end), | ||||
|     end | ||||
|   ) | ||||
|   let anchors = ( | ||||
|     "start": start, | ||||
|     "start2": points.at(1), | ||||
|     "dodge-start": points.at(2), | ||||
|     "dodge-end": points.at(3), | ||||
|     "end2": points.at(4), | ||||
|     "end": end | ||||
|   ) | ||||
|  | ||||
|   return (points, anchors) | ||||
| } | ||||
|  | ||||
| #let wire( | ||||
|   id, pts, | ||||
|   bus: false, | ||||
|   name: none, | ||||
|   name-pos: "middle", | ||||
|   slice: none, | ||||
|   color: black, | ||||
|   dashed: false, | ||||
|   style: "direct", | ||||
|   reverse: false, | ||||
|   zigzag-ratio: 50%, | ||||
|   dodge-y: 0, | ||||
|   dodge-sides: ("east", "west"), | ||||
|   dodge-margins: (5%, 5%) | ||||
| ) = draw.get-ctx(ctx => { | ||||
|   if not style in wire-styles { | ||||
|     panic("Invalid wire style '" + style + "'") | ||||
|   } | ||||
|  | ||||
|   if pts.len() != 2 { | ||||
|     panic("Wrong number of points (got " + str(pts.len()) + " instead of 2)") | ||||
|   } | ||||
|    | ||||
|   let stroke = ( | ||||
|     paint: color, | ||||
|     thickness: if bus {bus-width} else {signal-width} | ||||
|   ) | ||||
|   if dashed { | ||||
|     stroke.insert("dash", "dashed") | ||||
|   } | ||||
|  | ||||
|   let points = () | ||||
|   let anchors = () | ||||
|  | ||||
|   if style == "direct" { | ||||
|     (points, anchors) = get-direct-wire(pts) | ||||
|      | ||||
|   } else if style == "zigzag" { | ||||
|     (points, anchors) = get-zigzag-wire(pts, zigzag-ratio) | ||||
|      | ||||
|   } else if style == "dodge" { | ||||
|     (points, anchors) = get-dodge-wire( | ||||
|       pts, | ||||
|       dodge-y, | ||||
|       dodge-margins, | ||||
|       dodge-sides, | ||||
|       ctx | ||||
|     ) | ||||
|   } | ||||
|  | ||||
|   draw.group(name: id, { | ||||
|     draw.line(..points, stroke: stroke) | ||||
|     for (anchor-name, anchor-pos) in anchors { | ||||
|       draw.anchor(anchor-name, anchor-pos) | ||||
|     } | ||||
|   }) | ||||
|  | ||||
|   let first-pt = id + ".start" | ||||
|   let last-pt = id + ".end" | ||||
|   if reverse { | ||||
|     (first-pt, last-pt) = (last-pt, first-pt) | ||||
|   } | ||||
|    | ||||
|   if name != none { | ||||
|     let names = () | ||||
|      | ||||
|     if type(name) == str { | ||||
|       names = ((name, name-pos),) | ||||
|        | ||||
|     } else if type(name) == array { | ||||
|       names = ( | ||||
|         (name.at(0), "start"), | ||||
|         (name.at(1), "end") | ||||
|       ) | ||||
|     } | ||||
|  | ||||
|     for (name, pos) in names { | ||||
|       let point | ||||
|       let anchor | ||||
|        | ||||
|       if pos == "middle" { | ||||
|         point = (first-pt, 50%, last-pt) | ||||
|         anchor = "south" | ||||
|  | ||||
|       } else if pos == "start" { | ||||
|         point = first-pt | ||||
|         anchor = "south-west" | ||||
|  | ||||
|       } else if pos == "end" { | ||||
|         point = last-pt | ||||
|         anchor = "south-east" | ||||
|       } | ||||
|  | ||||
|       draw.content(point, anchor: anchor, padding: 3pt, name) | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   if slice != none { | ||||
|     let (start, end) = slice | ||||
|     let slice-txt = "[" + str(start) + ":" + str(end) + "]" | ||||
|      | ||||
|     draw.content( | ||||
|       first-pt, | ||||
|       anchor: "south-west", | ||||
|       padding: 3pt, | ||||
|       text(slice-txt, size: 0.75em) | ||||
|     ) | ||||
|   } | ||||
| }) | ||||
|  | ||||
| #let stub(port-id, side, name: none, vertical: false, length: 1em) = { | ||||
|   let offset = ( | ||||
|     north: (0, length), | ||||
|     east: (length, 0), | ||||
|     south: (0, -length), | ||||
|     west: (-length, 0) | ||||
|   ).at(side) | ||||
|   draw.line( | ||||
|     port-id, | ||||
|     (rel: 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: offset, to: port-id), | ||||
|       name | ||||
|     ) | ||||
|   } | ||||
| } | ||||
							
								
								
									
										14
									
								
								typst.toml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								typst.toml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,14 @@ | ||||
| [package] | ||||
| name = "circuiteria" | ||||
| version = "0.0.1" | ||||
| compiler = "0.11.0" | ||||
| repository = "https://git.kb28.ch/HEL/circuiteria" | ||||
| entrypoint = "src/lib.typ" | ||||
| authors = [ | ||||
|     "Louis Heredero <https://git.kb28.ch/HEL>" | ||||
| ] | ||||
| categories = [ "visualization" ] | ||||
| license = "Apache-2.0" | ||||
| description = "Drawing block circuits with Typst made easy, using CeTZ" | ||||
| keywords = [ "circuit", "block", "draw" ] | ||||
| exclude = [ "/gallery/*" ] | ||||
		Reference in New Issue
	
	Block a user