Learning custom shapes with Fletcher -- any suggestions?

I’m messing around with Fletcher and custom shapes. I wanted a circular node with an upper and a lower section; this is what I ended up with. Suggestions welcome; I’m not that familiar with typst or cetz so I’m still muddling around in the dark to figure out how to write code that is idiomatic.

#import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge, draw

#let semicircs(node, extrude, uppertext: none, lowertext: none) = {
  let (w,h) = node.size
  let r = 0.5 * calc.max(w,h)
  let q = 0.4
  return draw.group({
    draw.arc((r,0),start: 0deg, stop:180deg, radius: r, close:true, fill:none)
    draw.arc((r,0),start: 0deg, stop:-180deg, radius: r, close:true)
    draw.line((-r,0),(r,0))
    if (uppertext != none) {
      draw.content((0,q*r), uppertext)
    }
    if (lowertext != none) {
      draw.content((0,-q*r), lowertext)
    }
  })
}

#{
  diagram(
    edge-stroke: 0.3mm,
    mark-scale: 80%, 
    node((0,0), name: <p0>, width:7em, shape: semicircs.with(uppertext:[YO], lowertext:[THERE]), stroke: 1pt+red, fill: red),
    node((2,1.5), name: <p1>, width:5em, shape: semicircs.with(uppertext: text(18pt)[$A$], lowertext: text(18pt,white)[$B$]), stroke: 1pt+green, fill: green),
    node((0,3), name: <p2>, width:4em, shape: semicircs.with(uppertext: $3x$, lowertext: $1+x^2$), stroke: 1pt, fill:green.lighten(75%)),
    edge(<p1>, "-|>", <p0>),
    edge(<p1>, "-|>", <p2>),
    edge(<p0>, "<|-|>", <p2>)
  )
}

In particular, how do I incorporate extrude properly?

This works great! This is pretty much just as I would implement it.

To support node extrusion, which enables 1) proper drawing of arrows with node outset and 2) double node stroke effects, you just need to decide how to draw the shape extruded by the amount given. In this case, you probably just want to make the outer circle larger, but keep everything else the same. That’s what I did here:

#import "@preview/fletcher:0.5.8" as fletcher: diagram, node, edge, cetz

#let semicircs(node, extrude, t: none, b: none) = {
  import cetz.draw: *
  let (w,h) = node.size
  let r = 0.5 * calc.max(w,h)
  let q = 0.4
  group({
    circle((0,0), radius: r + extrude, fill: none)
    arc((0,0), start: 0deg, stop: -180deg, radius: r, anchor: "origin")
    line((-r,0),(r,0))
    content((0,q*r), t)
    content((0,-q*r), b)
  })
}

#diagram(
  edge-stroke: 0.3mm,
  mark-scale: 80%, 
  node-outset: 5pt,
  node((0,0), name: <p0>, width:7em, shape: semicircs.with(t:[YO], b:[THERE]), stroke: 1pt+red, fill: red),
  node((2,1.5), name: <p1>, width:5em, shape: semicircs.with(t: text(18pt)[$A$], b: text(18pt,white)[$B$]), stroke: 1pt+green, fill: green),
  node((0,3), name: <p2>, width:4em, shape: semicircs.with(t: $3x$, b: $1+x^2$), stroke: 1pt, fill:green.lighten(75%), extrude: (0, 2)),
  edge(<p1>, "-|>", <p0>),
  edge(<p1>, "-|>", <p2>),
  edge(<p0>, "<|-|>", <p2>)
)

4 Likes