#### Howdy, Stranger!

It looks like you're new here. If you want to get involved, click one of these buttons!

# Line to nearest neighbor

edited January 2018 Posts: 8,383

Here’s another useless program. Each circle draws a fat line to its nearest neighbor. Tap the screen to add 5 more circles. I had nothing better to do.

``````displayMode(FULLSCREEN)

function setup()
tab={}
FPS=60
create()
end

function create()
for z=1,5 do
local sp=2
local t={}
t.x=math.random(WIDTH)
t.y=math.random(HEIGHT)
t.xv=math.random(-sp,sp)
t.yv=math.random(-sp,sp)
t.dist=0    -- nearest neighbor distance
t.x1=0      -- nearest neighbor x,y
t.y1=0
t.col=color(math.random(255),math.random(255),math.random(255))
table.insert(tab,t)
end
end

function draw()
background(80, 80, 80, 54)
fill(255)
text("Tap screen for 5 more circles",WIDTH/2,HEIGHT-20)
text("Circles "..#tab,WIDTH/2,HEIGHT-40)
text("FPS "..FPS//1,WIDTH/2,HEIGHT-60)
-- find nearest neighbor
for a,b in pairs(tab) do
local v1=vec2(b.x,b.y)
b.dist=9999
for c,d in pairs(tab) do
local v2=vec2(d.x,d.y)
local dst=v1:dist(v2)
if dst>0 and dst<b.dist then
b.dist=dst
b.x1=d.x
b.y1=d.y
end
end
end
-- draw lines
for a,b in pairs(tab) do
stroke(b.col)
strokeWidth(40)
line(b.x,b.y,b.x1,b.y1)
end
-- draw circles over lines
for a,b in pairs(tab) do
fill(0)
noStroke()
ellipse(b.x,b.y,10)
stroke(0)
strokeWidth(5)
line(b.x,b.y,b.x-(b.x-b.x1)/4,b.y-(b.y-b.y1)/4)
end
-- change position and reverse direction at edges
for a,b in pairs(tab) do
b.x=b.x+b.xv
b.y=b.y+b.yv
if b.x<0 or b.x>WIDTH then
b.xv=-b.xv
end
if b.y<0 or b.y>HEIGHT then
b.yv=-b.yv
end
end
FPS = FPS * 0.9 + 0.1 / DeltaTime
end

function touched(t)
if t.state==BEGAN then
create()
end
end
``````

• Posts: 489

That's quite fun.

I took the liberty of vecing it.

``````-- NeighbourLines

displayMode(FULLSCREEN)

function setup()
tab={}
FPS=60
create()
end

function create()
local t,sp
sp=2
for z=1,5 do
t={}
t.p=vec2(math.random(WIDTH),math.random(HEIGHT))
t.v=vec2(math.random(-sp,sp),math.random(-sp,sp))
t.col=randomColour()
table.insert(tab,t)
end
end

function randomColour()
local h = math.random()*6
local x = 255*(1 - math.abs(h%2 - 1))
local r,g,b
if h < 1 then
r,g,b = 255,x,0
elseif h < 2 then
r,g,b = x,255,0
elseif h < 3 then
r,g,b = 0,255,x
elseif h < 4 then
r,g,b = 0,x,255
elseif h < 5 then
r,g,b = x,0,255
else
r,g,b = 255,0,x
end
return color(r,g,b)
end

function draw()
background(80, 80, 80, 54)
fill(255)
text("Tap screen for 5 more circles",WIDTH/2,HEIGHT-20)
text("Circles "..#tab,WIDTH/2,HEIGHT-40)
text("FPS "..FPS//1,WIDTH/2,HEIGHT-60)

local dists = {}
local d
-- work out all the distances in one fell swoop
for k,v in ipairs(tab) do
dists[k] = {}
for l=1,k-1 do
d = v.p:dist(tab[l].p)
dists[k][l] = {d,tab[l]}
dists[l][k] = {d,tab[k]}
end
-- ensure that the closest point is not itself
dists[k][k] = {math.max(WIDTH,HEIGHT),v}
end
-- find closest neighbour by sorting the rows
for k,v in ipairs(dists) do
table.sort(v,function(a,b) return a < b end)
end
-- draw lines
strokeWidth(40)
local u
for k,v in ipairs(tab) do
stroke(v.col)
u = dists[k]
line(v.p.x,v.p.y,u.p.x,u.p.y)
end
-- draw circles over lines
fill(0)
noStroke()
for k,v in ipairs(tab) do
ellipse(v.p.x,v.p.y,10)
end
-- change position and reverse direction at edges
for a,b in pairs(tab) do
b.p = b.p + b.v
if b.p.x<0 or b.p.x>WIDTH then
b.v.x=-b.v.x
end
if b.p.y<0 or b.p.y>HEIGHT then
b.v.y=-b.v.y
end
end
FPS = FPS * 0.9 + 0.1 / DeltaTime
end

function touched(t)
if t.state==BEGAN then
create()
end
end
``````
• edited January 2018 Posts: 8,383

Made changes to my code at the top so the circles point to its nearest neighbor. That helps to see who the closest neighbor is. @LoopSpace I’m still trying to figure out why the vectors work in the calcP3 function of the other program. I printed the different values in the calcP3 function, but why they work I haven’t figured out yet.

• Posts: 489

To make the same change in my code:

``````u = dists[k].p/4 + 3* v.p/4
line(v.p.x,v.p.y,u.x,u.y)
``````

I'll write up an explanation of the code in the calcP3 function in a bit.

• Posts: 489

I thought that the shorter lines behaved like springs, so I put in forces and acceleration.

``````-- NeighbourLines

displayMode(FULLSCREEN)

function setup()
tab={}
FPS=60
create()
end

function create()
local t,sp
sp=2
for z=1,5 do
t={}
t.p=vec2(math.random(WIDTH),math.random(HEIGHT))
t.v=vec2(0,0)
t.a=vec2(0,0)
t.col=randomColour()
table.insert(tab,t)
end
end

function randomColour()
local h = math.random()*6
local x = 255*(1 - math.abs(h%2 - 1))
local r,g,b
if h < 1 then
r,g,b = 255,x,0
elseif h < 2 then
r,g,b = x,255,0
elseif h < 3 then
r,g,b = 0,255,x
elseif h < 4 then
r,g,b = 0,x,255
elseif h < 5 then
r,g,b = x,0,255
else
r,g,b = 255,0,x
end
return color(r,g,b)
end

function draw()
background(80, 80, 80, 54)
fill(255)
text("Tap screen for 5 more circles",WIDTH/2,HEIGHT-20)
text("Circles "..#tab,WIDTH/2,HEIGHT-40)
text("FPS "..FPS//1,WIDTH/2,HEIGHT-60)

local dists = {}
local d
-- work out all the distances in one fell swoop
for k,v in ipairs(tab) do
dists[k] = {}
for l=1,k-1 do
d = v.p:dist(tab[l].p)
dists[k][l] = {d,tab[l]}
dists[l][k] = {d,tab[k]}
end
-- ensure that the closest point is not itself
dists[k][k] = {math.max(WIDTH,HEIGHT),v}
end
-- find closest neighbour by sorting the rows
for k,v in ipairs(dists) do
table.sort(v,function(a,b) return a < b end)
end
-- draw lines
strokeWidth(40)
local u
for k,v in ipairs(tab) do
stroke(v.col)
u = dists[k].p/4 + 3*v.p/4
line(v.p.x,v.p.y,u.x,u.y)
end
-- draw circles over lines
fill(0)
noStroke()
for k,v in ipairs(tab) do
ellipse(v.p.x,v.p.y,10)
end
-- change position and reverse direction at edges
for a,b in pairs(tab) do
b.p = b.p + DeltaTime * b.v
b.v = b.v + DeltaTime * b.a
b.a = (dists[a].p - b.p)
b.a = b.a*(b.a:len() - 150)/3000
if b.p.x<0 then
b.v.x = math.abs(b.v.x)
b.p.x = math.abs(b.p.x)
end
if b.p.x>WIDTH then
b.v.x = -math.abs(b.v.x)
b.p.x = 2*WIDTH - b.p.x
end
if b.p.y<0 then
b.v.y = math.abs(b.v.y)
b.p.y = math.abs(b.p.y)
end
if b.p.y>HEIGHT then
b.v.y = -math.abs(b.v.y)
b.p.y = 2*HEIGHT - b.p.y
end
end
FPS = FPS * 0.9 + 0.1 / DeltaTime
end

function touched(t)
if t.state==BEGAN then
create()
end
end
``````
• Posts: 8,383

@LoopSpace Interesting changes. Kind of reminds me of dodgem cars.