1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
|
-- see also: http://www.vergenet.net/~conrad/boids/pseudocode.html
local swarm = pd.Class:new():register("swarm")
function swarm:initialize(sel, atoms) -- constructor
if type(atoms[1]) ~= "number" or atoms[1] < 2 then return false end
if type(atoms[2]) ~= "number" or atoms[2] < 3 then return false end
self.dim = math.floor(atoms[1])
self.count = math.floor(atoms[2])
self.cluster = 0.05 -- magic values look ok in the help patch..
self.distance2 = 0.2
self.similar2 = 0.1
self.friction = 0.96
self.flock = { }
self:in_1_randomize()
self.inlets = 2
self.outlets = 2
return true
end
function swarm:in_1_randomize() -- randomize positions, no movement
for i = 1, self.count do
self.flock[i] = { x = { }, dx = { } }
for j = 1, self.dim do
self.flock[i].x[j] = math.random() - 0.5
self.flock[i].dx[j] = 0
end
self.flock[i].w = math.random() + 0.5
end
end
function swarm:in_1_bang() -- update and output
local c = self:center()
for i = 1, self.count do
f = self.flock[i] -- update
local v1 = self:rule1(c, f)
local v2 = self:rule2(i, f)
local v3 = self:rule3(i, f)
for k = 1, self.dim do f.dx[k] = f.dx[k] + v1[k] + v2[k] + v3[k] end
for k = 1, self.dim do f.dx[k] = f.dx[k] * self.friction end
for k = 1, self.dim do f.x[k] = f.x[k] + f.dx[k] end
self:outlet(2, "float", { i }) -- output
self:outlet(1, "list", f.x)
end
end
function swarm:center() -- center of mass
local c = { }
local w = 0
for k = 1, self.dim do c[k] = 0 end
for i = 1, self.count do
w = w + self.flock[i].w
for k = 1, self.dim do c[k] = c[k] + self.flock[i].w * self.flock[i].x[k] end
end
for k = 1, self.dim do c[k] = c[k] / w end
return c
end
function swarm:rule1(c, f) -- clustering
local v = { }
for k = 1, self.dim do v[k] = self.cluster * (c[k] - (1 + f.w) * f.x[k]) end
return v
end
function swarm:rule2(i, f) -- avoidance
local v = { }
for k = 1, self.dim do v[k] = 0 end
for j = 1, self.count do
if i ~= j then
g = self.flock[j]
local d = { }
local m = 0
for k = 1, self.dim do d[k] = g.x[k] - f.x[k] ; m = m + d[k] * d[k] end
if m < self.distance2 then
for k = 1, self.dim do v[k] = v[k] - d[k] end
end
end
end
for k = 1, self.dim do v[k] = 0.01 * v[k] end
return v
end
function swarm:rule3(i, f) -- similarity
local v = { }
for k = 1, self.dim do v[k] = 0 end
for j = 1, self.count do
if i ~= j then
g = self.flock[j]
local d = { }
local m = 0
for k = 1, self.dim do d[k] = g.dx[k] - f.dx[k] ; m = m + d[k] * d[k] end
if m < self.similar2 then
for k = 1, self.dim do v[k] = v[k] + d[k] end
end
end
end
for k = 1, self.dim do v[k] = 0.004 * v[k] end
return v
end
-- exercise: make the right inlet control individual elements
|