Another collision detection work. Very elegant.
Here’s a little bit background about this sketch. As we can see, this sketch is composed by non-touching circles in a canvas. This algorithm generate a random sample by generating K candidates, and choose the best one and add it to the system. The definition of best is that it’s the farthest away from the previous sample. By this way, the emergance of new sample would be more natural, compared with the uniform random sampling.
Some people ask, “is this useful? I can’t see how I can use it into my work.” They are probably wrong, an English artist use exactly the same effect in his work Silent Buddha. It’s a really impressive work.
Now take a look from the inside.
Sketch
If you read the previous post about collision detection, you can safely read from setup timer section. If not, and you do not have much experience about d3, you can spend maybe 5 - 10 mins on that post to have a basic sense about the following things.
Initialization
1 | <!DOCTYPE html> |
Setup timer
1 |
|
The timer
function is not like the tick
function. tick
will be trigger forever, but timer will stop. timer receive a function, and then invoking that function until it return true.
There are also a new method we have not seen before transition. it animate change smoothly over time rather than applying instantaneously.
The r
attribute in a circle
will be transited from 0
to a given value circle[2]
.
So here’s what it has done in this fucntion.
- create a new circle. this circle is selected from
k
candidates. - add it to the svg container
- do step 1&2
m
time for each timer - if have add enough circle, then stop the timer.
Circle Generator
As you might already noticed, the secret lies in the newCircle(k)
method.
newCircle = bestCircleGenerator(maxRadius, padding);
What? Why we need to pass a k
?
All right, take a close look of the bestCircleGenerator
.
bestCircleGenerator
return an anonymous function, which receive an integer k
as number of candidates. And look at the anonymous function, we can see that the function do mainly 3 things.
- create k candidates and select the best one.
- add it to the quadtree
- return the coordinate and the radius
Then in the timer, we can add this candidate to svg and present it.
1 | function bestCircleGenerator(maxRadius, padding) { |
When firstly bestCircleGenerator
is called, an empty Quadtree is generated, which will cover the whole svg container via the extent method. And it also setup an searching range.
Again, it need some effort to understand the quadtree.visit. Here, it will visit nodes in this quadtree.But because quadtree have some feature that we can reduce the depth of visit, so we need to tell the quadtree whether we want to continue our visit to deeper node. the anonymous fucntion here, return a boolean value indicate whether we need to continue our visit. If function return true, then the children of current node won’t be visited.
So what have been done inside this function is:
- get the position and radius of current node
- calculate the whether current node is apart from candidate node
- If not, return true and stop visiting this node
- If so, update the minimum distance. if the distance is zero and current node is outside of the search radius, also return true and stop visiting this node.
- check whether the new distance is the “best” distance
- If so, update the “best” distance
And finally, if a new circle is founded, add it to the quadtree, return the position and radius. So in the d3.timer() method, it can be drawn on the svg container.
That’s all for this simple and pretty sketch.