adding nmos and pmos #6

Open
opened 2025-03-27 23:57:17 +00:00 by Kreijstal · 4 comments

an attempt to add nmos and pmos

https://typst.app/project/rh20mdDbyd3OPJt98POytf

#import "@preview/circuiteria:0.2.0": circuit, element, util, wire, gates.gate
#import "@preview/cetz:0.2.2": draw


#let nmos-shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl //botom left
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)


  // Define all 25 points (5 rows, 5 columns)
  // Row 0 (Top edge)
  let tl = (x, y + height)  // provided as parameter
  let tml = (x + width/4, y + height)
  let t = (x + width/2, y + height)
  let tmr = (x + 3*width/4, y + height)
  let tr = (x + width, y + height)  // provided as parameter

  // Row 1
  let lmt = (x, y + 3*height/4)
  let ctll = (x + width/4-0.1, y + 3*height/4)
  let ctl = (x + width/4, y + 3*height/4)
  let ct = (x + width/2, y + 3*height/4)
  let ctr = (x + 3*width/4, y + 3*height/4)
  let rmt = (x + width, y + 3*height/4)

  // Row 2 (Centerline)
  let l = (x, y + height/2)
  let cll = (x + width/4-0.1, y + height/2)
  let cl = (x + width/4, y + height/2)
  let c = (x + width/2, y + height/2)
  let cr = (x + 3*width/4, y + height/2)
  let r = (x + width, y + height/2)

  // Row 3
  let lmb = (x, y + height/4)
  let cbll = (x + width/4-0.1, y + height/4)
  let cbl = (x + width/4, y + height/4)
  let cb2 = (x + width/2+0.1, y + height/4)
  let cb = (x + width/2, y + height/4)
  let cbr = (x + 3*width/4, y + height/4)
  let rmb = (x + width, y + height/4)

  // Row 4 (Bottom edge)
  let bl = (x, y)  // provided as parameter
  let bml = (x + width/4, y)
  let b = (x + width/2, y)
  let bmr = (x + 3*width/4, y)
  let br = (x + width, y)  // provided as parameter

  let f = draw.group(name: id, {
    
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(t, ct,ctl,cbl,cb2,mark: (end: ">")) // bottomleft,topleft,top
      }
    )
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(cl, r)
      }
    )
  draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(cb, b)
      }
    )
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(ctll, cbll)
      }
    )
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(l, cll)
      }
    )
    draw.anchor("drain", t)
    draw.anchor("source", t)
    draw.anchor("bulk", r)
    draw.anchor("gate", r)
  })
  return (f, tl, tr, br, bl)
}

#let nmos(
  x: none,
  y: none,
  w: none,
  h: none,
  inputs: 4,
  fill: none,
  stroke: black + 1pt,
  id: "",
  inverted: (),
  debug: (
    ports: false
  )
) = {
  gate(
    draw-shape: nmos-shape,
    x: x,
    y: y,
    w: w,
    h: h,
    inputs: inputs,
    fill: fill,
    stroke: stroke,
    id: id,
    inverted: inverted,
    debug: debug
  )
}


#let pmos-shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl //botom left
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)


  // Define all 25 points (5 rows, 5 columns)
  // Row 0 (Top edge)
  let tl = (x, y + height)  // provided as parameter
  let tml = (x + width/4, y + height)
  let t = (x + width/2, y + height)
  let tmr = (x + 3*width/4, y + height)
  let tr = (x + width, y + height)  // provided as parameter

  // Row 1
  let lmt = (x, y + 3*height/4)
  let ctll = (x + width/4-0.1, y + 3*height/4)
  let ctl = (x + width/4, y + 3*height/4)
  let ct = (x + width/2, y + 3*height/4)
  let ct2 = (x + width/2+0.1, y + 3*height/4)
  let ctr = (x + 3*width/4, y + 3*height/4)
  let rmt = (x + width, y + 3*height/4)

  // Row 2 (Centerline)
  let l = (x, y + height/2)
  let cll = (x + width/4-0.1, y + height/2)
  let cl = (x + width/4, y + height/2)
  let c = (x + width/2, y + height/2)
  let cr = (x + 3*width/4, y + height/2)
  let r = (x + width, y + height/2)

  // Row 3
  let lmb = (x, y + height/4)
  let cbll = (x + width/4-0.1, y + height/4)
  let cbl = (x + width/4, y + height/4)
  let cb2 = (x + width/2+0.1, y + height/4)
  let cb = (x + width/2, y + height/4)
  let cbr = (x + 3*width/4, y + height/4)
  let rmb = (x + width, y + height/4)

  // Row 4 (Bottom edge)
  let bl = (x, y)  // provided as parameter
  let bml = (x + width/4, y)
  let b = (x + width/2, y)
  let bmr = (x + 3*width/4, y)
  let br = (x + width, y)  // provided as parameter

  let f = draw.group(name: id, {
    
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(cb,cbl,ctl,ct,mark: (end: "<")) // bottomleft,topleft,top
      }
    )
    
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(t, ct)
      }
    )
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(cl, r)
      }
    )
  draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(cb, b)
      }
    )
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(ctll, cbll)
      }
    )
    draw.merge-path(
      inset: 0.5em,
      fill: fill,
      stroke: stroke,
      name: id + "-path",
      close: false, {
        draw.line(l, cll)
      }
    )
    draw.anchor("drain", t)
    draw.anchor("source", t)
    draw.anchor("bulk", r)
    draw.anchor("gate", r)
  })
  return (f, tl, tr, br, bl)
}


#let pmos(
  x: none,
  y: none,
  w: none,
  h: none,
  inputs: 4,
  fill: none,
  stroke: black + 1pt,
  id: "",
  inverted: (),
  debug: (
    ports: false
  )
) = {
  gate(
    draw-shape:pmos-shape,
    x: x,
    y: y,
    w: w,
    h: h,
    inputs: inputs,
    fill: fill,
    stroke: stroke,
    id: id,
    inverted: inverted,
    debug: debug
  )
}

#circuit({

nmos(
    x: 3, y: -3, w: 2, h: 2, id: "and"
  )

  pmos(
    x: 3, y: -6, w: 2, h: 2, id: "and"
  )
})


