Skip to content

Instantly share code, notes, and snippets.

/_.md

Forked from enjalot/_.md
Created September 25, 2012 03:42
Show Gist options
  • Select an option

  • Save anonymous/3779864 to your computer and use it in GitHub Desktop.

Select an option

Save anonymous/3779864 to your computer and use it in GitHub Desktop.
just another inlet to tributary
{"editor_editor":{"coffee":false,"vim":false,"emacs":false,"width":487,"height":278,"hide":false},"endpoint":"bigfish"}
//appearance
var rx = 7.5;
var ry = 5;
//number of boids
var n = 50;
var neighbor_radius = 50;
var mouse_radius = 200;
var desired_separation = 105;
var max_force = .1;
var max_speed = 2;
var separation_weight = 2;
//how much the boids want to line up
var alignment_weight = 10;
//how much the boids want to stay close together
var cohesion_weight = 10;
//mostly changes how much the mouse affects the boids
var gravity_multiplier = 100;
//some defaults
tributary.trace = true; //turns on console trace for errors
var w = tributary.sw; //get screen width and height
var h = tributary.sh;
//initialize the "global" variable that keeps track of mouse
var mouse = [null, null];
tributary.init = function(g) {
//setup the nodes
tributary.nodes = d3.range(n).map(function() {
var x = Math.random() * w, y = Math.random() * h;
var b = boid()
.position([Math.random() * w, Math.random() * h])
.velocity([Math.random() * 2 - 1, Math.random() * 2 - 1])
.gravityCenter(mouse)
return b;
});
vertices = tributary.nodes.map(function(boid) {
return boid(tributary.nodes);
});
//render the boids as ellipses
var gs = g.selectAll("g.node")
.data(tributary.nodes)
.enter().append("g").classed("node", true);
var head = gs.append("svg:ellipse")
//mouse interaction stuff
function nullGravity() {
mouse[0] = mouse[1] = null;
}
d3.select("svg").on("mousemove", function() {
var m = d3.mouse(this);
mouse[0] = m[0];
mouse[1] = m[1];
})
.on("mouseout", nullGravity);
};
//update the simulation while the play button is running.
tributary.run = function(g,t) {
var len = tributary.nodes.length;
for (var i = -1; ++i < len;) {
var b = tributary.nodes[i];
b.separationWeight(separation_weight)
.alignmentWeight(alignment_weight)
.cohesionWeight(cohesion_weight)
.neighborRadius(neighbor_radius)
.desiredSeparation(desired_separation)
.mouseRadius(mouse_radius)
.gravityMultiplier(gravity_multiplier)
.maxForce(max_force)
.maxSpeed(max_speed)
//perform update with "neighbors"
b(tributary.nodes);
}
var gs = g.selectAll("g.node")
var head = gs.select("ellipse")
head.attr("transform", function(d,i) {
var angle = 90-Math.atan2(d.velocity()[0], d.velocity()[1]) * 180/Math.PI;
return "translate(" + d.position() + ")rotate(" + angle + ")";
})
.attr("rx", rx)
.attr("ry", ry);
};
// Boid flocking based on http://harry.me/2011/02/17/neat-algorithms---flocking
var boid = (function() {
function boid() {
var position = [0, 0],
velocity = [0, 0],
gravityCenter = null,
gravityMultiplier = 1,
neighborRadius = 50,
mouseRadius = 50,
maxForce = .1,
maxSpeed = 1,
separationWeight = 2,
alignmentWeight = 1,
cohesionWeight = 1,
desiredSeparation = 10;
function boid(neighbors) {
var accel = flock(neighbors);
d3_ai_boidWrap(position);
velocity[0] += accel[0];
velocity[1] += accel[1];
if (gravityCenter) {
//var g = d3_ai_boidGravity(gravityCenter, position, neighborRadius);
var g = d3_ai_boidGravity(gravityCenter, position, mouseRadius)
velocity[0] += g[0] * gravityMultiplier;
velocity[1] += g[1] * gravityMultiplier;;
}
d3_ai_boidLimit(velocity, maxSpeed);
position[0] += velocity[0];
position[1] += velocity[1];
return position;
}
function flock(neighbors) {
var separation = [0, 0],
alignment = [0, 0],
cohesion = [0, 0],
separationCount = 0,
alignmentCount = 0,
cohesionCount = 0,
i = -1,
l = neighbors.length;
while (++i < l) {
var n = neighbors[i];
if (n === this) continue;
var npos = n.position(),
d = d3_ai_boidDistance(position, npos);
if (d > 0) {
if (d < desiredSeparation) {
var tmp = d3_ai_boidNormalize(d3_ai_boidSubtract(position.slice(), npos));
separation[0] += tmp[0] / d;
separation[1] += tmp[1] / d;
separationCount++;
}
if (d < neighborRadius) {
var nvel = n.velocity();
alignment[0] += nvel[0];
alignment[1] += nvel[1];
alignmentCount++;
cohesion[0] += npos[0];
cohesion[1] += npos[1];
cohesionCount++;
}
}
}
if (separationCount > 0) {
separation[0] /= separationCount;
separation[1] /= separationCount;
}
if (alignmentCount > 0) {
alignment[0] /= alignmentCount;
alignment[1] /= alignmentCount;
}
d3_ai_boidLimit(alignment, maxForce);
if (cohesionCount > 0) {
cohesion[0] /= cohesionCount;
cohesion[1] /= cohesionCount;
} else {
cohesion = position.slice();
}
cohesion = steerTo(cohesion);
return [
separation[0] * separationWeight +
alignment[0] * alignmentWeight +
cohesion[0] * cohesionWeight,
separation[1] * separationWeight +
alignment[1] * alignmentWeight +
cohesion[1] * cohesionWeight
];
}
function steerTo(target) {
var desired = d3_ai_boidSubtract(target, position),
d = d3_ai_boidMagnitude(desired);
if (d > 0) {
d3_ai_boidNormalize(desired);
// Two options for desired vector magnitude (1 -- based on distance, 2 -- maxspeed)
var mul = maxSpeed * (d < 100 ? d / 100 : 1);
desired[0] *= mul;
desired[1] *= mul;
// Steering = Desired minus Velocity
var steer = d3_ai_boidSubtract(desired, velocity);
d3_ai_boidLimit(steer, maxForce) // Limit to maximum steering force
} else {
steer = [0, 0];
}
return steer;
}
boid.position = function(x) {
if (!arguments.length) return position;
position = x;
return boid;
}
boid.velocity = function(x) {
if (!arguments.length) return velocity;
velocity = x;
return boid;
}
boid.gravityCenter = function(x) {
if (!arguments.length) return gravityCenter;
gravityCenter = x;
return boid;
}
boid.gravityMultiplier = function(x) {
if (!arguments.length) return gravityMultiplier;
gravityMultiplier = x;
return boid;
}
boid.neighborRadius = function(x) {
if (!arguments.length) return neighborRadius;
neighborRadius = x;
return boid;
}
boid.mouseRadius = function(x) {
if (!arguments.length) return mouseRadius;
mouseRadius = x;
return boid;
}
boid.maxForce = function(x) {
if (!arguments.length) return maxForce;
maxForce = x;
return boid;
}
boid.maxSpeed = function(x) {
if (!arguments.length) return maxSpeed;
maxSpeed = x;
return boid;
}
boid.separationWeight = function(x) {
if (!arguments.length) return separationWeight;
separationWeight = x;
return boid;
}
boid.alignmentWeight = function(x) {
if (!arguments.length) return alignmentWeight;
alignmentWeight = x;
return boid;
}
boid.cohesionWeight = function(x) {
if (!arguments.length) return cohesionWeight;
cohesionWeight = x;
return boid;
}
boid.desiredSeparation = function(x) {
if (!arguments.length) return desiredSeparation;
desiredSeparation = x;
return boid;
}
return boid;
}
function d3_ai_boidNormalize(a) {
var m = d3_ai_boidMagnitude(a);
if (m > 0) {
a[0] /= m;
a[1] /= m;
}
return a;
}
function d3_ai_boidWrap(position) {
if (position[0] > w) position[0] = 0;
else if (position[0] < 0) position[0] = w;
if (position[1] > h) position[1] = 0;
else if (position[1] < 0) position[1] = h;
}
function d3_ai_boidGravity(center, position, neighborRadius) {
if (center[0] != null) {
var m = d3_ai_boidSubtract(center.slice(), position),
d = d3_ai_boidMagnitude(m) - 10;
if (d > 0 && d < neighborRadius * 5) {
d3_ai_boidNormalize(m);
m[0] /= d;
m[1] /= d;
return m;
}
}
return [0, 0];
}
function d3_ai_boidDistance(a, b) {
var dx = a[0] - b[0],
dy = a[1] - b[1];
if (dx > w / 2) dx = w - dx;
if (dy > h / 2) dy = h - dy;
return Math.sqrt(dx * dx + dy * dy);
}
function d3_ai_boidSubtract(a, b) {
a[0] -= b[0];
a[1] -= b[1];
return a;
}
function d3_ai_boidMagnitude(v) {
return Math.sqrt(v[0] * v[0] + v[1] * v[1]);
}
function d3_ai_boidLimit(a, max) {
if (d3_ai_boidMagnitude(a) > max) {
d3_ai_boidNormalize(a);
a[0] *= max;
a[1] *= max;
}
return a;
}
return boid;
})();
Display the source blob
Display the rendered blob
Raw
<svg id="bigfishsvg" class="tributary_svg" width="900" height="535"><g id="bigfish"><g class="node"><ellipse transform="translate(392.7251026569036,510.6235200979916)rotate(0.37461175849932715)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(415.92476874769244,313.1460738455699)rotate(148.9143106216568)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(455.1530864536137,420.4772477787507)rotate(72.11090794906346)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(358.3987504766935,451.4067604433196)rotate(97.34846741563874)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(742.4436109156887,364.14181404898386)rotate(18.273013508018195)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(871.1786102567245,291.0122758281892)rotate(233.25633274123967)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(363.0881959139897,308.667666007259)rotate(97.63222646695071)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(257.4891298462485,164.52316289719954)rotate(121.47843672356154)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(414.5801250114063,151.1614918420688)rotate(231.00208557779055)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(472.10968587640673,30.148964719614014)rotate(35.9496606041332)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(584.9208412444233,56.37833080778127)rotate(81.19051201352097)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(790.6253640990274,116.43346430915017)rotate(20.305819895520457)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(512.2174485391492,469.13911991158835)rotate(-39.09681655721221)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(664.9685424138895,433.6572931523808)rotate(114.58933972910047)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(217.17759215354374,174.77558792552645)rotate(69.14837472424573)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(385.5836759682408,311.2815972006558)rotate(110.804531723332)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(158.24623098985955,527.5474420621726)rotate(261.46427201794484)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(778.4083518276133,184.16557418688325)rotate(262.3966171634356)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(272.9118078908591,31.890859127618494)rotate(149.84579814739067)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(861.8548306837965,111.23826157945281)rotate(-27.609482359422486)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(588.1567952577371,335.79989021801794)rotate(48.13692152054624)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(222.85710642715875,487.9896498580663)rotate(-18.307145379843135)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(323.2671868099894,174.43754285185167)rotate(18.624081384283528)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(853.0019235592276,20.825544948465154)rotate(205.03750304029415)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(88.85540676654222,103.95484946380354)rotate(262.33098578567115)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(486.462924956992,522.2014027076865)rotate(-59.89725275667371)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(354.7394795828875,77.05356856525935)rotate(-11.022768426122951)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(827.836568754824,19.95118824359078)rotate(228.23232322525965)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(832.6803335429265,26.105859791141878)rotate(250.82607407490525)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(300.42759705574207,68.41201183135792)rotate(208.7021939753646)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(622.2968548786531,333.70739781487356)rotate(76.51902539781715)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(734.8515701079014,171.76742561190946)rotate(236.43991795071355)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(49.29366003815772,294.8045921378555)rotate(104.68252012049302)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(586.3489203408791,374.5666031240328)rotate(29.24857448409645)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(713.3239777823964,337.1857361786808)rotate(32.28623696441172)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(456.11437953940316,383.1993947132143)rotate(172.14714051560492)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(877.5517336157496,194.9509503736376)rotate(57.55192174354938)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(360.8581714526885,313.73576570762316)rotate(93.25026725708192)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(24.092601894401014,477.62175456713885)rotate(-78.11286041756506)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(704.3760618188749,170.98427240895666)rotate(-76.43026815393353)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(258.69258440150037,476.6897818698057)rotate(-6.247354238881542)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(643.0824273136742,283.4310321871091)rotate(5.02905685310688)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(556.8417781105985,150.77836586295257)rotate(45.24678936541423)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(434.75629677277885,352.27554956880164)rotate(180.85708853021873)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(581.7595495475713,87.0942586739249)rotate(73.24203410044315)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(786.5624066572587,78.67159211764253)rotate(59.163275601494306)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(23.77852460132456,262.73032918280626)rotate(52.55184847446341)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(774.3715214555774,313.77998706144643)rotate(229.11644458625733)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(679.3639751754109,289.93472113210896)rotate(-0.5511306136280609)" rx="7.5" ry="5"></ellipse></g><g class="node"><ellipse transform="translate(24.741102626006043,114.91359777698752)rotate(149.2799013505526)" rx="7.5" ry="5"></ellipse></g></g></svg>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment