This had some dead ends. I spent some time trying to use the parametric equation of a line. But the parameter is not comparable across two lines.
KDIC32VKQ4Z7UAWIJBTUNXZWKJIZ4FTGUN5TCILOLIC5LYWQZEOQC
B3ZC44KYSYCCNVPNA7UZL6XFCD27O37PNHZ2SS45Q6V6UXHDW5IAC
H3HB2MENN6YV4Y7MGS4FMHKUS4AOV2JHRJRSG27PDTMYHSD2GEAAC
R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC
FHLFZZ3SG5VGJX25JID6A6C5XLT6Q76RAJDQSYQSZTXQMSIUTCCAC
FBDRJ53NJ5BWDQGU2GWZ6NEYHKCCRD7RODMIG7QQZBRFUB4HR7OAC
7UWLGLA6FAO42YN6IBEFAKMTDUY26IJAQDBHGHHH55OK2SHUIZHAC
KI6LF2LF2LK6Q7SRWN3U4TJ25Y6BGJ2M3AU5FUTN6JIVA2MUBEXAC
M2JTUQQL2JBWHMN3JG6KO6NDHZ5X7ZW2RF7HVG4WVMS5TE6DYUPQC
JIBCE66ZTWM5WEHEHNKKTRWBJQSQWBDDWPMOJIJR5Q676OSHYCNAC
TBPJ5WSRM5IKQH7FTAVYTWWUBWW7G2CLT5M6FN7CMPLD6Y77YIWQC
VEVJJKOCDIODY35MQDZFZU7R77IIGIL7HWMEPZ6J5F2BJFGCP4RQC
ZQMQVMFWZIGWBRCB455IKHPTAOUYPLYCSC44NBPPET557RGVRX3AC
3GK7GC2WTTU4K76MD7DN6W4UPSFTYSEJMTGG4P7ADEHLH6K3P4IQC
7OUKVXJTWEJBYNBPB2SBXJ4ADFZ7OV4SJEG4K2A3J4D7FSJAJ52QC
distance_sq = function(x1,y1, x2,y2)
return (x2-x1)^2+(y2-y1)^2
end
x_at_y = function(startx,starty, endx,endy, y)
-- x at a given y on a line
-- Could be nil when the line is parallel to the x axis.
if starty == endy then
return
end
return (endx-startx)/(endy-starty)*(y-starty) + startx
end
y_at_x = function(startx,starty, endx,endy, x)
-- y at a given x on a line
-- Could be nil when the line is parallel to the y axis.
if startx == endx then
return
end
return (endy-starty)/(endx-startx)*(x-startx) + starty
end
intersect_with_centroid = function(node, sx,sy)
local h = node_height(Edge.source)
local c = {
sx=Edge.source.x + Edge.source.w/2,
sy=Edge.source.y + h/2
}
if c.sx == sx then
if sy > c.sy then
return {sx=sx, sy=Edge.source.y + h + 10}
else
return {sx=sx, sy=Edge.source.y - 10}
end
end
-- collect nearest intersection with all 4 boundaries
local candidates = {}
local y = y_at_x(sx,sy, c.sx,c.sy, Edge.source.x-10)
if y and y >= Edge.source.y-10 and y < Edge.source.x+h+10 then
table.insert(candidates, {sx=Edge.source.x-10, sy=y})
end
y = y_at_x(sx,sy, c.sx,c.sy, Edge.source.x + Edge.source.w + 10)
if y and y >= Edge.source.y-10 and y < Edge.source.x+h+10 then
table.insert(candidates, {sx=Edge.source.x+Edge.source.w+10, sy=y})
end
local x = x_at_y(sx,sy, c.sx,c.sy, Edge.source.y-10)
if x and x >= Edge.source.x-10 and x < Edge.source.x + Edge.source.w + 10 then
table.insert(candidates, {sx=x, sy=Edge.source.y-10})
end
x = x_at_y(sx,sy, c.sx,c.sy, Edge.source.y+h+10)
if x and x >= Edge.source.x-10 and x < Edge.source.x + Edge.source.w + 10 then
table.insert(candidates, {sx=x, sy=Edge.source.y+h+10})
end
if #candidates == 0 then
-- no intersection; just return the same point
return {sx=sx, sy=sy}
end
if #candidates == 1 then
return candidates[1]
end
assert(#candidates == 2)
if distance_sq(sx,sy, candidates[1].sx, candidates[1].sy) < distance_sq(sx,sy, candidates[2].sx, candidates[2].sy) then
return candidates[1]
else
return candidates[2]
end
end
node_height = function(node)
-- we store the node's height internally, but it can be too small
return math.max(node.h, 3*node.editor.line_height)
end
table.length = function(h)
-- length of a table (not just the array side)
local result = 0
for _ in pairs(h) do
result = result+1
end
return result
end
if Border then
App.color{r=0,g=1,b=1}
love.graphics.circle('fill', vx(Border.sx),vy(Border.sy), 5)
if Edge then
App.color{r=0,g=0,b=1}
if Edge.s.debug_info then
for _,p in ipairs(Edge.s.debug_info) do
love.graphics.circle('line', vx(p.sx), vy(p.sy), 5)
end
end
App.color{r=0,g=0,b=0}
love.graphics.line(vx(Edge.s.sx),vy(Edge.s.sy), vx(Edge.e.sx),vy(Edge.e.sy))
love.graphics.circle('fill', vx(Edge.s.sx),vy(Edge.s.sy), 5)
love.graphics.circle('fill', vx(Edge.e.sx),vy(Edge.e.sy), 5)
elseif Border then
Border = nil
elseif Edge then
local src = Edge.source
local line_height = Edge.source.editor.line_height
local dest = {id=next_key(), type='text', x=sx(x)-60,y=sy(y)-1.5*line_height, margin=0, width=120, outgoing_edges={}, incoming_edges={src.id}}
Nodes[dest.id] = dest
table.insert(Nodes[src.id].outgoing_edges, dest.id)
Edge = nil
A()