an attempt to add nmos and pmos https://typst.app/project/rh20mdDbyd3OPJt98POytf ```typst #import "@preview/circuiteria:0.2.0": circuit, element, util, wire, gates.gate #import "@preview/cetz:0.2.2": draw #let nmos-shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl //botom left let (width, height) = (tr.at(0) - x, tr.at(1) - y) // Define all 25 points (5 rows, 5 columns) // Row 0 (Top edge) let tl = (x, y + height) // provided as parameter let tml = (x + width/4, y + height) let t = (x + width/2, y + height) let tmr = (x + 3*width/4, y + height) let tr = (x + width, y + height) // provided as parameter // Row 1 let lmt = (x, y + 3*height/4) let ctll = (x + width/4-0.1, y + 3*height/4) let ctl = (x + width/4, y + 3*height/4) let ct = (x + width/2, y + 3*height/4) let ctr = (x + 3*width/4, y + 3*height/4) let rmt = (x + width, y + 3*height/4) // Row 2 (Centerline) let l = (x, y + height/2) let cll = (x + width/4-0.1, y + height/2) let cl = (x + width/4, y + height/2) let c = (x + width/2, y + height/2) let cr = (x + 3*width/4, y + height/2) let r = (x + width, y + height/2) // Row 3 let lmb = (x, y + height/4) let cbll = (x + width/4-0.1, y + height/4) let cbl = (x + width/4, y + height/4) let cb2 = (x + width/2+0.1, y + height/4) let cb = (x + width/2, y + height/4) let cbr = (x + 3*width/4, y + height/4) let rmb = (x + width, y + height/4) // Row 4 (Bottom edge) let bl = (x, y) // provided as parameter let bml = (x + width/4, y) let b = (x + width/2, y) let bmr = (x + 3*width/4, y) let br = (x + width, y) // provided as parameter let f = draw.group(name: id, { draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(t, ct,ctl,cbl,cb2,mark: (end: ">")) // bottomleft,topleft,top } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(cl, r) } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(cb, b) } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(ctll, cbll) } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(l, cll) } ) draw.anchor("drain", t) draw.anchor("source", t) draw.anchor("bulk", r) draw.anchor("gate", r) }) return (f, tl, tr, br, bl) } #let nmos( x: none, y: none, w: none, h: none, inputs: 4, fill: none, stroke: black + 1pt, id: "", inverted: (), debug: ( ports: false ) ) = { gate( draw-shape: nmos-shape, x: x, y: y, w: w, h: h, inputs: inputs, fill: fill, stroke: stroke, id: id, inverted: inverted, debug: debug ) } #let pmos-shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl //botom left let (width, height) = (tr.at(0) - x, tr.at(1) - y) // Define all 25 points (5 rows, 5 columns) // Row 0 (Top edge) let tl = (x, y + height) // provided as parameter let tml = (x + width/4, y + height) let t = (x + width/2, y + height) let tmr = (x + 3*width/4, y + height) let tr = (x + width, y + height) // provided as parameter // Row 1 let lmt = (x, y + 3*height/4) let ctll = (x + width/4-0.1, y + 3*height/4) let ctl = (x + width/4, y + 3*height/4) let ct = (x + width/2, y + 3*height/4) let ct2 = (x + width/2+0.1, y + 3*height/4) let ctr = (x + 3*width/4, y + 3*height/4) let rmt = (x + width, y + 3*height/4) // Row 2 (Centerline) let l = (x, y + height/2) let cll = (x + width/4-0.1, y + height/2) let cl = (x + width/4, y + height/2) let c = (x + width/2, y + height/2) let cr = (x + 3*width/4, y + height/2) let r = (x + width, y + height/2) // Row 3 let lmb = (x, y + height/4) let cbll = (x + width/4-0.1, y + height/4) let cbl = (x + width/4, y + height/4) let cb2 = (x + width/2+0.1, y + height/4) let cb = (x + width/2, y + height/4) let cbr = (x + 3*width/4, y + height/4) let rmb = (x + width, y + height/4) // Row 4 (Bottom edge) let bl = (x, y) // provided as parameter let bml = (x + width/4, y) let b = (x + width/2, y) let bmr = (x + 3*width/4, y) let br = (x + width, y) // provided as parameter let f = draw.group(name: id, { draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(cb,cbl,ctl,ct,mark: (end: "<")) // bottomleft,topleft,top } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(t, ct) } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(cl, r) } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(cb, b) } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(ctll, cbll) } ) draw.merge-path( inset: 0.5em, fill: fill, stroke: stroke, name: id + "-path", close: false, { draw.line(l, cll) } ) draw.anchor("drain", t) draw.anchor("source", t) draw.anchor("bulk", r) draw.anchor("gate", r) }) return (f, tl, tr, br, bl) } #let pmos( x: none, y: none, w: none, h: none, inputs: 4, fill: none, stroke: black + 1pt, id: "", inverted: (), debug: ( ports: false ) ) = { gate( draw-shape:pmos-shape, x: x, y: y, w: w, h: h, inputs: inputs, fill: fill, stroke: stroke, id: id, inverted: inverted, debug: debug ) } #circuit({ nmos( x: 3, y: -3, w: 2, h: 2, id: "and" ) pmos( x: 3, y: -6, w: 2, h: 2, id: "and" ) }) ```
Author

I added more circuit stuff
I'd like help by adding rotations image.png

#import "@preview/circuiteria:0.2.0": circuit, element, util, wire, gates.gate // Removed gates.gate import
#import "@preview/cetz:0.3.4": draw, canvas, coordinate

// Helper function for NMOS/PMOS shapes
#let sig(m)={
  if m == 0 { 1 } else { calc.abs(m)/m } // Avoid division by zero if width/height is 0
}

// --- NMOS Shape Definition ---
// Defines anchors: drain, source, gate, bulk, north, south, east, west, center
#let nmos_shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl // bottom left
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)
  // Define points relative to bl=(x,y)
  let t   = (x + width/2, y + height)
  let ctll= (x + width/4-0.1*sig(width), y + 3*height/4)
  let ct  = (x + width/2, y + 3*height/4)
  let ctl = (x + width/4, y + 3*height/4)
  let cll = (x + width/4-0.1*sig(width), y + height/2)
  let l   = (x, y + height/2)
  let cl  = (x + width/4, y + height/2)
  let r   = (x + width, y + height/2)
  let cbll = (x + width/4-0.1*sig(width), y + height/4)
  let cbl = (x + width/4, y + height/4)
  let cb  = (x + width/2, y + height/4)
  let cb2 = (x + width/2+0.1*sig(width), y + height/4) // Point near center bottom
  let b   = (x + width/2, y)

  let f = draw.group(name: id, {
    // Draw the transistor shape lines
    draw.line(t, ct)
    draw.line(ct, ctl, cbl, cb2, mark: (end: ">"))
    draw.line(cb, b)
    draw.line(l, cll)
    draw.line(ctll, cbll)
    draw.line(cl, r)
    // Define LOGICAL anchors for port connections
    draw.anchor("drain", t)
    draw.anchor("source", b)
    draw.anchor("gate", l)
    draw.anchor("bulk", r)
    // Define standard ELEMENT anchors for relative placement
    draw.anchor("north", t)
    draw.anchor("south", b)
    draw.anchor("west", l)
    draw.anchor("east", r)
    draw.anchor("center", (x + width/2, y + height/2))
  })
  return (f, tl, tr, br, bl)
}

// --- NMOS Element Function (using element.elmt) ---
#let nmos(
  x: none,
  y: none,
  w: none,
  h: none,
  fill: none,
  stroke: black + 1pt,
  id: "",
  debug: (ports: false) // Removed unused inputs/inverted args
) = {
  element.elmt( // Use element.elmt
    draw-shape: nmos_shape,
    x: x,
    y: y,
    w: w,
    h: h,
    ports: ( // Explicitly define ports linking to anchors in nmos_shape
      north: ((id: "drain"),), // Port "nmos1-port-drain" at anchor "drain"
      south: ((id: "source"),),// Port "nmos1-port-source" at anchor "source"
      west:  ((id: "gate"),),  // Port "nmos1-port-gate" at anchor "gate"
      east:  ((id: "bulk"),),  // Port "nmos1-port-bulk" at anchor "bulk"
    ),
    fill: fill,
    stroke: stroke,
    id: id,
    debug: debug
  )
}

