This circle collision script was a more dynamic version of circle packing. Normally this would be done with dart throwing or something a bit less brute force. In this case its very brute force and hence ugly and slow, but fun all the same.

Take a look. https://vimeo.com/60926441

-Michael

Code:

---------------------------------------------------------------------------------------- -- Circle Collision -- -- Dynamic Circle packing -- Circles are placed in a domain and then push their neighbors till there are no overlaps -- -- Michael Spaw -- Morphographic.com -- Started 02/05/13 -- ver 0.01 02/08/13 -- -- Here are the steps for the algorithm -- 1. N# of circles are placed randomly within the bounding shape -- and the wirecolor is set to yellow -- 2. For each circle its closest neighbor is found -- 3. Based on the vector between the circle and its closest neighbor the circle -- is moved just a bit in the oposite dirrection -- 4. The neighbor and repulsion setp is looped through till there are no overlaps -- -- Also of note you can see the wirecole change based on if the circle has been moved or is stationary ---------------------------------------------------------------------------------------- -- Setup aqua = (color 87 224 198)--Create a color to be used for the bounding shape drawRad = 3 --the radius of the circles radvary = 0.7 --The amount of variation in the radius of the circles numcircles =200 --Total number of circles created within the test Iterations = 5000 --Total attemps to move the cicrcles so they no longer collide initxpos = 50.0-drawrad --Inital x position for the circle minus some to keep it in the bounding rectangle initypos = 50.0-drawrad --same for the y delete objects--Lets clearout all the objects before we start Rectangle length:100 width:100 pos:[0,0,0] wirecolor:aqua --a nice bounding rectangle for neatness fn blendcolor a b x = ( return ((a) * (1 - (x)) + (b) * (x)) ) blendTime = 10 startColor = red endColor = yellow fn setColor startColor endColor obj blendTime = ( StartColorV = [startColor.r,startColor.g,startColor.b] endColorV = [endColor.r,endColor.g,endColor.b] colorDelta = (StartColorV - endColorV)*(1.0/blendTime) *-1 currentColor = [obj.wirecolor.r,obj.wirecolor.g,obj.wirecolor.b] L = (length (endColorV - currentColor)) if (L > (length colorDelta)) then ( newColor = currentColor + colorDelta obj.wirecolor = (color newColor.x newColor.y newColor.z) ) else ( obj.wirecolor = endColor ) ) --Make some circles in the bounding area Circles= #() for i = 1 to numcircles do ( p = (random [-initxpos,-initypos ,0.0] [initxpos,initypos,0.0]) randRad = drawRad + (random (drawRad*-radvary) (drawRad*radvary)) myCircle = circle pos:p radius:randRad wirecolor:startColor append circles myCircle ) circlescolor= #() for i = 1 to numcircles do ( circleColorVal = 0.0 append circlescolor circleColorVal ) fn findClosestNodes circles obj = ( closestNodes = #() for i=1 to circles.count do ( -- loop through the circles to find any that are within the radius of the circle in question (obj) if obj!=circles[i] do ( --check to make sure we aren't comparing against ourself ( currDist = distance obj.pos circles[i].pos -- get the dist between comparison pairs if (currDist < (obj.radius+circles[i].radius)) do ( -- if the circles overlap, add to the return array append closestNodes circles[i] ) ) ) ) return closestNodes ) --Time for some collision testing and movement for j=1 to iterations do ( noChange = true for i = 1 to circles.count do ( closestCircles = findClosestNodes circles circles[i] if closestCircles.count == 0 do (setColor startColor endColor circles[i] blendTime) for k=1 to closestCircles.count do ( ra = circles[i].radius rb = closestCircles[k].radius rad = ra+rb d = distance closestCircles[k].pos circles[i].pos if (d < rad) do ( noChange = false currentpos = circles[i].pos v = (closestCircles[k].pos - circles[i].pos) * -0.05 circles[i].pos += v newpos = circles[i].pos if (newPos != currentpos) do (circles[i].wirecolor = red) ) ) ) if noChange do ( circles.wirecolor = yellow format "Number of iterations: %\n" j exit ) forceCompleteRedraw() windows.processPostedMessages() )