diff --git a/gallery/simple-circuit.typ b/gallery/simple-circuit.typ new file mode 100644 index 0000000..e1b00aa --- /dev/null +++ b/gallery/simple-circuit.typ @@ -0,0 +1,36 @@ +#import "../src/lib.typ": * +#import "@preview/cetz:0.3.2": draw // For potential use of draw.hide if needed, but trying without first + +#set page(width: auto, height: auto, margin: 1cm) + +#circuit({ + // Circuit 1: Series Lamps + electrical.voltage-source(x: 0, y: 0, w: 1, h: 1, id: "vs1") + electrical.lamp(x: 1, y: 0, w: 1, h: 1, id: "lamp1") + electrical.lamp(x: 2, y: 0, w: 1, h: 1, id: "lamp2") + + // Circuit 1 Wires + wire.wire("w-s-1", ("vs1.east", "lamp1.west")) + wire.wire("w-s-2", ("lamp1.east", "lamp2.west")) + // Use dodge style for return path + wire.wire("w-s-return", ("lamp2.east", "vs1.west"), style: "dodge", dodge-y: -1.5, dodge-sides: ("east", "west")) +}) + + +#circuit({ + // Circuit 2: RC Charging + + electrical.voltage-source(x: 0, y: 0, w: 1, h: 1, id: "vs") + electrical.switch(x: 2, y: 0, w: 1, h: 1, id: "sw1", closed: false) + electrical.capacitor(x: 2, y: -2, w: 1, h: 1, id: "c1") + electrical.resistor(x: 0, y: -2, w: 2, h: 1, id: "r1") + + electrical.voltmeter(x: 2, y: -3, w: 1, h: 1, id: "vm") + + wire.wire("w-s-1", ("vs-port-1", "sw1-port-0")) + wire.wire("w-s-2", ("c1-port-1", "sw1-port-1")) + wire.wire("w-s-3", ("r1-port-0", "vs-port-0")) + + wire.wire("w-s-4", ("vm-port-0", "c1-port-0")) + wire.wire("w-s-4", ("vm-port-1", "c1-port-1")) +}) diff --git a/src/electrical.typ b/src/electrical.typ new file mode 100644 index 0000000..f6736d6 --- /dev/null +++ b/src/electrical.typ @@ -0,0 +1,9 @@ +#import "elements/electrical/capacitor.typ": capacitor +#import "elements/electrical/resistor.typ": resistor +#import "elements/electrical/voltage-source.typ": voltage-source +#import "elements/electrical/ac-source.typ": ac-source +#import "elements/electrical/ammeter.typ": ammeter +#import "elements/electrical/voltmeter.typ": voltmeter +#import "elements/electrical/inductor.typ": inductor +#import "elements/electrical/switch.typ": switch +#import "elements/electrical/lamp.typ": lamp \ No newline at end of file diff --git a/src/elements/electrical/ac-source.typ b/src/elements/electrical/ac-source.typ new file mode 100644 index 0000000..c94dbff --- /dev/null +++ b/src/elements/electrical/ac-source.typ @@ -0,0 +1,100 @@ +#import "@preview/cetz:0.3.2": draw +#import "../element.typ" +#import "../ports.typ": add-port + +#let draw-shape( + id, + tl, + tr, + br, + bl, + fill, + stroke, + vertical: false, +) = { + let (x0, y0) = tl + let (x1, y1) = br + + let w = x1 - x0 + let h = y1 - y0 + + let cx = x0 + w / 2 + let cy = y0 + h / 2 + let r = calc.min(w, h) / 2 + + let line = draw.line.with(stroke: stroke) + let circle = draw.circle.with(stroke: stroke, fill: fill) + + let f = draw.group( + name: id, + { + // Kreis und Tilde-Symbol + circle((cx, cy), radius: r) + draw.content((cx, cy), [$tilde$], anchor: "center") + + // Verbindungslinien zu den Ports + if vertical { + // Vertikale Quelle + let p_start = (cx, y0) // North port + let p_end = (cx, y1) // South port + let circle_top = (cx, cy - r) // Top point of the circle + let circle_bottom = (cx, cy + r) // Bottom point of the circle + line(p_start, circle_top) // Line from North port to top of circle + line(circle_bottom, p_end) // Line from bottom of circle to South port + } else { + // Horizontale Quelle + let p_start = (x0, cy) // West port + let p_end = (x1, cy) // East port + let circle_left = (cx - r, cy) // Left point of the circle + let circle_right = (cx + r, cy) // Right point of the circle + line(p_start, circle_right) // Line from West port to left of circle + line(circle_left, p_end) // Line from right of circle to East port + } + }, + ) + + return (f, tl, tr, br, bl) +} + +#let ac-source( + x: none, + y: none, + w: none, + h: none, + name: none, + name-anchor: "center", + vertical: false, + 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), + x: x, + y: y, + w: w, + h: h, + name: name, + name-anchor: name-anchor, + ports: ports, + fill: fill, + stroke: stroke, + id: id, + debug: debug, + ) +} diff --git a/src/elements/electrical/ammeter.typ b/src/elements/electrical/ammeter.typ new file mode 100644 index 0000000..11faaf9 --- /dev/null +++ b/src/elements/electrical/ammeter.typ @@ -0,0 +1,81 @@ +#import "@preview/cetz:0.3.2": draw +#import "../element.typ" +#import "../ports.typ": add-port + +#let draw-shape( + id, tl, tr, br, bl, + fill, stroke, + vertical: false +) = { + let (x0, y0) = tl + let (x1, y1) = br + + let w = x1 - x0 + let h = y1 - y0 + + let cx = x0 + w / 2 + let cy = y0 + h / 2 + let r = calc.min(w, h) / 3 + + let line = draw.line.with(stroke: stroke) + let circle = draw.circle.with(stroke: stroke, fill: fill) + + let f = draw.group(name: id, { + // Kreis und 'A'-Symbol + circle((cx, cy), radius: r) + draw.content((cx, cy), [A], anchor: "center") + + // Verbindungslinien zu den Ports + if vertical { + // Vertikales Amperemeter + let p_start = (cx, y0) // North port + let p_end = (cx, y1) // South port + let circle_top = (cx, cy - r) // Top point of the circle + let circle_bottom = (cx, cy + r) // Bottom point of the circle + line(p_start, circle_top) // Line from North port to top of circle + line(circle_bottom, p_end) // Line from bottom of circle to South port + } else { + // Horizontales Amperemeter + let p_start = (x0, cy) // West port + let p_end = (x1, cy) // East port + let circle_left = (cx - r, cy) // Left point of the circle + let circle_right = (cx + r, cy) // Right point of the circle + line(p_start, circle_right) // Line from West port to left of circle + line(circle_left, p_end) // Line from right of circle to East port + } + }) + + return (f, tl, tr, br, bl) +} + +#let ammeter( + x: none, + y: none, + w: none, + h: none, + name: none, + name-anchor: "center", + vertical: false, + 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 + ), + x: x, y: y, w: w, h: h, name: name, name-anchor: name-anchor, + ports: ports, fill: fill, stroke: stroke, id: id, debug: debug + ) +} \ No newline at end of file diff --git a/src/elements/electrical/capacitor.typ b/src/elements/electrical/capacitor.typ new file mode 100644 index 0000000..a1ee078 --- /dev/null +++ b/src/elements/electrical/capacitor.typ @@ -0,0 +1,138 @@ +#import "@preview/cetz:0.3.2": draw, coordinate +#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 + ) +} \ No newline at end of file diff --git a/src/elements/electrical/inductor.typ b/src/elements/electrical/inductor.typ new file mode 100644 index 0000000..27aefdc --- /dev/null +++ b/src/elements/electrical/inductor.typ @@ -0,0 +1,137 @@ +#import "@preview/cetz:0.3.2": draw, +#import "../element.typ" +#import "../ports.typ": add-port + +#let draw-shape( + id, + tl, + tr, + br, + bl, + fill, + stroke, + vertical: false, +) = { + let (x0, y0) = tl + let (x1, y1) = br + + let w = x1 - x0 + let h = y1 - y0 + + let cx = x0 + w / 2 + let cy = y0 + h / 2 + + let line = draw.line.with(stroke: stroke) + let arc = draw.arc.with(stroke: stroke) + let loops = 4 // Number of half-circle loops + + let f = draw.group( + name: id, + { + if vertical { + // Vertical Inductor + let p_start = (cx, y0) + let p_end = (cx, y1) + let coil_margin = 0.1 * h // Margin for connection lines + let coil_start_y = y0 + coil_margin + let coil_end_y = y1 - coil_margin + let coil_length = coil_end_y - coil_start_y + let loop_height = coil_length / loops + let loop_radius = w / 2 // Radius of the arcs depends on the element's width + let first_loop_start_y = coil_start_y + let last_loop_end_y = coil_end_y + + // Draw connection lines (ending at the start/end of the coil loops) + line(p_start, (cx, first_loop_start_y)) + line((cx, last_loop_end_y), p_end) + + // Draw loops + for i in range(loops) { + let loop_center_y = coil_start_y + loop_height * i + loop_height / 2 + arc( + (cx, loop_center_y), + start: -90deg, + delta: 180deg, + radius: loop_radius, + ) + } + } else { + // Horizontal Inductor + let p_start = (x0, cy) + let p_end = (x1, cy) + let coil_margin = 0.1 * w // Margin for connection lines + let coil_start_x = x0 + coil_margin + let coil_end_x = x1 - coil_margin + let coil_length = coil_end_x - coil_start_x + let loop_width = coil_length / loops + let loop_radius = h / 2 // Radius of the arcs depends on the element's height + let first_loop_start_x = coil_start_x + let last_loop_end_x = coil_end_x + + draw.merge-path({ + // Draw connection lines (ending at the start/end of the coil loops) + line(p_start, (first_loop_start_x, cy)) + + // Draw loops + for i in range(loops) { + let loop_center_x = coil_start_x + loop_width * i + loop_width / 2 + arc( + (loop_center_x, cy), + start: 0deg, + delta: 180deg, + radius: loop_radius / 2.5, + anchor: "origin", + ) + } + + line((last_loop_end_x, cy), p_end) + }) + } + }, + ) + + return (f, tl, tr, br, bl) +} + +#let inductor( + x: none, + y: none, + w: none, + h: none, + name: none, + name-anchor: "center", + vertical: false, + 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), + x: x, + y: y, + w: w, + h: h, + name: name, + name-anchor: name-anchor, + ports: ports, + fill: fill, + stroke: stroke, + id: id, + debug: debug, + ) +} diff --git a/src/elements/electrical/lamp.typ b/src/elements/electrical/lamp.typ new file mode 100644 index 0000000..b167d65 --- /dev/null +++ b/src/elements/electrical/lamp.typ @@ -0,0 +1,85 @@ +#import "@preview/cetz:0.3.2": draw +#import "../element.typ" +#import "../ports.typ": add-port + +#let draw-shape( + id, tl, tr, br, bl, + fill, stroke, + vertical: false +) = { + let (x0, y0) = tl + let (x1, y1) = br + + let w = x1 - x0 + let h = y1 - y0 + + let cx = x0 + w / 2 + let cy = y0 + h / 2 + let r = calc.min(w, h) / 3 + + let line = draw.line.with(stroke: stroke) + let circle = draw.circle.with(stroke: stroke, fill: fill) + + let f = draw.group(name: id, { + // Kreis für die Glühlampe + circle((cx, cy), radius: r, name: "lamp-circle") + + // X-Symbol im Kreis für die Glühlampe + let r_inner = r * 0.7 // Scale factor for the 'X' size + line("lamp-circle.north-west", "lamp-circle.south-east") + line("lamp-circle.north-east", "lamp-circle.south-west") + + // Verbindungslinien zu den Ports + if vertical { + // Vertikale Lampe + let p_start = (cx, y0) // North port + let p_end = (cx, y1) // South port + let circle_top = (cx, cy - r) // Top point of the circle + let circle_bottom = (cx, cy + r) // Bottom point of the circle + line(p_start, circle_top) // Line from North port to top of circle + line(circle_bottom, p_end) // Line from bottom of circle to South port + } else { + // Horizontale Lampe + let p_start = (x0, cy) // West port + let p_end = (x1, cy) // East port + let circle_left = (cx - r, cy) // Left point of the circle + let circle_right = (cx + r, cy) // Right point of the circle + line(p_end, circle_left) // Line from West port to left of circle + line(circle_right, p_start) // Line from right of circle to East port + } + }) + + return (f, tl, tr, br, bl) +} + +#let lamp( + x: none, + y: none, + w: none, + h: none, + name: none, + name-anchor: "center", + vertical: false, + 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 + ), + x: x, y: y, w: w, h: h, name: name, name-anchor: name-anchor, + ports: ports, fill: fill, stroke: stroke, id: id, debug: debug + ) +} \ No newline at end of file diff --git a/src/elements/electrical/resistor.typ b/src/elements/electrical/resistor.typ new file mode 100644 index 0000000..a89bdb6 --- /dev/null +++ b/src/elements/electrical/resistor.typ @@ -0,0 +1,115 @@ +#import "@preview/cetz:0.3.2": draw, coordinate +#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) + + // Draw rectangle (IEC standard) if zigzags is none + if zigzags == none { + let rect_height = s1 / 2 + let rect_top = m1 - rect_height / 2 + let rect_bottom = m1 + rect_height / 2 + let p4 = pt(o0 + 0.2 * s0, rect_top) + let p5 = pt(o0 + 0.8 * s0, rect_bottom) + 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) + } + // Draw zigzags (ANSI standard) if zigzags is an integer + else if type(zigzags) == int { + 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) + } + // Fallback or error? For now, just return nothing or raise an error. + // Let's return an empty group for now. + return (draw.group(name: id, {}), 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 (int, none): Number of zigzags for the ANSI style symbol. If `none` (default), a rectangle (IEC style) is drawn. +#let resistor( + x: none, + y: none, + w: none, + h: none, + name: none, + name-anchor: "center", + vertical: false, + zigzags: none, // Default to IEC style (rectangle) + 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 + ) +} diff --git a/src/elements/electrical/switch.typ b/src/elements/electrical/switch.typ new file mode 100644 index 0000000..b8638cd --- /dev/null +++ b/src/elements/electrical/switch.typ @@ -0,0 +1,136 @@ +#import "@preview/cetz:0.3.2": draw +#import "../element.typ" +#import "../ports.typ": add-port + +#let draw-shape( + id, + tl, + tr, + br, + bl, + fill, + stroke, + vertical: false, + closed: false, +) = { + let (x0, y0) = tl + let (x1, y1) = br + + let w = x1 - x0 + let h = y1 - y0 + + let line = draw.line.with(stroke: stroke) + let circle = draw.circle.with(stroke: stroke, fill: white) // Use white fill for visibility + let terminal_radius = 0.05 * calc.min(w, h) // Small radius for terminals + + let cx = x0 + w / 2 // Center x + let cy = y0 + h / 2 // Center y + + let f = draw.group( + name: id, + { + if vertical { + // Vertical Switch + let p0 = (cx, y0) // North port + let p1 = (cx, y1) // South port + let terminal0 = (cx, y0 + 0.2 * h) // Upper terminal position + let terminal1 = (cx, y1 - 0.2 * h) // Lower terminal position + + // Draw connection lines (ending at the terminals) + line(p0, terminal0) // Line from North port to upper terminal + line(terminal1, p1) // Line from lower terminal to South port + + // Draw terminals (circles) + circle(terminal0, radius: terminal_radius, name: "left-connector") + circle(terminal1, radius: terminal_radius, name: "right-connector") + + // Draw switch lever + let lever_end + let lever_start + if closed { + lever_start = "left-connector.north" + lever_end = "right-connector.south" + } else { + lever_start = "left-connector.135deg" + lever_end = (rel: (-45deg, calc.abs(y1 - y0) * 0.6), to: "left-connector.45deg") + } + line(lever_start, lever_end) + } else { + // Horizontal Switch + let p0 = (x0, cy) // West port + let p1 = (x1, cy) // East port + let terminal0 = (x0 + 0.2 * w, cy) // Left terminal position + let terminal1 = (x1 - 0.2 * w, cy) // Right terminal position + + // Draw connection lines (ending at the terminals) + line(p0, terminal0) // Line from West port to left terminal + line(terminal1, p1) // Line from right terminal to East port + + // Draw terminals (circles) + circle(terminal0, radius: terminal_radius, name: "left-connector") + circle(terminal1, radius: terminal_radius, name: "right-connector") + + // Draw switch lever + let lever_end + let lever_start + if closed { + lever_start = "left-connector.west" + lever_end = "right-connector.east" + } else { + lever_start = "left-connector.225deg" + lever_end = (rel: (45deg, calc.abs(x1 - x0) * 0.6), to: "left-connector.45deg") + } + line(lever_start, lever_end) + } + }, + ) + + return (f, tl, tr, br, bl) +} + +#let switch( + x: none, + y: none, + w: none, + h: none, + name: none, + name-anchor: "center", + vertical: false, + closed: false, + 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, + closed: closed, + ), + x: x, + y: y, + w: w, + h: h, + name: name, + name-anchor: name-anchor, + ports: ports, + fill: fill, + stroke: stroke, + id: id, + debug: debug, + ) +} diff --git a/src/elements/electrical/voltage-source.typ b/src/elements/electrical/voltage-source.typ new file mode 100644 index 0000000..2ddf140 --- /dev/null +++ b/src/elements/electrical/voltage-source.typ @@ -0,0 +1,100 @@ +#import "@preview/cetz:0.3.2": draw +#import "../element.typ" +#import "../ports.typ": add-port + +#let draw-shape( + id, tl, tr, br, bl, + fill, stroke, + vertical: false +) = { + let (x0, y0) = tl + let (x1, y1) = br + + let w = x1 - x0 + let h = y1 - y0 + + let line = draw.line.with(stroke: stroke) + let cx = x0 + w / 2 + let cy = y0 + h / 2 + + let f = draw.group(name: id, { + if vertical { + // Vertical voltage source (battery symbol) - Centered + let p0 = (cx, y0) // North port (+) + let p1 = (cx, y1) // South port (-) + let gap = 0.1 * h // Gap between the two plates + let plate_width = 0.6 * w // Width of the plates + + // Center the plates around cy + let plate0_y = cy - gap / 2 // Position of the long plate (+) + let plate1_y = cy + gap / 2 // Position of the short plate (-) + + // Create a thicker stroke for the short plate + let thicker_stroke = (paint: stroke.paint, thickness: stroke.thickness + 1pt) + + // Draw plates + line((cx - plate_width / 2, plate0_y), (cx + plate_width / 2, plate0_y)) // Long plate (+) + line((cx - plate_width / 3, plate1_y), (cx + plate_width / 3, plate1_y)) // Short plate (-) + + // Draw connection lines (ending at the plates) + line(p0, (cx, plate0_y)) // Line from North port to top plate + line((cx, plate1_y), p1) // Line from bottom plate to South port + + } else { + // Horizontal voltage source (battery symbol) - Centered + let p0 = (x0, cy) // West port (+) + let p1 = (x1, cy) // East port (-) + let gap = 0.1 * w // Gap between the two plates + let plate_height = 0.6 * h // Height of the plates + + // Center the plates around cx + let plate0_x = cx - gap / 2 // Position of the long plate (+) + let plate1_x = cx + gap / 2 // Position of the short plate (-) + + // Create a thicker stroke for the short plate + let thicker_stroke = (paint: stroke.paint, thickness: stroke.thickness + 1pt) + + // Draw plates + line((plate0_x, cy - plate_height / 2), (plate0_x, cy + plate_height / 2)) // Long plate (+) + line((plate1_x, cy - plate_height / 3), (plate1_x, cy + plate_height / 3)) // Short plate (-) + + // Draw connection lines (ending at the plates) + line(p0, (plate0_x, cy)) // Line from West port to left plate + line((plate1_x, cy), p1) // Line from right plate to East port + } + }) + + return (f, tl, tr, br, bl) +} + +#let voltage-source( + x: none, + y: none, + w: none, + h: none, + name: none, + name-anchor: "center", + vertical: false, + 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 + ), + x: x, y: y, w: w, h: h, name: name, name-anchor: name-anchor, + ports: ports, fill: fill, stroke: stroke, id: id, debug: debug + ) +} \ No newline at end of file diff --git a/src/elements/electrical/voltmeter.typ b/src/elements/electrical/voltmeter.typ new file mode 100644 index 0000000..be2f18c --- /dev/null +++ b/src/elements/electrical/voltmeter.typ @@ -0,0 +1,81 @@ +#import "@preview/cetz:0.3.2": draw +#import "../element.typ" +#import "../ports.typ": add-port + +#let draw-shape( + id, tl, tr, br, bl, + fill, stroke, + vertical: false +) = { + let (x0, y0) = tl + let (x1, y1) = br + + let w = x1 - x0 + let h = y1 - y0 + + let cx = x0 + w / 2 + let cy = y0 + h / 2 + let r = calc.min(w, h) / 3 + + let line = draw.line.with(stroke: stroke) + let circle = draw.circle.with(stroke: stroke, fill: fill) + + let f = draw.group(name: id, { + // Kreis und 'V'-Symbol + circle((cx, cy), radius: r) + draw.content((cx, cy), [V], anchor: "center") + + // Verbindungslinien zu den Ports + if vertical { + // Vertikales Voltmeter + let p_start = (cx, y0) // North port + let p_end = (cx, y1) // South port + let circle_top = (cx, cy - r) // Top point of the circle + let circle_bottom = (cx, cy + r) // Bottom point of the circle + line(p_start, circle_top) // Line from North port to top of circle + line(circle_bottom, p_end) // Line from bottom of circle to South port + } else { + // Horizontales Voltmeter + let p_start = (x0, cy) // West port + let p_end = (x1, cy) // East port + let circle_left = (cx - r, cy) // Left point of the circle + let circle_right = (cx + r, cy) // Right point of the circle + line(p_start, circle_right) // Line from West port to left of circle + line(circle_left, p_end) // Line from right of circle to East port + } + }) + + return (f, tl, tr, br, bl) +} + +#let voltmeter( + x: none, + y: none, + w: none, + h: none, + name: none, + name-anchor: "center", + vertical: false, + 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 + ), + x: x, y: y, w: w, h: h, name: name, name-anchor: name-anchor, + ports: ports, fill: fill, stroke: stroke, id: id, debug: debug + ) +} \ No newline at end of file diff --git a/src/lib.typ b/src/lib.typ index 7f27208..0603b79 100644 --- a/src/lib.typ +++ b/src/lib.typ @@ -4,4 +4,5 @@ #import "element.typ" #import "gates.typ" #import "util.typ" -#import "wire.typ" \ No newline at end of file +#import "wire.typ" +#import "electrical.typ" \ No newline at end of file