#let impedance_eu_shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)
  let center_y = y + height / 2

  // Define proportions (similar to resistor)
  let lead_ratio = 0.15 // Fraction of total width for each lead
  let lead_len = width * lead_ratio
  let box_width = width * (1.0 - 2.0 * lead_ratio) // Width of the rectangle

  // Calculate points
  let term1 = (x, center_y) // Left terminal
  let box_left = x + lead_len // Left edge of rectangle
  let box_right = x + width - lead_len // Right edge of rectangle
  let term2 = (x + width, center_y) // Right terminal

  // Rectangle corner points
  let box_bl = (box_left, y)
  let box_tr = (box_right, y + height)

  let f = draw.group(name: id, {
    // Leads
    draw.line(term1, (box_left, center_y), stroke: stroke)
    draw.line((box_right, center_y), term2, stroke: stroke)
    // Rectangular body
    draw.rect(box_bl, box_tr, fill: fill, stroke: stroke)

    // Anchors for ports
    draw.anchor("t1", term1) // Terminal 1 (left)
    draw.anchor("t2", term2) // Terminal 2 (right)
    // Standard anchors (bounding box)
    draw.anchor("west", term1)
    draw.anchor("east", term2)
    draw.anchor("center", (x + width/2, center_y))
    draw.anchor("north", (x + width/2, y + height)) // Top edge of element box
    draw.anchor("south", (x + width/2, y)) // Bottom edge of element box
  })
  return (f, tl, tr, br, bl)
}

// --- European Impedance Element Function ---
#let impedance_eu(
  x: none,
  y: none,
  w: 1,     // Default width (same as resistor)
  h: 0.3,   // Default height (same as resistor)
  fill: none, // Default to no fill (just outline)
  stroke: black + 1pt,
  id: "",
  debug: (ports: false)
) = {
  element.elmt(
    draw-shape: impedance_eu_shape,
    x: x, y: y, w: w, h: h,
    ports: (
      west: ((id: "t1"),), // Port t1 = west anchor
      east: ((id: "t2"),), // Port t2 = east anchor
    ),
    fill: fill,
    stroke: stroke,
    id: id,
    debug: debug
  )
}

// --- PMOS Shape Definition --- [CORRECTED ANCHORS]
// Defines anchors: source (top), drain (bottom), gate, bulk
#let pmos_shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl // bottom left
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)
  // Define points relative to bl=(x,y)
  let t   = (x + width/2, y + height) // Top center (physical top point)
  let ctll= (x + width/4-0.1*sig(width), y + 3*height/4)
  let ct  = (x + width/2, y + 3*height/4)
  let ctl = (x + width/4, y + 3*height/4)
  let cll = (x + width/4-0.1*sig(width), y + height/2)
  let l   = (x, y + height/2) // Left center (Gate)
  let cl  = (x + width/4, y + height/2)
  let r   = (x + width, y + height/2) // Right center (Bulk)
  let cbll = (x + width/4-0.1*sig(width), y + height/4)
  let cbl = (x + width/4, y + height/4)
  let cb  = (x + width/2, y + height/4)
  let b   = (x + width/2, y) // Bottom center (physical bottom point)
  let circle_center = (x + width/4 - 0.1*sig(width) - 0.15*sig(width), y + height/2)
  let circle_radius = 0.05 * calc.min(width, height)

  let f = draw.group(name: id, {
    // Draw the transistor shape lines
    draw.line(t, ct) // Top lead (Source) to top H
    //draw.line(ct, ctl, cbl, cb, mark: (end: "<")) // WRONG
    draw.line(cb,cbl,ctl,ct, mark: (end: "<")) // CORRECT
    draw.line(cb, b) // Bottom lead (Drain) from bottom H
    draw.line((rel: (+circle_radius*2, 0), to: l), cll) // Gate lead adjusted for circle
    draw.line(ctll, cbll) // Gate vertical bar
    draw.line(cl, r) // Bulk lead connection line
    draw.circle(circle_center, radius: circle_radius, stroke: stroke, fill: white); // PMOS circle

    // --- CORRECTED LOGICAL ANCHORS ---
    draw.anchor("source", t) // Logical SOURCE is the TOP terminal
    draw.anchor("drain", b)  // Logical DRAIN is the BOTTOM terminal
    draw.anchor("gate", l)   // Logical GATE is the LEFT terminal
    draw.anchor("bulk", r)   // Logical BULK is the RIGHT terminal
    // --- Standard ELEMENT anchors for relative placement ---
    draw.anchor("north", t) // Topmost physical point
    draw.anchor("south", b) // Bottommost physical point
    draw.anchor("west", l)
    draw.anchor("east", r)
    draw.anchor("center", (x + width/2, y + height/2))
  })
  return (f, tl, tr, br, bl)
}

// --- PMOS Element Function (using element.elmt) --- [CORRECTED PORT MAPPING]
#let pmos(
  x: none, y: none,
  w: 1.0, h: 1.0,
  fill: none, stroke: black + 1pt,
  id: "", debug: (ports: false)
) = {
  element.elmt(
    draw-shape: pmos_shape, x: x, y: y, w: w, h: h,
    ports: ( // Link logical ports to physical shape anchors (north/south/west/east)
      // The 'north' anchor in the shape is the physical top, which we defined as logical 'source'
      north: ((id: "source"),), // Element's North port corresponds to logical Source
      // The 'south' anchor in the shape is the physical bottom, which we defined as logical 'drain'
      south: ((id: "drain"),),  // Element's South port corresponds to logical Drain
      west:  ((id: "gate"),),   // Element's West port corresponds to logical Gate
      east:  ((id: "bulk"),),   // Element's East port corresponds to logical Bulk
    ),
    fill: fill, stroke: stroke, id: id, debug: debug
  )
}

// --- GND Symbol Function ---
// Defines anchor "conn" and "north"
#let gnd(pos, length: 0.5, spacing: 0.15, stroke: black + 1pt, id: "gnd") = {
  draw.group(name: id, {
    let p1 = pos // Top connection point
    let p2 = (rel: (0, -spacing), to: p1)
    let p3 = (rel: (0, -spacing), to: p2)
    let p4 = (rel: (0, -spacing), to: p3)
    let len1 = length
    let len2 = length * 0.7
    let len3 = length * 0.4
    draw.line(p1, p2, stroke: stroke) // Stem
    draw.line((rel: (-len1/2, 0), to: p2), (rel: (len1/2, 0), to: p2), stroke: stroke) // Bar 1
    draw.line((rel: (-len2/2, 0), to: p3), (rel: (len2/2, 0), to: p3), stroke: stroke) // Bar 2
    draw.line((rel: (-len3/2, 0), to: p4), (rel: (len3/2, 0), to: p4), stroke: stroke) // Bar 3
    draw.anchor("conn", p1) // Anchor for wiring
    draw.anchor("north", p1) // Standard anchor
  })
}

// --- Vsource Shape Definition ---
// Independent Voltage Source Symbol
#let vsource_shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)
  let center_x = x + width / 2
  let center_y = y + height / 2
  let radius = calc.min(width, height) / 2 * 0.8 // Slightly smaller radius

  let top_term = (center_x, y + height)
  let bot_term = (center_x, y)
  let top_circle = (center_x, center_y + radius)
  let bot_circle = (center_x, center_y - radius)
  let plus_pos = (center_x, center_y + radius * 0.5)
  let minus_pos = (center_x, center_y - radius * 0.5)

  let f = draw.group(name: id, {
    // Circle
    draw.circle((center_x, center_y), radius: radius, stroke: stroke, fill: fill)
    // Terminals lines
    draw.line(top_term, top_circle, stroke: stroke)
    draw.line(bot_circle, bot_term, stroke: stroke)
    // Plus sign
    draw.line((rel: (-radius*0.2, 0), to: plus_pos), (rel: (radius*0.2, 0), to: plus_pos), stroke: stroke)
    draw.line((rel: (0, -radius*0.2), to: plus_pos), (rel: (0, radius*0.2), to: plus_pos), stroke: stroke)
    // Minus sign
    draw.line((rel: (-radius*0.2, 0), to: minus_pos), (rel: (radius*0.2, 0), to: minus_pos), stroke: stroke)

    // Anchors for ports
    draw.anchor("p", top_term) // Positive terminal
    draw.anchor("n", bot_term) // Negative terminal
    // Standard anchors
    draw.anchor("north", top_term)
    draw.anchor("south", bot_term)
    draw.anchor("center", (center_x, center_y))
    draw.anchor("west", (x, center_y))
    draw.anchor("east", (x + width, center_y))
  })
  return (f, tl, tr, br, bl)
}

