Skip to content

Instantly share code, notes, and snippets.

@JnBrymn-EB
Last active August 29, 2015 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save JnBrymn-EB/8b54c6def88d2640fb8c to your computer and use it in GitHub Desktop.
Save JnBrymn-EB/8b54c6def88d2640fb8c to your computer and use it in GitHub Desktop.
N-body gravitational simulation with large N (a D3 experiment)
<!DOCTYPE html>
<html>
<head>
<title>Asteroids</title>
<script src="https://cdnjs.cloudflare.com/ajax/libs/d3/3.5.5/d3.min.js" charset="utf-8"></script>
<style>
svg {
background-color:black;
}
</style>
</head>
<body>
<!-- This file lives in public/404.html -->
<div class="dialog"></div>
<script type="text/javascript">
var width = 1000;
var height = 600;
var planet_num = -1;
var vis = d3.select("div")
.append("svg:svg")
.attr("width", width)
.attr("height", height);
function make_planet() {
planet_num++;
var r = Math.random();
r = Math.pow(r,60)*100+1;
p = {
i: planet_num,
x: Math.random()*width,
y: Math.random()*height,
vx: (Math.random()-0.5)*0.1/r,
vy: (Math.random()-0.5)*0.1/r,
r: r
};
p.mass = Math.PI*p.r*p.r*p.r;
return p;
};
planet_data = []
for(var i = 0;i < 100; i++) {
planet_data.push(make_planet())
}
function color() {
return '#'+(((Math.random()*0.9)+0.1)*0xFFFFFF<<0).toString(16)
}
function update(planet_data,planet_created) {
planet_sel = vis.selectAll("circle.planet")
.data(planet_data,function(d) { return d.i; })
planet_sel.enter()
.append("circle")
.attr("class","planet")
.attr("cx",function(d) { return d.x; })
.attr("cy",function(d) { return d.y; })
.attr("r",function(d) { return d.r; })
.attr("fill",function(d){return color();})
.filter(function(d) { return d.r > 12.0;})
.attr("r",0)
.transition()
.duration(300)
.attr("r",function(d) { return d.r; });
planet_sel
.attr("cx",function(d) { return d.x; })
.attr("cy",function(d) { return d.y; });
planet_sel.exit()
.remove();
if(planet_created) {
planet_sel.sort(function (a, b) { return Math.sign(b.r - a.r);})
}
}
G = 0.00001; //gravitational constant
min_dist = 50; // to avoid instability
aero = 0.0007;
chance_small_one_disappears = 0.0001;
small_r = 2;
function integrate(planet_data, del_t) {
var to_delete = [];
var planet_created = false;
for(var i = 0;i < planet_data.length; i++) {
var p = planet_data[i];
if(p.x > (width+p.r) || p.x < (0-p.r) || p.y > (height+p.r) || p.y < (0-p.r)
|| (p.r < 4 && Math.random() < chance_small_one_disappears)) {
to_delete.push(i);
}
}
if(to_delete.length > 0) {
planet_created = true;
for(var i = 0;i < to_delete.length; i++) {
planet_data[to_delete[i]] = make_planet();
}
}
var force_x = [];
var force_y = [];
for(var i = 0;i < planet_data.length; i++) {
force_x.push([]);
force_y.push([]);
}
var f_x,f_y;
for(var i = 0;i < planet_data.length; i++) {
force_x[i][i] = 0;
force_y[i][i] = 0;
for(var j = i+1;j < planet_data.length; j++) {
var pi = planet_data[i];
var pj = planet_data[j];
if(pi.r < small_r && pj.r < small_r) {
force_x[i][j] = 0;
force_y[i][j] = 0;
force_x[j][i] = 0;
force_y[j][i] = 0;
}
var dist_x = pi.x - pj.x;
var dist_y = pi.y - pj.y;
var dist = Math.sqrt(dist_x*dist_x + dist_y*dist_y);
if(dist < min_dist) {
dist = min_dist;
}
var M = G*pi.mass*pj.mass;
var f_x = M*dist_x/Math.pow(dist,3);
var f_y = M*dist_y/Math.pow(dist,3);
force_x[i][j] = -f_x; // force placed upon i by j
force_y[i][j] = -f_y;
force_x[j][i] = f_x;
force_y[j][i] = f_y;
}
}
for(var i = 0;i < planet_data.length; i++) {
var p = planet_data[i];
// position
p.x += del_t*p.vx;
p.y += del_t*p.vy;
// velocity
f_x = 0;
f_y = 0;
for(var j = 0;j < planet_data.length; j++) {
f_x += force_x[i][j];
f_y += force_y[i][j];
}
p.vx += del_t*f_x/p.mass - del_t*aero*p.vx;
p.vy += del_t*f_y/p.mass - del_t*aero*p.vy;
}
return planet_created;
}
update(planet_data)
del_t = 20;
setInterval(function() {
planet_created = integrate(planet_data,del_t)
update(planet_data,planet_created);
}, del_t);
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment