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.
KA3WML5YL2EKXNDNL2GP4GVVCPZYAAZBOQLVJH3GD2LEXUI4OB6AC
5N57VOATVSATXDBSRBNNPQU3BHONGN22EOMHZAD3DV5367WJRSLQC
VOSTX4QHUMVJNSCP34WPRESQRN4OBXK7PILA2RMODRFEAU5LJV2QC
R5QXEHUIZLELJGGCZAE7ATNS3CLRJ7JFRENMGH4XXH24C5WABZDQC
C2REOTRMF7EY6E3DAEL4ICI4O2AFAURWNQ7QCDMEZRNVM6ERM2UQC
J62CVGNGJZSN7TMTE2SG53O47YG4SJGJFTUFKVOZY4TM4KAC566QC
SMZJGK56DYOP2CYIYDV3QXVHL5P52IEF34GFBESNMULJDMDLJR2AC
JNS2ATVJRXCIBGRFRPPN63OAOQRVV7GE2VRAL3T6YNRXFX6YYMQAC
ZUXG2RU4WF5WF7EYU2XQJ6AERLJLOMGDEXWRMGWHT5DR3B7X7MWQC
YUQ4YINAT5YTK3CAY4VK3HSYQ4D63FXLLPMC4R3DUFHIZIUQO7WQC
GE7YT55JWPF5YGO2UPE6JDDBUKCP27CPHAE75XQ77IJWGFM2AJIQC
UJ2RZ43LIVRIBWIXHXMLIQIQTL32VVEN4CVU7PEBTITQFPO4EXXQC
T7T66GEUFLP3YHZN5UNOVBYK33KISJWJQKCPZU6MQH45KSU7CZZQC
BBJCF6PTCLGQJ37LINJKTG3BBFYTLB6AV3NFJOEWNZYONQYQXU2QC
QFUZ53WLZETJ7SQTEHL7NLTEXDPX2WX2S3Y7VO53SSSIFADGUTNQC
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()