// --- Vsource Element Function ---
#let vsource(x: none, y: none, w: 1, h: 1, fill: white, stroke: black + 1pt, id: "", debug: (ports: false)) = {
  element.elmt(
    draw-shape: vsource_shape, x: x, y: y, w: w, h: h,
    ports: (north: ((id: "p"),), south: ((id: "n"),),), // Port p = north, Port n = south
    fill: fill, stroke: stroke, id: id, debug: debug
  )
}

// --- Isource Shape Definition ---
// Independent Current Source Symbol
#let isource_shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)
  let center_x = x + width / 2
  let center_y = y + height / 2
  let radius = calc.min(width, height) / 2 * 0.8 // Slightly smaller radius

  let top_term = (center_x, y + height)
  let bot_term = (center_x, y)
  let top_circle = (center_x, center_y + radius)
  let bot_circle = (center_x, center_y - radius)
  // Arrow points (pointing up)
  let arrow_tip = (center_x, center_y + radius * 0.5)
  let arrow_base = (center_x, center_y - radius * 0.5)
  let arrow_l = (center_x - radius * 0.25, center_y + radius * 0.1)
  let arrow_r = (center_x + radius * 0.25, center_y + radius * 0.1)


  let f = draw.group(name: id, {
    // Circle
    draw.circle((center_x, center_y), radius: radius, stroke: stroke, fill: fill)
    // Terminals lines
    draw.line(top_term, top_circle, stroke: stroke)
    draw.line(bot_circle, bot_term, stroke: stroke)
    // Arrow line
    draw.line(arrow_base, arrow_tip, stroke: stroke, mark: (end: ">"))

    // Anchors for ports (assuming current flows out the top)
    draw.anchor("out", top_term)
    draw.anchor("in", bot_term)
    // Standard anchors
    draw.anchor("north", top_term)
    draw.anchor("south", bot_term)
    draw.anchor("center", (center_x, center_y))
    draw.anchor("west", (x, center_y))
    draw.anchor("east", (x + width, center_y))
  })
  return (f, tl, tr, br, bl)
}

// --- Isource Element Function ---
#let isource(x: none, y: none, w: 1, h: 1, fill: white, stroke: black + 1pt, id: "", debug: (ports: false)) = {
  element.elmt(
    draw-shape: isource_shape, x: x, y: y, w: w, h: h,
    ports: (north: ((id: "out"),), south: ((id: "in"),),), // Port out = north, Port in = south
    fill: fill, stroke: stroke, id: id, debug: debug
  )
}



// --- Capacitor Shape Definition ---
// Parallel plates
#let cap_shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)
  let center_y = y + height / 2
  let plate_gap = width * 0.2
  let lead_len = (width - plate_gap) / 2
  let plate_height = height * 0.8

  let p1_x = x + lead_len
  let p2_x = x + lead_len + plate_gap

  let term1 = (x, center_y)
  let term2 = (x + width, center_y)
  let p1_start = (p1_x, center_y)
  let p2_start = (p2_x, center_y)
  let p1_top = (p1_x, center_y + plate_height / 2)
  let p1_bot = (p1_x, center_y - plate_height / 2)
  let p2_top = (p2_x, center_y + plate_height / 2)
  let p2_bot = (p2_x, center_y - plate_height / 2)


  let f = draw.group(name: id, {
    // Leads
    draw.line(term1, p1_start, stroke: stroke)
    draw.line(p2_start, term2, stroke: stroke)
    // Plates
    draw.line(p1_top, p1_bot, stroke: stroke)
    draw.line(p2_top, p2_bot, stroke: stroke)

    // Anchors for ports
    draw.anchor("t1", term1) // Terminal 1 (left)
    draw.anchor("t2", term2) // Terminal 2 (right)
    // Standard anchors
    draw.anchor("west", term1)
    draw.anchor("east", term2)
    draw.anchor("center", (x + width/2, center_y))
    draw.anchor("north", (x + width/2, y + height))
    draw.anchor("south", (x + width/2, y))
  })
  return (f, tl, tr, br, bl)
}

// --- Capacitor Element Function ---
#let cap(x: none, y: none, w: 1, h: 1, fill: none, stroke: black + 1pt, id: "", debug: (ports: false)) = {
  element.elmt(
    draw-shape: cap_shape, x: x, y: y, w: w, h: h,
    ports: (west: ((id: "t1"),), east: ((id: "t2"),),), // Port t1 = west, Port t2 = east
    fill: fill, stroke: stroke, id: id, debug: debug
  )
}


// --- Resistor Shape Definition ---
// Zig-zag resistor symbol
#let res_shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)
  let center_y = y + height / 2

  // Define proportions
  let lead_ratio = 0.15 // Fraction of total width for each lead
  let lead_len = width * lead_ratio
  let zigzag_width = width * (1.0 - 2.0 * lead_ratio) // Width available for zig-zags
  let num_segments = 7
  let dx = zigzag_width / num_segments // Horizontal distance covered by each segment
  let zig_height = height * 0.4 // Amplitude (half of total vertical zig-zag extent)

  // Calculate points
  let term1 = (x, center_y)
  let p_start = (x + lead_len, center_y) // Start of zig-zag

  // Generate zig-zag points dynamically
  let points = (p_start,) // Start with the first point
  for i in range(num_segments) {
    let current_x = p_start.at(0) + dx * (i + 1)
    // Alternate adding and subtracting zig_height
    let current_y = center_y + zig_height * calc.pow(-1,i) // + for i=0, - for i=1, + for i=2...
    points.push((current_x, current_y))
  }
  // Ensure last point is on the center line if num_segments is even
   let p_end = (p_start.at(0) + zigzag_width, center_y)
   points.at(num_segments) = p_end // Correct last point to be on center line


  let term2 = (x + width, center_y) // End terminal

  let f = draw.group(name: id, {
    // Leads
    draw.line(term1, p_start, stroke: stroke)
    draw.line(p_end, term2, stroke: stroke)
    // Zig-zag body using the calculated points
    draw.line(..points, stroke: stroke) // Spread the points array into line arguments

    // Anchors for ports
    draw.anchor("t1", term1) // Terminal 1 (left)
    draw.anchor("t2", term2) // Terminal 2 (right)
    // Standard anchors (bounding box)
    draw.anchor("west", term1)
    draw.anchor("east", term2)
    draw.anchor("center", (x + width/2, center_y))
    draw.anchor("north", (x + width/2, center_y + zig_height)) // Top extent
    draw.anchor("south", (x + width/2, center_y - zig_height)) 
  })
  return (f, tl, tr, br, bl)
}

// --- Resistor Element Function ---
#let res(x: none, y: none, w: 1, h: 0.4, fill: none, stroke: black + 1pt, id: "", debug: (ports: false)) = {
  element.elmt(
    draw-shape: res_shape, x: x, y: y, w: w, h: h,
    ports: (west: ((id: "t1"),), east: ((id: "t2"),),), // Port t1 = west, Port t2 = east
    fill: fill, stroke: stroke, id: id, debug: debug
  )
}

