Building an equation plotter


New version with just a couple of minor tweaks:

  • I wasn't calling car.mousemoved (akin to love.mousemoved). Now I am.
  • Fixed a crash due to UTF-8 in just the right place in the editor. This was something I missed in July 2022 and all my apps inherited. Now they're all fixed. Hopefully there's no more than 1 such bug remaining.

Today's program is a small equation plotter:

v = {x=-5, y=-5*Safe_height/Safe_width}
v.w, v.h = -2*v.x, -2*v.y
v.zoom = Safe_width/v.w
f,s = nil  -- ids of first and second touches
start, curr = {}, {}  -- coords of touches
initzoom = nil
initpos = nil -- for panning
function car.draw()
  color(0.5,0.5,0.5)
  line(0, vy(0), Safe_width, vy(0))
  line(vx(0), 0, vx(0), Safe_height)
  color(0,0,1)
  plot(sin)
  color(0,0.6,0)
  plot(function(x) return sin(2*x) end)
  color(0,0.8,1)
  plot(function(x) return 2*sin(x) end)
  color(0.8,0.6,0)
  plot(function(x) return x^2 end)
  color(0.5, 0.5, 0.5)
  for _,touch in ipairs(touches()) do
    if curr[touch] then
      circle('fill', curr[touch].x, curr[touch].y, 10)
    end
  end
end
function plot(f)
  for vx=0,Safe_width do
    circle('fill', vx, vy(f(sx(vx))), 1)
  end
end
function car.touchpressed(id, x,y, ...)
  if f == nil then
    f = id
    initpos = {x=v.x, y=v.y}
  else
    s = id
    initzoom = v.zoom
  end
  start[id] = {x=x, y=y}
  curr[id] = {x=x, y=y}
end
function car.touchreleased(id, x,y, ...)
  f,s = nil
  start, curr = {}, {}
  initzoom = nil
  initpos = nil
end
function car.touchmoved(id, x,y, ...)
  if start[id] then
    curr[id] = {x=x, y=y}
    if s then
      local oldzoom = v.zoom
      v.zoom = dist(curr[f], curr[s])/dist(start[f], start[s])*initzoom
      adjust_viewport(oldzoom, v.zoom)
    elseif f then
      v.x = initpos.x + iscale(start[f].x - x)
      v.y = initpos.y + iscale(start[f].y - y)
    end end end
function adjust_viewport(oldzoom, zoom)
  -- ensure centroid of fingers remains in view
  local c = centroid(curr[f], curr[s])
  v.x = v.x + c.x/oldzoom - c.x/zoom
  v.y = v.y + c.y/oldzoom - c.y/zoom
end
function centroid(a, b)
  return{x=(a.x+b.x)/2, y=(a.y+b.y)/2}
end
function vx(sx) return scale(sx-v.x) end
function vy(sy) return scale(sy-v.y) end
function scale(d) return d*v.zoom end
function sx(vx) return v.x + iscale(vx) end
function sy(vy) return v.y + iscale(vy) end
function iscale(d) return d/v.zoom end
function dist(p1, p2)
  return ((p2.x-p1.x)^2 + (p2.y-p1.y)^2) ^ 0.5
end

If you try pasting this program into Lua Carousel, remember to first run the abbreviations on one of the example screens. Or if you've deleted that screen, here are the abbreviations I used in this post:

g = love.graphics
line, circle = g.line, g.circle
color = g.setColor
sin = math.sin
touches = love.touch.getTouches

Files

carousel-be.love 113 kB
Dec 27, 2023
carousel-be-safe.love 113 kB
Dec 27, 2023

Get Lua Carousel

Leave a comment

Log in with itch.io to leave a comment.