Deterministic initialization!

Rather than initialize the node positions randomly, use a phyllotaxis. This is
just as good, and means the resulting behavior will be deterministic as long as
no nodes are exactly coincident.
This commit is contained in:
Mike Bostock 2016-04-26 17:37:00 -07:00
parent ec754db14f
commit aa410cf32e
2 changed files with 20 additions and 11 deletions

View File

@ -60,16 +60,11 @@ export default function() {
w = x2 - x1,
l = x * x + y * y;
// Limit forces for very close nodes.
// Randomize direction for exactly-coincident nodes.
if (l < distanceMin2) {
if (!l) l = Math.random() * tau, x = Math.cos(l), y = Math.sin(l), l = 1;
l = Math.sqrt(l / distanceMin2), x /= l, y /= l, l = distanceMin2;
}
// Apply the Barnes-Hut approximation if possible.
// Limit forces for very close nodes.
if (w * w / theta2 < l) {
if (l < distanceMax2) {
if (l < distanceMin2) l = Math.sqrt(l / distanceMin2), x /= l, y /= l, l = distanceMin2;
l = quad.value * alpha / l;
node.vx += x * l;
node.vy += y * l;
@ -80,6 +75,13 @@ export default function() {
// Otherwise, process points directly.
else if (quad.length || l >= distanceMax2) return;
// Limit forces for very close nodes.
// Randomize direction for exactly-coincident nodes.
if (l < distanceMin2) {
if (!l) l = Math.random() * tau, x = Math.cos(l), y = Math.sin(l), l = 1;
l = Math.sqrt(l / distanceMin2), x /= l, y /= l, l = distanceMin2;
}
do if (quad.data !== node) {
w = strengths[quad.data.index] * alpha / l;
node.vx += x * w;

View File

@ -10,6 +10,9 @@ export function y(d) {
return d.y;
}
var initialRadius = 10,
initialAngle = Math.PI * (3 - Math.sqrt(5));
export default function(nodes) {
var simulation,
iteration = 0,
@ -58,10 +61,14 @@ export default function(nodes) {
function initializeNodes() {
for (var i = 0, n = nodes.length, node; i < n; ++i) {
node = nodes[i], node.index = i;
if (isNaN(node.x)) node.x = Math.random() * 100 - 50;
if (isNaN(node.y)) node.y = Math.random() * 100 - 50;
if (isNaN(node.vx)) node.vx = 0;
if (isNaN(node.vy)) node.vy = 0;
if (isNaN(node.x) || isNaN(node.y)) {
var radius = initialRadius * Math.sqrt(i), angle = i * initialAngle;
node.x = radius * Math.cos(angle);
node.y = radius * Math.sin(angle);
}
if (isNaN(node.vx) || isNaN(node.vy)) {
node.vx = node.vy = 0;
}
}
}