#let ind_shape(id, tl, tr, br, bl, fill, stroke) = {
  let (x, y) = bl
  let (width, height) = (tr.at(0) - x, tr.at(1) - y)
  let center_y = y + height / 2

  // Define proportions
  let lead_ratio = 0.1 // Fraction of total width for each lead
  let lead_len = width * lead_ratio
  let coil_width = width * (1.0 - 2.0 * lead_ratio) // Width available for coil
  let num_loops = 4 // Number of semi-circular loops (standard is 3 or 4)
  let loop_width = coil_width / num_loops // Horizontal width of each loop
  let loop_radius = loop_width / 2 // Radius of the semi-circles

  // Calculate terminal and coil start/end points
  let term1 = (x, center_y)
  let p_start2 = (x +0.13+lead_len, center_y)
  let p_start = (x +lead_len, center_y) // Start of coil
  let p_end = (x + width , center_y) // End of coil
  let term2 = (width+x+lead_len+0.13, center_y) // End terminal

  let f = draw.group(name: id, {
    // Draw Leads
    draw.line(term1, p_start2, stroke: stroke)
    draw.line(p_end, term2, stroke: stroke)

    // Draw Coil Loops using arcs (Corrected Syntax)
    for i in range(num_loops) {
      let loop_center_x = p_start.at(0) + loop_width * i + loop_radius
      // Correct usage: arc(center, radius: r, start: angle, delta: angle)
      // We start at 180deg (left) and sweep +180deg (counter-clockwise) to 0deg (right)
      draw.arc(
        (loop_center_x, center_y), // Center position is the first argument
        radius: loop_radius,
        start: 180deg,
        delta: 180deg, // Positive delta for counter-clockwise sweep over the top
        stroke: stroke
      )
    }

    // Anchors for ports
    draw.anchor("t1", term1) // Terminal 1 (left)
    draw.anchor("t2", term2) // Terminal 2 (right)
    // Standard anchors
    draw.anchor("west", term1)
    draw.anchor("east", term2)
    draw.anchor("center", (x + width/2, center_y))
    // Use the actual top of the arc for North anchor
    draw.anchor("north", (x + width/2, center_y + loop_radius))
    // Use the bounding box bottom for South anchor
    // If height is small, center_y - loop_radius might be below y.
    // Using 'y' ensures it's the element's defined bottom.
    draw.anchor("south", (x + width/2, y))
  })
  return (f, tl, tr, br, bl)
}

// --- Inductor Element Function ---
// (This function remains the same, it just calls the corrected shape)
#let ind(
  x: none,
  y: none,
  w: 1.2, // Inductors often wider than high
  h: 0.5,
  fill: none,
  stroke: black + 1pt,
  id: "",
  debug: (ports: false)
) = {
  element.elmt(
    draw-shape: ind_shape,
    x: x, y: y, w: w, h: h,
    ports: (
      west: ((id: "t1"),), // Port t1 = west anchor
      east: ((id: "t2"),), // Port t2 = east anchor
    ),
    fill: fill,
    stroke: stroke,
    id: id,
    debug: debug
  )
}
#circuit({
  impedance_eu(x: 0, y: -2, id: "Z1")
  // Place a capacitor
  cap(x: 0, y: -4, id: "C1")
  ind(x: 0, y: -8, id: "R2")
  res(x: 0, y: 0, id: "R1")
  // === Placement Phase ===
  let nmos_x = 3; let nmos_y = -3; let nmos_w = 1.5; let nmos_h = 1.5
  let pmos_x = nmos_x; let pmos_y = nmos_y + nmos_h + 2 
  let pmos_w = nmos_w; let pmos_h = nmos_h
  let gnd_x = nmos_x; let gnd_y = nmos_y - 1 
  let vdd_x = pmos_x; let vdd_y = pmos_y + pmos_h + 1 
  

  // Place elements
  nmos(x: nmos_x, y: nmos_y, w: nmos_w, h: nmos_h, id: "nmos1")
  pmos(x: pmos_x, y: pmos_y, w: pmos_w, h: pmos_h, id: "pmos1")
  gnd((gnd_x, gnd_y), id: "gnd1")
  vsource(x: vdd_x, y: vdd_y, w: 1, h: 1, id: "vdd")
   isource(x: vdd_x+4, y: vdd_y, w: 1, h: 1, id: "vdd")// Add VDD source
  let nmos1_src_coord = coordinate.resolve("nmos1-port-source")
  let nmos1_drain_coord = coordinate.resolve("nmos1-port-drain")
  let nmos1_bulk_coord = coordinate.resolve("nmos1-port-bulk")
  let pmos1_drain_coord = coordinate.resolve("pmos1-port-drain")
  let pmos1_src_coord = coordinate.resolve("pmos1-port-source")
  let pmos1_bulk_coord = coordinate.resolve("pmos1-port-bulk")
  let gnd1_conn_coord = coordinate.resolve("gnd1.conn")
  let vdd_n_coord = coordinate.resolve("vdd-port-n")
