-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Split files into modules; added gravitation between all bodies
- Loading branch information
Showing
6 changed files
with
328 additions
and
207 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,114 @@ | ||
const MIN_BODY_RADIUS = 5; | ||
const MAX_BODY_RADIUS = 25; | ||
const BASE_TIME_SCALE = 86400; | ||
let timeScale = 5; | ||
let numToRun = 1000; | ||
|
||
define(function () { | ||
|
||
function CanvasDisplay(canvas, solarSystem) { | ||
|
||
this.canvas = canvas; | ||
this.ctx = canvas.getContext("2d"); | ||
this.solarSystem = solarSystem; | ||
|
||
this.ctx.scale(-1, 1); | ||
this.ctx.translate(-canvas.width / 2, canvas.height / 2); | ||
this.ctx.rotate(Math.PI); | ||
}; | ||
|
||
CanvasDisplay.prototype._runAnimation = function (frameFunc) { | ||
var lastTime = null; | ||
|
||
function frame(time) { | ||
var stop = false; | ||
if (lastTime != null) { | ||
var timeStep = (time - lastTime) / 1000 * BASE_TIME_SCALE * Math.pow(timeScale, 2); | ||
stop = frameFunc(timeStep) === false; | ||
} | ||
lastTime = time; | ||
if (!stop) | ||
requestAnimationFrame(frame); | ||
} | ||
requestAnimationFrame(frame); | ||
} | ||
|
||
CanvasDisplay.prototype._drawBody = function (body) { | ||
let ctx = this.ctx; | ||
let canvas = this.canvas; | ||
|
||
ctx.beginPath(); | ||
|
||
let radius, color; | ||
switch (body.name) { | ||
case "sun": | ||
radius = 25; | ||
color = "yellow"; | ||
break; | ||
case "earth": | ||
radius = 10; | ||
color = "blue"; | ||
break; | ||
case "moon": | ||
radius = 3; | ||
color = "purple"; | ||
break; | ||
default: | ||
radius = 5; | ||
color = "black"; | ||
} | ||
|
||
// Calculate unit vector | ||
let distance = body.position.magnitude(); | ||
let position = body.position.times(Math.min(canvas.height, canvas.width) / 5); | ||
|
||
ctx.beginPath(); | ||
ctx.fillStyle = color; | ||
ctx.arc(position.x, position.y, Math.max(MIN_BODY_RADIUS, radius), 0, 2 * Math.PI); | ||
ctx.fill(); | ||
}; | ||
|
||
CanvasDisplay.prototype.run = function () { | ||
|
||
let last = 0; | ||
let numTimes = 0; | ||
|
||
let solarSystem = this.solarSystem; | ||
let ctx = this.ctx; | ||
let canvas = this.canvas; | ||
|
||
this._runAnimation(function (step) { | ||
|
||
// Update physics | ||
solarSystem.update(last, step); | ||
|
||
// Clear Canvas | ||
ctx.fillStyle = 'gray'; | ||
ctx.fillRect(-canvas.width / 2, -canvas.height / 2, canvas.width, canvas.height); | ||
|
||
solarSystem.forEach(function (body) { | ||
this._drawBody(body); | ||
}, this); | ||
|
||
ctx.strokeStyle = "red"; | ||
ctx.beginPath(); | ||
ctx.moveTo(25, 0); | ||
ctx.lineTo(-25, 0); | ||
ctx.stroke(); | ||
ctx.closePath(); | ||
ctx.beginPath(); | ||
ctx.moveTo(0, 25); | ||
ctx.lineTo(0, -25); | ||
ctx.stroke(); | ||
|
||
last += step; | ||
numTimes++; | ||
if (numTimes >= numToRun) { | ||
console.log('All done!'); | ||
return false; | ||
} | ||
}.bind(this)); | ||
}; | ||
|
||
return CanvasDisplay; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,175 @@ | ||
define(["Vector"], function (Vector) { | ||
|
||
const AU = 149597870700.0; // m | ||
const SUN_MASS = 1.989e30 / AU; // kg | ||
const EARTH_MASS = 5.97e24 / AU; // kg | ||
const MOON_MASS = 7.3476e22 / AU; // kg | ||
const JUPITER_MASS = 1.898e27 / AU; // kg | ||
const EARTH_TO_SUN = 149.6e9 / AU; // m | ||
const MOON_TO_EARTH = 0.3633e9 / AU; // m | ||
const UNIVERSAL_GRAVITY = 6.674e-11 / Math.pow(AU, 2); // N⋅m^2/kg^2 | ||
|
||
function SolarSystem() { | ||
this.bodies = []; | ||
}; | ||
|
||
SolarSystem.prototype.seed = function () { | ||
|
||
let sun = this.addBody("sun", SUN_MASS); | ||
let earth = this.addBody("earth", EARTH_MASS); | ||
let moon = this.addBody("moon", MOON_MASS); | ||
|
||
earth.position = new Vector(0, EARTH_TO_SUN, 0); | ||
earth.velocity = new Vector(-Math.sqrt(UNIVERSAL_GRAVITY * (SUN_MASS + EARTH_MASS) / EARTH_TO_SUN), 0, 0).times(1); | ||
earth.momentum = earth.velocity.times(earth.mass); | ||
earth.updateMomentum(earth.momentum); | ||
|
||
moon.position = new Vector(0, EARTH_TO_SUN + 10 * MOON_TO_EARTH, 0); | ||
moon.velocity = new Vector(-Math.sqrt(UNIVERSAL_GRAVITY * (SUN_MASS + MOON_MASS) / (EARTH_TO_SUN + 2 * MOON_TO_EARTH)), 0, 0).times(1); | ||
moon.momentum = moon.velocity.times(moon.mass); | ||
moon.updateMomentum(moon.momentum); | ||
}; | ||
|
||
// Calculate a new 'CoM' given all of the current bodies and update the | ||
// coordinates of all current bodies. | ||
SolarSystem.prototype.update = function (t, dt) { | ||
|
||
this.updateBarycenter(); | ||
this.updateEphemeris(t, dt); | ||
|
||
}; | ||
|
||
// Calcluate the barycenter of the system and adjust the coordinate | ||
// system accordingly. | ||
SolarSystem.prototype.updateBarycenter = function () { | ||
let upper = this.bodies.reduce(function (prev, current) { | ||
return prev.plus(current.position.times(current.mass)); | ||
}, new Vector(0, 0, 0)); | ||
|
||
let lower = this.bodies.reduce(function (prev, current) { | ||
return prev + current.mass; | ||
}, 0); | ||
|
||
let newCenterOfMass = upper.times(-1 / lower); | ||
|
||
// TBD: Should velocity and momentum be adjusted here, or just position? | ||
this.bodies.forEach(function (body) { | ||
body.position = body.position.plus(newCenterOfMass); | ||
body.velocity = body.velocity.plus(newCenterOfMass); | ||
body.momentum = body.momentum.plus(newCenterOfMass); | ||
}); | ||
}; | ||
|
||
SolarSystem.prototype.updateEphemeris = function (t, dt) { | ||
|
||
let updates = new Map(); | ||
let bodies = this.bodies; | ||
|
||
bodies.forEach(function (body) { | ||
|
||
let attractors = bodies.filter(function (b) { | ||
return b !== body | ||
}); | ||
let changes = integrate(body, attractors, t, dt); | ||
|
||
updates.set(body, changes); | ||
}); | ||
|
||
bodies.forEach(function (body) { | ||
|
||
let changes = updates.get(body); | ||
body.position = body.position.plus(changes["dxdt"]); | ||
body.updateMomentum(body.momentum.plus(changes["dpdt"])); | ||
}) | ||
}; | ||
|
||
SolarSystem.prototype.forEach = function (each, context) { | ||
this.bodies.forEach(each, context); | ||
}; | ||
|
||
SolarSystem.prototype.addBody = function (name, mass) { | ||
let body = new Body(name, mass); | ||
this.bodies.push(body); | ||
return body; | ||
}; | ||
|
||
function Body(name, mass) { | ||
this.name = name; | ||
this.mass = mass; | ||
this.inverseMass = 1 / mass; | ||
this.position = new Vector(0, 0, 0); | ||
this.velocity = new Vector(0, 0, 0); | ||
this.momentum = new Vector(0, 0, 0); | ||
}; | ||
|
||
Body.prototype.clone = function () { | ||
let b = new Body(this.name, this.mass); | ||
return b; | ||
}; | ||
|
||
Body.prototype.updateMomentum = function (momentum) { | ||
this.momentum = momentum; | ||
this.velocity = momentum.times(this.inverseMass); | ||
|
||
// let u = UNIVERSAL_GRAVITY * this.primary.mass; | ||
// | ||
// //https://en.wikipedia.org/wiki/Orbital_eccentricity | ||
// //https://en.wikipedia.org/wiki/Eccentricity_vector | ||
// //e = |eccentricity_vector| | ||
// | ||
// let orbitalEnergy = Math.pow(this.velocity.magnitude(), 2) / 2 - | ||
// (u / this.position.magnitude()); | ||
// | ||
// //let specificRelativeAngularMomentum = | ||
// | ||
// this.semiMajorAxis = -u / (2 * orbitalEnergy); | ||
//this.eccentricity = Math.sqrt(1 + (2 * orbitalEnergy * Math.pow(specificRelativeAngularMomentum, 2) / Math.pow(UNIVERSAL_GRAVITY * this.primary.mass, 2))) | ||
} | ||
|
||
function force(body, attractors, t) { | ||
return attractors.reduce(function (prev, attractor) { | ||
|
||
let r = attractor.position.plus(body.position.times(-1)); | ||
let F = r.times(UNIVERSAL_GRAVITY * body.mass * attractor.mass / Math.pow(r.magnitude(), 3)); | ||
return prev.plus(F); | ||
|
||
}, new Vector(0, 0, 0)); | ||
} | ||
|
||
function Derivitives() { | ||
this.dx = new Vector(0, 0, 0); | ||
this.dp = new Vector(0, 0, 0); | ||
}; | ||
|
||
function evaluate(body, attractors, t, dt, changes) { | ||
|
||
let updatedBody = body.clone(); | ||
updatedBody.position = body.position.plus(changes.dx.times(dt)); | ||
updatedBody.updateMomentum(body.momentum.plus(changes.dp.times(dt))); | ||
|
||
let derivitives = new Derivitives(); | ||
derivitives.dx = updatedBody.velocity; | ||
derivitives.dp = force(updatedBody, attractors, t + dt); | ||
return derivitives; | ||
} | ||
|
||
function integrate(body, attractors, t, dt) { | ||
|
||
let a, b, c, d; | ||
|
||
a = evaluate(body, attractors, t, 0, new Derivitives()); | ||
b = evaluate(body, attractors, t, dt * 0.5, a); | ||
c = evaluate(body, attractors, t, dt * 0.5, b); | ||
d = evaluate(body, attractors, t, dt, c); | ||
|
||
let dxdt = (a.dx.plus(b.dx.plus(c.dx).times(2.0)).plus(d.dx)).times(1.0 / 6.0); | ||
let dpdt = (a.dp.plus(b.dp.plus(c.dp).times(2.0)).plus(d.dp)).times(1.0 / 6.0); | ||
|
||
return { | ||
dxdt: dxdt.times(dt), | ||
dpdt: dpdt.times(dt) | ||
}; | ||
}; | ||
|
||
return SolarSystem; | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
function Vector(x, y, z) { | ||
this.x = x; | ||
this.y = y; | ||
this.z = z; | ||
}; | ||
|
||
Vector.prototype.plus = function (other) { | ||
return new Vector(this.x + other.x, this.y + other.y, this.z + other.z); | ||
}; | ||
|
||
Vector.prototype.times = function (factor) { | ||
return new Vector(this.x * factor, this.y * factor, this.z * factor); | ||
}; | ||
|
||
Vector.prototype.magnitude = function (other) { | ||
if (!other) other = new Vector(0, 0, 0); | ||
|
||
return Math.sqrt( | ||
Math.pow(this.x - other.x, 2) + | ||
Math.pow(this.y - other.y, 2) + | ||
Math.pow(this.z - other.z, 2)); | ||
}; | ||
|
||
// Export Vector | ||
define(function () { | ||
return Vector; | ||
}); |
Oops, something went wrong.