diff options
Diffstat (limited to 'main.lua')
-rw-r--r-- | main.lua | 190 |
1 files changed, 91 insertions, 99 deletions
@@ -1,131 +1,123 @@ +local class = require 'class' +local hsluv = require 'hsluv' +local catenary = require 'catenary' + +local tau = 2*math.pi +local ZOOM = 200 local G = love.graphics -local function atanh(x) - return (1/2) * math.log((1+x)/(1-x)) +local function write_at(text,x,y) + G.push() + G.translate(x,y) + G.scale(1/ZOOM) + G.print(text,0,0) + G.pop() end -local function solve_for_A(r) - local A - if r < 3 then - A = math.sqrt(6 * (r-1)) - else - A = math.log(2*r) + math.log(math.log(2*r)) - end - for i=1,5 do - A = A - (math.sinh(A) - r*A)/(math.cosh(A)-r) - end - return A +local Port = class() +Port.R = 0.1 +function Port.make(cls, x,y, num) + return setmetatable({x=x,y=y,n=num,wires={}},cls) end - -local function plot(f,x0,xn) - local n = 30 - x0 = x0 or G.inverseTransformPoint(0,0) - xn = xn or G.inverseTransformPoint(G.getDimensions(),0) - - if xn < x0 then - xn,x0 = x0,xn - end - - local h = (xn-x0)/n - local ps = {} - for i=0,n do - local x = x0 + i*h - local y = f(x) - table.insert(ps,x) - table.insert(ps,y) +function Port.draw(self, istate) + local c = {0,0,0} + if istate == 'hover' then + c[1] = 1 + elseif istate == 'selected' then + c[2] = 1 end - return ps + love.graphics.setColor(c) + G.circle('line',self.x,self.y,self.R) + write_at(self.n, self.x, self.y) +end +function Port.contains(self, px,py) + local d = math.sqrt((self.x - px)^2 + (self.y - py)^2) + return d <= self.R end -local function catenary0(x1,y1,x2,y2, L) - -- https://math.stackexchange.com/a/3557768 - y1 = -y1 - y2 = -y2 - local dx = x2-x1 - local dy = y2-y1 - local mx = (x1+x2)/2 - local my = (y1+y2)/2 - - local D = math.sqrt(dx^2+dy^2) - L = L or D+(1/(D+0.3)) - - local r = math.sqrt(L^2 - dy^2)/dx - local A = solve_for_A(r) +local ports = {} +local n = 10 +for i = 1,n do + local theta = tau * i/n + table.insert(ports, Port:make(math.cos(theta), math.sin(theta), i)) +end +ports[3].wires = {ports[6]} +ports[5].wires = {ports[7],ports[2]} - local a = dx/(2*A) - local b = mx - a*atanh(dy/L) - local c = my - L/(2*math.tanh(A)) - return function(x) return -(a * math.cosh((x-b)/a) + c) end +local function wire_color(n) + local phi = (1+math.sqrt(5))/2 + local h = (360*phi*n)%360 + return hsluv.hsluv_to_rgb({h, 80, 60}) end +local state = 'normal' +local selected = nil -local function catenary(x1,y1, x2,y2, L) - local D = math.sqrt((x2-x1)^2 + (y2-y1)^2) - L = L or D+(1/(D+0.3)) - - if x2 < x1 then - x1,x2 = x2,x1 - y1,y2 = y2,y1 +local function hovering_port(mx,my) + for i,p in ipairs(ports) do + if p:contains(mx,my) then + return p + end end - - local f = catenary0(x1,y1,x2,y2,L) - return plot(f, x1,x2) + return nil end -return { - catenary = catenary -} - - ---[[ -local Ps = {{-1,1}, {1,1}} - -function love.update(dt) - for b = 1,2 do - if love.mouse.isDown(b) then - Ps[b] = {G.inverseTransformPoint(love.mouse.getPosition())} +function love.mousepressed(x,y,b) + if b == 2 then + state = 'normal' + selected = nil + return + end + local mx,my = G.inverseTransformPoint(x,y) + local p = hovering_port(mx,my) + if p then + if state == 'normal' then + state = 'joining' + selected = p.n + elseif state == 'joining' then + table.insert(ports[selected].wires, p) + state = 'normal' + selected = nil end end end + +local L = 2 +function love.wheelmoved(x,y) + L = L + (y/15) +end + function love.draw() local W,H = G.getDimensions() G.clear(1,1,1) G.setColor(0,0,0) G.origin() - local dx = Ps[1][1] - Ps[2][1] - local dy = Ps[1][2] - Ps[2][2] - local D = math.sqrt(dx^2+dy^2) - local L = D+(1/(D+0.3)) - -- local L = D+1 - G.print(("%.2f\n%.2f\n%.2f"):format(L,D,L-D),10,10) + G.print(L,10,10) G.setLineWidth(0.01) G.translate(W/2,H/2) - G.scale(50) - - G.setColor(0.8,0.8,0.8) - for i=-10,10 do - G.line(-10,i,10,i) - G.line(i,-10,i,10) + G.scale(ZOOM) + + local mx,my = G.inverseTransformPoint(love.mouse.getPosition()) + local wn = 0 + for i,p in ipairs(ports) do + local istate = 'normal' + if p:contains(mx,my) then istate = 'hover' end + if state ~= 'normal' and selected == i then istate = 'selected' end + p:draw(istate) + for _,q in ipairs(p.wires) do + G.setColor(wire_color(wn)) + wn = wn + 1 + G.line(catenary.catenary(p.x,p.y,q.x,q.y)) + end end - G.circle('line',0,0,1) - - -- G.setColor(0,0,0) - -- -- plot(function(x) return x^2 end) - -- plot(math.tanh) - -- G.setColor(0,1,0) - -- plot(atanh) - - G.setColor(0,0,0) - G.line(catenary(Ps[1][1],Ps[1][2], Ps[2][1], Ps[2][2])) - - G.setColor(1,0,0) - G.circle('fill',Ps[1][1],Ps[1][2],0.05) - G.setColor(0,0,1) - G.circle('fill',Ps[2][1],Ps[2][2],0.05) + if state == 'joining' then + G.setColor(wire_color(wn)) + local p = ports[selected] + G.line(catenary.catenary(p.x,p.y,mx,my)) + end end ---]] |