let nmos_corner_coord = (horizontal: "nmos1-port-bulk", vertical: "nmos1-port-source")
  // Give this coordinate a name using draw.anchor so we can reference it
  draw.anchor("nmos1-corner-bs", nmos_corner_coord)
  
  wire.wire("w_nmos_gnd", ("nmos1-port-source", "gnd1.conn"))
  //wire.wire("w_nmos_bulk", ("nmos1-port-bulk", "nmos1-port-source")) too direct
  wire.wire("w_nmos_bulk_1", ("nmos1-port-bulk", "nmos1-corner-bs")) // Bulk to Corner
  wire.wire("w_nmos_bulk_2", ("nmos1-corner-bs", "nmos1-port-source")) // Corner to Source

  
})
I added more circuit stuff I'd like help by adding rotations ![image.png](/attachments/ca445f96-7f77-4957-886b-11e0133f00b2) ``` #import "@preview/circuiteria:0.2.0": circuit, element, util, wire, gates.gate // Removed gates.gate import #import "@preview/cetz:0.3.4": draw, canvas, coordinate // Helper function for NMOS/PMOS shapes #let sig(m)={ if m == 0 { 1 } else { calc.abs(m)/m } // Avoid division by zero if width/height is 0 } // --- NMOS Shape Definition --- // Defines anchors: drain, source, gate, bulk, north, south, east, west, center #let nmos_shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl // bottom left let (width, height) = (tr.at(0) - x, tr.at(1) - y) // Define points relative to bl=(x,y) let t = (x + width/2, y + height) let ctll= (x + width/4-0.1*sig(width), y + 3*height/4) let ct = (x + width/2, y + 3*height/4) let ctl = (x + width/4, y + 3*height/4) let cll = (x + width/4-0.1*sig(width), y + height/2) let l = (x, y + height/2) let cl = (x + width/4, y + height/2) let r = (x + width, y + height/2) let cbll = (x + width/4-0.1*sig(width), y + height/4) let cbl = (x + width/4, y + height/4) let cb = (x + width/2, y + height/4) let cb2 = (x + width/2+0.1*sig(width), y + height/4) // Point near center bottom let b = (x + width/2, y) let f = draw.group(name: id, { // Draw the transistor shape lines draw.line(t, ct) draw.line(ct, ctl, cbl, cb2, mark: (end: ">")) draw.line(cb, b) draw.line(l, cll) draw.line(ctll, cbll) draw.line(cl, r) // Define LOGICAL anchors for port connections draw.anchor("drain", t) draw.anchor("source", b) draw.anchor("gate", l) draw.anchor("bulk", r) // Define standard ELEMENT anchors for relative placement draw.anchor("north", t) draw.anchor("south", b) draw.anchor("west", l) draw.anchor("east", r) draw.anchor("center", (x + width/2, y + height/2)) }) return (f, tl, tr, br, bl) } // --- NMOS Element Function (using element.elmt) --- #let nmos( x: none, y: none, w: none, h: none, fill: none, stroke: black + 1pt, id: "", debug: (ports: false) // Removed unused inputs/inverted args ) = { element.elmt( // Use element.elmt draw-shape: nmos_shape, x: x, y: y, w: w, h: h, ports: ( // Explicitly define ports linking to anchors in nmos_shape north: ((id: "drain"),), // Port "nmos1-port-drain" at anchor "drain" south: ((id: "source"),),// Port "nmos1-port-source" at anchor "source" west: ((id: "gate"),), // Port "nmos1-port-gate" at anchor "gate" east: ((id: "bulk"),), // Port "nmos1-port-bulk" at anchor "bulk" ), fill: fill, stroke: stroke, id: id, debug: debug ) } #let impedance_eu_shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl let (width, height) = (tr.at(0) - x, tr.at(1) - y) let center_y = y + height / 2 // Define proportions (similar to resistor) let lead_ratio = 0.15 // Fraction of total width for each lead let lead_len = width * lead_ratio let box_width = width * (1.0 - 2.0 * lead_ratio) // Width of the rectangle // Calculate points let term1 = (x, center_y) // Left terminal let box_left = x + lead_len // Left edge of rectangle let box_right = x + width - lead_len // Right edge of rectangle let term2 = (x + width, center_y) // Right terminal // Rectangle corner points let box_bl = (box_left, y) let box_tr = (box_right, y + height) let f = draw.group(name: id, { // Leads draw.line(term1, (box_left, center_y), stroke: stroke) draw.line((box_right, center_y), term2, stroke: stroke) // Rectangular body draw.rect(box_bl, box_tr, fill: fill, stroke: stroke) // Anchors for ports draw.anchor("t1", term1) // Terminal 1 (left) draw.anchor("t2", term2) // Terminal 2 (right) // Standard anchors (bounding box) draw.anchor("west", term1) draw.anchor("east", term2) draw.anchor("center", (x + width/2, center_y)) draw.anchor("north", (x + width/2, y + height)) // Top edge of element box draw.anchor("south", (x + width/2, y)) // Bottom edge of element box }) return (f, tl, tr, br, bl) } // --- European Impedance Element Function --- #let impedance_eu( x: none, y: none, w: 1, // Default width (same as resistor) h: 0.3, // Default height (same as resistor) fill: none, // Default to no fill (just outline) stroke: black + 1pt, id: "", debug: (ports: false) ) = { element.elmt( draw-shape: impedance_eu_shape, x: x, y: y, w: w, h: h, ports: ( west: ((id: "t1"),), // Port t1 = west anchor east: ((id: "t2"),), // Port t2 = east anchor ), fill: fill, stroke: stroke, id: id, debug: debug ) } // --- PMOS Shape Definition --- [CORRECTED ANCHORS] // Defines anchors: source (top), drain (bottom), gate, bulk #let pmos_shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl // bottom left let (width, height) = (tr.at(0) - x, tr.at(1) - y) // Define points relative to bl=(x,y) let t = (x + width/2, y + height) // Top center (physical top point) let ctll= (x + width/4-0.1*sig(width), y + 3*height/4) let ct = (x + width/2, y + 3*height/4) let ctl = (x + width/4, y + 3*height/4) let cll = (x + width/4-0.1*sig(width), y + height/2) let l = (x, y + height/2) // Left center (Gate) let cl = (x + width/4, y + height/2) let r = (x + width, y + height/2) // Right center (Bulk) let cbll = (x + width/4-0.1*sig(width), y + height/4) let cbl = (x + width/4, y + height/4) let cb = (x + width/2, y + height/4) let b = (x + width/2, y) // Bottom center (physical bottom point) let circle_center = (x + width/4 - 0.1*sig(width) - 0.15*sig(width), y + height/2) let circle_radius = 0.05 * calc.min(width, height) let f = draw.group(name: id, { // Draw the transistor shape lines draw.line(t, ct) // Top lead (Source) to top H //draw.line(ct, ctl, cbl, cb, mark: (end: "<")) // WRONG draw.line(cb,cbl,ctl,ct, mark: (end: "<")) // CORRECT draw.line(cb, b) // Bottom lead (Drain) from bottom H draw.line((rel: (+circle_radius*2, 0), to: l), cll) // Gate lead adjusted for circle draw.line(ctll, cbll) // Gate vertical bar draw.line(cl, r) // Bulk lead connection line draw.circle(circle_center, radius: circle_radius, stroke: stroke, fill: white); // PMOS circle // --- CORRECTED LOGICAL ANCHORS --- draw.anchor("source", t) // Logical SOURCE is the TOP terminal draw.anchor("drain", b) // Logical DRAIN is the BOTTOM terminal draw.anchor("gate", l) // Logical GATE is the LEFT terminal draw.anchor("bulk", r) // Logical BULK is the RIGHT terminal // --- Standard ELEMENT anchors for relative placement --- draw.anchor("north", t) // Topmost physical point draw.anchor("south", b) // Bottommost physical point draw.anchor("west", l) draw.anchor("east", r) draw.anchor("center", (x + width/2, y + height/2)) }) return (f, tl, tr, br, bl) } // --- PMOS Element Function (using element.elmt) --- [CORRECTED PORT MAPPING] #let pmos( x: none, y: none, w: 1.0, h: 1.0, fill: none, stroke: black + 1pt, id: "", debug: (ports: false) ) = { element.elmt( draw-shape: pmos_shape, x: x, y: y, w: w, h: h, ports: ( // Link logical ports to physical shape anchors (north/south/west/east) // The 'north' anchor in the shape is the physical top, which we defined as logical 'source' north: ((id: "source"),), // Element's North port corresponds to logical Source // The 'south' anchor in the shape is the physical bottom, which we defined as logical 'drain' south: ((id: "drain"),), // Element's South port corresponds to logical Drain west: ((id: "gate"),), // Element's West port corresponds to logical Gate east: ((id: "bulk"),), // Element's East port corresponds to logical Bulk ), fill: fill, stroke: stroke, id: id, debug: debug ) } // --- GND Symbol Function --- // Defines anchor "conn" and "north" #let gnd(pos, length: 0.5, spacing: 0.15, stroke: black + 1pt, id: "gnd") = { draw.group(name: id, { let p1 = pos // Top connection point let p2 = (rel: (0, -spacing), to: p1) let p3 = (rel: (0, -spacing), to: p2) let p4 = (rel: (0, -spacing), to: p3) let len1 = length let len2 = length * 0.7 let len3 = length * 0.4 draw.line(p1, p2, stroke: stroke) // Stem draw.line((rel: (-len1/2, 0), to: p2), (rel: (len1/2, 0), to: p2), stroke: stroke) // Bar 1 draw.line((rel: (-len2/2, 0), to: p3), (rel: (len2/2, 0), to: p3), stroke: stroke) // Bar 2 draw.line((rel: (-len3/2, 0), to: p4), (rel: (len3/2, 0), to: p4), stroke: stroke) // Bar 3 draw.anchor("conn", p1) // Anchor for wiring draw.anchor("north", p1) // Standard anchor }) } // --- Vsource Shape Definition --- // Independent Voltage Source Symbol #let vsource_shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl let (width, height) = (tr.at(0) - x, tr.at(1) - y) let center_x = x + width / 2 let center_y = y + height / 2 let radius = calc.min(width, height) / 2 * 0.8 // Slightly smaller radius let top_term = (center_x, y + height) let bot_term = (center_x, y) let top_circle = (center_x, center_y + radius) let bot_circle = (center_x, center_y - radius) let plus_pos = (center_x, center_y + radius * 0.5) let minus_pos = (center_x, center_y - radius * 0.5) let f = draw.group(name: id, { // Circle draw.circle((center_x, center_y), radius: radius, stroke: stroke, fill: fill) // Terminals lines draw.line(top_term, top_circle, stroke: stroke) draw.line(bot_circle, bot_term, stroke: stroke) // Plus sign draw.line((rel: (-radius*0.2, 0), to: plus_pos), (rel: (radius*0.2, 0), to: plus_pos), stroke: stroke) draw.line((rel: (0, -radius*0.2), to: plus_pos), (rel: (0, radius*0.2), to: plus_pos), stroke: stroke) // Minus sign draw.line((rel: (-radius*0.2, 0), to: minus_pos), (rel: (radius*0.2, 0), to: minus_pos), stroke: stroke) // Anchors for ports draw.anchor("p", top_term) // Positive terminal draw.anchor("n", bot_term) // Negative terminal // Standard anchors draw.anchor("north", top_term) draw.anchor("south", bot_term) draw.anchor("center", (center_x, center_y)) draw.anchor("west", (x, center_y)) draw.anchor("east", (x + width, center_y)) }) return (f, tl, tr, br, bl) } // --- Vsource Element Function --- #let vsource(x: none, y: none, w: 1, h: 1, fill: white, stroke: black + 1pt, id: "", debug: (ports: false)) = { element.elmt( draw-shape: vsource_shape, x: x, y: y, w: w, h: h, ports: (north: ((id: "p"),), south: ((id: "n"),),), // Port p = north, Port n = south fill: fill, stroke: stroke, id: id, debug: debug ) } // --- Isource Shape Definition --- // Independent Current Source Symbol #let isource_shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl let (width, height) = (tr.at(0) - x, tr.at(1) - y) let center_x = x + width / 2 let center_y = y + height / 2 let radius = calc.min(width, height) / 2 * 0.8 // Slightly smaller radius let top_term = (center_x, y + height) let bot_term = (center_x, y) let top_circle = (center_x, center_y + radius) let bot_circle = (center_x, center_y - radius) // Arrow points (pointing up) let arrow_tip = (center_x, center_y + radius * 0.5) let arrow_base = (center_x, center_y - radius * 0.5) let arrow_l = (center_x - radius * 0.25, center_y + radius * 0.1) let arrow_r = (center_x + radius * 0.25, center_y + radius * 0.1) let f = draw.group(name: id, { // Circle draw.circle((center_x, center_y), radius: radius, stroke: stroke, fill: fill) // Terminals lines draw.line(top_term, top_circle, stroke: stroke) draw.line(bot_circle, bot_term, stroke: stroke) // Arrow line draw.line(arrow_base, arrow_tip, stroke: stroke, mark: (end: ">")) // Anchors for ports (assuming current flows out the top) draw.anchor("out", top_term) draw.anchor("in", bot_term) // Standard anchors draw.anchor("north", top_term) draw.anchor("south", bot_term) draw.anchor("center", (center_x, center_y)) draw.anchor("west", (x, center_y)) draw.anchor("east", (x + width, center_y)) }) return (f, tl, tr, br, bl) } // --- Isource Element Function --- #let isource(x: none, y: none, w: 1, h: 1, fill: white, stroke: black + 1pt, id: "", debug: (ports: false)) = { element.elmt( draw-shape: isource_shape, x: x, y: y, w: w, h: h, ports: (north: ((id: "out"),), south: ((id: "in"),),), // Port out = north, Port in = south fill: fill, stroke: stroke, id: id, debug: debug ) } // --- Capacitor Shape Definition --- // Parallel plates #let cap_shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl let (width, height) = (tr.at(0) - x, tr.at(1) - y) let center_y = y + height / 2 let plate_gap = width * 0.2 let lead_len = (width - plate_gap) / 2 let plate_height = height * 0.8 let p1_x = x + lead_len let p2_x = x + lead_len + plate_gap let term1 = (x, center_y) let term2 = (x + width, center_y) let p1_start = (p1_x, center_y) let p2_start = (p2_x, center_y) let p1_top = (p1_x, center_y + plate_height / 2) let p1_bot = (p1_x, center_y - plate_height / 2) let p2_top = (p2_x, center_y + plate_height / 2) let p2_bot = (p2_x, center_y - plate_height / 2) let f = draw.group(name: id, { // Leads draw.line(term1, p1_start, stroke: stroke) draw.line(p2_start, term2, stroke: stroke) // Plates draw.line(p1_top, p1_bot, stroke: stroke) draw.line(p2_top, p2_bot, stroke: stroke) // Anchors for ports draw.anchor("t1", term1) // Terminal 1 (left) draw.anchor("t2", term2) // Terminal 2 (right) // Standard anchors draw.anchor("west", term1) draw.anchor("east", term2) draw.anchor("center", (x + width/2, center_y)) draw.anchor("north", (x + width/2, y + height)) draw.anchor("south", (x + width/2, y)) }) return (f, tl, tr, br, bl) } // --- Capacitor Element Function --- #let cap(x: none, y: none, w: 1, h: 1, fill: none, stroke: black + 1pt, id: "", debug: (ports: false)) = { element.elmt( draw-shape: cap_shape, x: x, y: y, w: w, h: h, ports: (west: ((id: "t1"),), east: ((id: "t2"),),), // Port t1 = west, Port t2 = east fill: fill, stroke: stroke, id: id, debug: debug ) } // --- Resistor Shape Definition --- // Zig-zag resistor symbol #let res_shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl let (width, height) = (tr.at(0) - x, tr.at(1) - y) let center_y = y + height / 2 // Define proportions let lead_ratio = 0.15 // Fraction of total width for each lead let lead_len = width * lead_ratio let zigzag_width = width * (1.0 - 2.0 * lead_ratio) // Width available for zig-zags let num_segments = 7 let dx = zigzag_width / num_segments // Horizontal distance covered by each segment let zig_height = height * 0.4 // Amplitude (half of total vertical zig-zag extent) // Calculate points let term1 = (x, center_y) let p_start = (x + lead_len, center_y) // Start of zig-zag // Generate zig-zag points dynamically let points = (p_start,) // Start with the first point for i in range(num_segments) { let current_x = p_start.at(0) + dx * (i + 1) // Alternate adding and subtracting zig_height let current_y = center_y + zig_height * calc.pow(-1,i) // + for i=0, - for i=1, + for i=2... points.push((current_x, current_y)) } // Ensure last point is on the center line if num_segments is even let p_end = (p_start.at(0) + zigzag_width, center_y) points.at(num_segments) = p_end // Correct last point to be on center line let term2 = (x + width, center_y) // End terminal let f = draw.group(name: id, { // Leads draw.line(term1, p_start, stroke: stroke) draw.line(p_end, term2, stroke: stroke) // Zig-zag body using the calculated points draw.line(..points, stroke: stroke) // Spread the points array into line arguments // Anchors for ports draw.anchor("t1", term1) // Terminal 1 (left) draw.anchor("t2", term2) // Terminal 2 (right) // Standard anchors (bounding box) draw.anchor("west", term1) draw.anchor("east", term2) draw.anchor("center", (x + width/2, center_y)) draw.anchor("north", (x + width/2, center_y + zig_height)) // Top extent draw.anchor("south", (x + width/2, center_y - zig_height)) }) return (f, tl, tr, br, bl) } // --- Resistor Element Function --- #let res(x: none, y: none, w: 1, h: 0.4, fill: none, stroke: black + 1pt, id: "", debug: (ports: false)) = { element.elmt( draw-shape: res_shape, x: x, y: y, w: w, h: h, ports: (west: ((id: "t1"),), east: ((id: "t2"),),), // Port t1 = west, Port t2 = east fill: fill, stroke: stroke, id: id, debug: debug ) } #let ind_shape(id, tl, tr, br, bl, fill, stroke) = { let (x, y) = bl let (width, height) = (tr.at(0) - x, tr.at(1) - y) let center_y = y + height / 2 // Define proportions let lead_ratio = 0.1 // Fraction of total width for each lead let lead_len = width * lead_ratio let coil_width = width * (1.0 - 2.0 * lead_ratio) // Width available for coil let num_loops = 4 // Number of semi-circular loops (standard is 3 or 4) let loop_width = coil_width / num_loops // Horizontal width of each loop let loop_radius = loop_width / 2 // Radius of the semi-circles // Calculate terminal and coil start/end points let term1 = (x, center_y) let p_start2 = (x +0.13+lead_len, center_y) let p_start = (x +lead_len, center_y) // Start of coil let p_end = (x + width , center_y) // End of coil let term2 = (width+x+lead_len+0.13, center_y) // End terminal let f = draw.group(name: id, { // Draw Leads draw.line(term1, p_start2, stroke: stroke) draw.line(p_end, term2, stroke: stroke) // Draw Coil Loops using arcs (Corrected Syntax) for i in range(num_loops) { let loop_center_x = p_start.at(0) + loop_width * i + loop_radius // Correct usage: arc(center, radius: r, start: angle, delta: angle) // We start at 180deg (left) and sweep +180deg (counter-clockwise) to 0deg (right) draw.arc( (loop_center_x, center_y), // Center position is the first argument radius: loop_radius, start: 180deg, delta: 180deg, // Positive delta for counter-clockwise sweep over the top stroke: stroke ) } // Anchors for ports draw.anchor("t1", term1) // Terminal 1 (left) draw.anchor("t2", term2) // Terminal 2 (right) // Standard anchors draw.anchor("west", term1) draw.anchor("east", term2) draw.anchor("center", (x + width/2, center_y)) // Use the actual top of the arc for North anchor draw.anchor("north", (x + width/2, center_y + loop_radius)) // Use the bounding box bottom for South anchor // If height is small, center_y - loop_radius might be below y. // Using 'y' ensures it's the element's defined bottom. draw.anchor("south", (x + width/2, y)) }) return (f, tl, tr, br, bl) } // --- Inductor Element Function --- // (This function remains the same, it just calls the corrected shape) #let ind( x: none, y: none, w: 1.2, // Inductors often wider than high h: 0.5, fill: none, stroke: black + 1pt, id: "", debug: (ports: false) ) = { element.elmt( draw-shape: ind_shape, x: x, y: y, w: w, h: h, ports: ( west: ((id: "t1"),), // Port t1 = west anchor east: ((id: "t2"),), // Port t2 = east anchor ), fill: fill, stroke: stroke, id: id, debug: debug ) } #circuit({ impedance_eu(x: 0, y: -2, id: "Z1") // Place a capacitor cap(x: 0, y: -4, id: "C1") ind(x: 0, y: -8, id: "R2") res(x: 0, y: 0, id: "R1") // === Placement Phase === let nmos_x = 3; let nmos_y = -3; let nmos_w = 1.5; let nmos_h = 1.5 let pmos_x = nmos_x; let pmos_y = nmos_y + nmos_h + 2 let pmos_w = nmos_w; let pmos_h = nmos_h let gnd_x = nmos_x; let gnd_y = nmos_y - 1 let vdd_x = pmos_x; let vdd_y = pmos_y + pmos_h + 1 // Place elements nmos(x: nmos_x, y: nmos_y, w: nmos_w, h: nmos_h, id: "nmos1") pmos(x: pmos_x, y: pmos_y, w: pmos_w, h: pmos_h, id: "pmos1") gnd((gnd_x, gnd_y), id: "gnd1") vsource(x: vdd_x, y: vdd_y, w: 1, h: 1, id: "vdd") isource(x: vdd_x+4, y: vdd_y, w: 1, h: 1, id: "vdd")// Add VDD source let nmos1_src_coord = coordinate.resolve("nmos1-port-source") let nmos1_drain_coord = coordinate.resolve("nmos1-port-drain") let nmos1_bulk_coord = coordinate.resolve("nmos1-port-bulk") let pmos1_drain_coord = coordinate.resolve("pmos1-port-drain") let pmos1_src_coord = coordinate.resolve("pmos1-port-source") let pmos1_bulk_coord = coordinate.resolve("pmos1-port-bulk") let gnd1_conn_coord = coordinate.resolve("gnd1.conn") let vdd_n_coord = coordinate.resolve("vdd-port-n") let nmos_corner_coord = (horizontal: "nmos1-port-bulk", vertical: "nmos1-port-source") // Give this coordinate a name using draw.anchor so we can reference it draw.anchor("nmos1-corner-bs", nmos_corner_coord) wire.wire("w_nmos_gnd", ("nmos1-port-source", "gnd1.conn")) //wire.wire("w_nmos_bulk", ("nmos1-port-bulk", "nmos1-port-source")) too direct wire.wire("w_nmos_bulk_1", ("nmos1-port-bulk", "nmos1-corner-bs")) // Bulk to Corner wire.wire("w_nmos_bulk_2", ("nmos1-corner-bs", "nmos1-port-source")) // Corner to Source }) ```
Owner

