cetz-package / cetz

CeTZ: ein Typst Zeichenpaket - A library for drawing stuff with Typst.
https://cetz-package.github.io
GNU Lesser General Public License v3.0
825 stars 35 forks source link

Support for rounded rect #180

Closed Zheoni closed 9 months ago

Zheoni commented 1 year ago

Self explanatory title. I think rect could benefit from a radius parameter to make the corners round.

MultisampledNight commented 9 months ago

For what it's worth, this is the polyfill I'm using for now, which requires from and to to be resolved though. One can specify bendness: none to use an actual arc instead of the squircle-ish bezier curve. It can't deal with the size being less than radius, and from being larger than to.

#import cetz.draw: *

#let vec-add(a, b) = {
  a.zip(b).map(combi => combi.at(0) + combi.at(1))
}
#let vec-sub(a, b) = {
  a.zip(b).map(combi => combi.at(0) - combi.at(1))
}
#let vec-div-scalar(a, b) = {
  a.map(a => a / b)
}

#let rounded-rect(from, to, bendness: 0, radius: 1) = group({
  let size = vec-div-scalar(vec-sub(to, from), 2)
  set-origin(vec-add(from, size))

  let outline = merge-path({
    for _ in range(4) {
      let x-max = vec-sub(size, (radius, 0))
      let y-max = vec-sub(size, (0, radius))

      line(
        (horizontal: (0, 0), vertical: size),
        x-max,
      )
      if bendness == none {
        // round it
        arc(x-max, start: 90deg, stop: 0deg)
      } else {
        // squircle it
        bezier(
          x-max,
          y-max,
          vec-add(size, (bendness, bendness)),
        )
      }
      line(
        y-max,
        (vertical: (0, 0), horizontal: size)
      )

      rotate(90deg)
      size = (size.at(1), size.at(0))
    }
  })

  outline
})