Trying again with the toxiclibs library.
All I’d like to know is:
- How to push surrounding cells when they enter another cell’s perimeter ? (What’s the math ?)
Context:
A large part of my problem comes from the fact that the cells’ sizes are not fixed, they change with time.
As a result, both the spring rest length and the radius of the repulsion force of each cell must vary in time.
Regarding the force, I could certainly use the AttractionBehavior
class in the toxiclibs library instead of implementing my own BUT it would be then impossible to change the radius of the repulsion force dynamically (because the setRadius
method doesn’t seem to be working).
As a result, cells are overlapping (fixed repulsion force radius that doesn’t fit the cells’ radius) and it quickly becomes a mess.
That’s why I need to compute the force by myself and would need your help to fix the interact()
function.
def interact(self):
#Check every other cells
for a in collection:
if a is not self:
#Distance between other cells
d = dist(self.x(), self.y(), a.x(), a.y())
#If distance < sum of the 2 radii
if d < (a.radius + self.radius + 1):
#(NOT CORRECT) Push other cells outside its perimeter
gap = (a.radius + self.radius + 1) - d
diff = Vec2D.sub(Vec2D(self.x(), self.y()), Vec2D(a.x(), a.y())).normalizeTo(gap)
a.addVelocity(diff)
(for a “Processing version” of that snippet (no use of toxicilibs classes) see previous post above)
Full script
add_library('verletphysics')
add_library('toxiclibscore')
from toxi.physics2d import VerletPhysics2D, VerletParticle2D
from toxi.physics.behaviors import GravityBehavior
id = 0
def setup():
global collection, physics, d
size(480, 360, P2D)
smooth(8)
physics = VerletPhysics2D()
physics.setDrag(.4)
physics.setWorldBounds(Rect(0, 0, width, height))
collection = [Cell(width>>1, height>>1)]
physics.addParticle(collection[0])
d = {}
def draw():
global physics, collection, connections, col
background(255)
physics.update()
collection[0].lock()
for c in collection:
c.growth()
c.display()
c.interact()
#Updating spring's rest length
if len(collection) > 1:
for i in range(len(physics.springs)):
physics.springs.get(i).setRestLength(collection[-2].radius + collection[-1].radius)
for e in d:
for id in d[e]:
strokeWeight(1)
line(collection[e].x(), collection[e].y(), collection[id].x(), collection[id].y())
class Cell(VerletParticle2D):
growthInterval = 5
divisionInterval = 50
def __init__(self, x, y):
super(Cell, self).__init__(x, y)
self.position = Vec2D(x, y)
self.radius = 5
self.time = 0
self.id = 0
self.linked = False
def growth(self):
global id
self.time += 1
if len(collection) < 20:
if self.time > 0 and self.time%Cell.divisionInterval == 0:
if random(1) > .5:
dir = Vec2D.randomVector()
self.radius *= .5
id += 1
child = Cell(self.x() + dir.x(), self.y() + dir.y())
child.id = id
if self.id not in d:
d[self.id] = [child.id]
else:
d[self.id].append(child.id)
collection.append(child)
#Adding child to 'physics'
physics.addParticle(child)
#Adding springs between mother and child
s = VerletSpring2D(self, child, self.radius + child.radius + 10, .1)
physics.addSpring(s)
if self.time%Cell.growthInterval == 0:
self.radius += .5
def interact(self):
for a in collection:
if a is not self:
d = dist(self.x(), self.y(), a.x(), a.y())
if d < (a.radius + self.radius + 1):
gap = (a.radius + self.radius + 1) - d
diff = Vec2D.sub(Vec2D(self.x(), self.y()), Vec2D(a.x(), a.y())).normalizeTo(gap)
a.addVelocity(diff)
def display(self):
stroke(0)
strokeWeight(3)
point(self.x(), self.y())
noFill()
strokeWeight(1)
ellipse(self.x(), self.y(), self.radius*2, self.radius*2)