Thank you very much for your interest ! It looks very cool !
I had started working on some basic elements for resistors and capacitors but I haven't taken the time to finish it
Could you make this into a pull request ? I'll try to take a closer look ASAP

Thank you very much for your interest ! It looks very cool ! I had started working on some basic elements for resistors and capacitors but I haven't taken the time to finish it Could you make this into a pull request ? I'll try to take a closer look ASAP
HEL added the
feature request
label 2025-03-30 22:37:53 +00:00
HEL added
new component
and removed
feature request
labels 2025-03-30 22:39:41 +00:00
Author

Thank you very much for your interest ! It looks very cool !
I had started working on some basic elements for resistors and capacitors but I haven't taken the time to finish it
Could you make this into a pull request ? I'll try to take a closer look ASAP

I would do a PR but I need assistance, where did you put the resistors and capacitors, quick question as well, how are you supposed to caption your elements?

> Thank you very much for your interest ! It looks very cool ! > I had started working on some basic elements for resistors and capacitors but I haven't taken the time to finish it > Could you make this into a pull request ? I'll try to take a closer look ASAP I would do a PR but I need assistance, where did you put the resistors and capacitors, quick question as well, how are you supposed to caption your elements?
Owner

You can take a look at the comp/electrical branch where I've added resistors and capacitors

how are you supposed to caption your elements?

What do you mean by caption ? Do you mean like the name displayed in blocks or extenders ? If so, that would be here :

if (name != none) {

You can take a look at the [comp/electrical](https://git.kb28.ch/HEL/circuiteria/src/branch/comp/electrical/) branch where I've added resistors and capacitors > how are you supposed to caption your elements? What do you mean by caption ? Do you mean like the name displayed in blocks or extenders ? If so, that would be here : https://git.kb28.ch/HEL/circuiteria/src/commit/2bb7e3b5a98577297a53d4aefb8732e3dd761f4a/src/elements/element.typ#L127
Sign in to join this conversation.
No description provided.