cetz icon indicating copy to clipboard operation
cetz copied to clipboard

Function for scaling children to a fixed bounding box

Open johannes-wolf opened this issue 1 year ago • 0 comments

It would be nice to have something like set-viewport, which scales its children to a fixed AABB by measuring their bounding box and scaling their coordinates afterward (what plot.plot des, but for normal elements).

CeTZ 0.1.2 POC:

#let scale-up(body, size: (10, 10, 1)) = {
  ((
    children: body,
    finalize-children: (ctx, children) => {
      let low = none
      let high = none
      for c in children {
        for b in c.bounds {
          if low == none {
            low = b
          } else {
            low = (
              calc.min(low.at(0), b.at(0)),
              calc.min(low.at(1), b.at(1)),
              calc.min(low.at(1), b.at(1)), 1)
          }
          if high == none {
            high = b
          } else {
            high = (
              calc.max(high.at(0), b.at(0)),
              calc.max(high.at(1), b.at(1)),
              calc.max(high.at(1), b.at(1)), 1)
          }
        }
      }

      let m = cetz.matrix.transform-scale((x: size.at(0) / (high.at(0) - low.at(0)),
                                           y: -size.at(1) / (high.at(1) - low.at(1))))
      children = children.map(c => {
        c.segments = c.segments.map(s => {
          for i in range(1, s.len()) {
            s.at(i) = cetz.matrix.mul-vec(m, cetz.vector.as-vec(s.at(i), init: (0,0,0,1)))
          }
          return s
        })
        return c
      })

      return children
    }
  ),)
}

#cetz.canvas({
  import cetz.draw: *
  import cetz.plot

  let sx = 13
  let sy = 10

  rect((0,0), (sx, sy), stroke: red)
  scale-up({
    circle((1,-1))
    catmull((0,0), (2, -2), (4, 0))
  }, size: (sx, sy, 1))
})

johannes-wolf avatar Oct 29 '23 18:10 johannes-wolf