diff --git a/Readme.md b/Readme.md
index 1ff4a50..83466e1 100644
--- a/Readme.md
+++ b/Readme.md
@@ -8,8 +8,7 @@ Uses `npm` for `eslint`.
Screenshots
-----------
-
-
+
TODO
----
@@ -31,10 +30,7 @@ TODO
- [ ] Undo "Clear Traces" Action
- [ ] Undo "Reset
- [ ] Time Control: Reverse Time
-- [x] Save to LocalStorage
- [ ] Lossy Rescaling To Widen Zoom (Handling overflow/underflow)
- [ ] Track farthest reaches, min/max in each dimension (x, y)
-- [x] Compute Net Angular Momentum
-- [ ] Display Net Angular Momentum
- [ ] Calculate Work as FxD as measure of energy flux
- [ ] Option to automatically slow time when energy flux is greater
diff --git a/gravity-simulator-4.png b/gravity-simulator-4.png
new file mode 100644
index 0000000..5aa1d53
Binary files /dev/null and b/gravity-simulator-4.png differ
diff --git a/object.js b/object.js
index b958804..ef49ff6 100644
--- a/object.js
+++ b/object.js
@@ -180,22 +180,19 @@ export class MassObject {
let velocity = {x: vx, y: vy};
if (isSelected) {
const pointerV = this.sim.pointer.latestVelocity;
- const scale = this.sim.display.scale;
// const panning = this.sim.panning?.velocity ?? {x: 0, y: 0};
// velocity.x = vx + (pointerV.x + panning.x) * scale;
// velocity.y = vy + (pointerV.y + panning.y) * scale;
- velocity.x = vx + pointerV.x * scale;
- velocity.y = vy + pointerV.y * scale;
+ velocity.x = vx + pointerV.x / this.sim.timeScale;
+ velocity.y = vy + pointerV.y / this.sim.timeScale;
}
- const speed = Math.sqrt(velocity.x ** 2, velocity.y ** 2);
+ const speed = Math.sqrt(velocity.x ** 2, velocity.y ** 2) / this.sim.display.scale;
const arrowDirection = Math.atan2(velocity.y, velocity.x);
// Prevent negative numbers by adding 1
- const arrowLength = Math.log(speed + 1) * vecScale;
+ // TODO: Make logarithmic vector length scale optional
+ const arrowLength = Math.log10(speed + 1) * vecScale + radius;
const endVx = x + arrowLength * Math.cos(arrowDirection);
const endVy = y + arrowLength * Math.sin(arrowDirection);
- if (sim.getOption('debug.panningInfo')) {
- console.log('velocity', {vecScale, isSelected, velocity, speed, arrowDirection, arrowLength, endVx, endVy});
- }
const style = VELOCITY_VECTOR_COLOR === 'object color' ?
`rgb(${r}, ${g}, ${b})` : VELOCITY_VECTOR_COLOR;
sim.display.drawArrow(x, y, endVx, endVy, {
@@ -209,11 +206,13 @@ export class MassObject {
// Draw arrow for acceleration
if (sim.getOption('display.acceleration')) {
- const vecScale = this.sim.getOption('param.accelerationScale');
- const accelerationMagnitude = Math.sqrt(acceleration.x ** 2 + acceleration.y ** 2);
+ const vecScale = this.sim.getOption('display.accelerationScale');
+ const accelerationMagnitude = Math.sqrt(acceleration.x ** 2 + acceleration.y ** 2) /
+ this.sim.display.scale;
const arrowDirection = Math.atan2(acceleration.y, acceleration.x);
- // Prevent negative numbers by adding e
- const arrowLength = Math.log(accelerationMagnitude + 1) * vecScale / this.sim.display.scale;
+ // Prevent negative numbers by adding 1
+ const arrowLength = Math.log10(accelerationMagnitude + 1) * vecScale + radius;
+ //const arrowLength = accelerationMagnitude * vecScale;
const endAx = x + arrowLength * Math.cos(arrowDirection);
const endAy = y + arrowLength * Math.sin(arrowDirection);
const style = ACCELERATION_VECTOR_COLOR === 'object color' ?
diff --git a/sim-options.js b/sim-options.js
index dd9dd07..446a312 100644
--- a/sim-options.js
+++ b/sim-options.js
@@ -4,12 +4,12 @@ export const simOptions = {
selection: ['Pause While Selecting', 'boolean', true],
},
display: {
- traces: ['Path Trace', 'boolean', true],
+ traces: ['Path Traces', 'boolean', true],
dashedTraces: ['Dashed', 'boolean', false, {tall: true}],
- velocity: ['Velocity Vector', 'boolean', true],
- acceleration: ['Accel Vector', 'boolean', true],
- velocityScale: ['Velocity
Vec Scale', 'number', 20],
- accelerationScale: ['Accel
Vec Scale', 'number', 20],
+ velocity: ['Velocity Vectors', 'boolean', true],
+ acceleration: ['Accel Vectors', 'boolean', true],
+ velocityScale: ['Velocity
Vec Scale', 'number', 80],
+ accelerationScale: ['Accel
Vec Scale', 'number', 800],
},
collision: {
merge: ['Merge Masses
on Collision', 'boolean', true, {wide: true}],
@@ -18,7 +18,6 @@ export const simOptions = {
gravity: ['Gravity', 'number', 1],
timeScale: ['Time Scale', 'number', 0.1],
massCreationRate: ['Mass Creation Rate', 'number', 1],
- massAcceleration: ['Mass Rate Accel', 'boolean', false, {wide: true}],
},
debug: {
objectsInfo: ['Objects Info', 'boolean', false],
diff --git a/system.js b/system.js
index cd57812..c88638e 100644
--- a/system.js
+++ b/system.js
@@ -157,8 +157,8 @@ export class System {
// Convert pointer velocity to simulation scale
// Including time scale - if time is slow, our motion is relatively faster
const pointer = {...this.sim.pointer.latestVelocity};
- obj.velocity.x = pointer.x / this.sim.display.scale;
- obj.velocity.y = pointer.y / this.sim.display.scale;
+ obj.velocity.x = pointer.x / this.sim.display.scale / this.sim.timeScale;
+ obj.velocity.y = pointer.y / this.sim.display.scale / this.sim.timeScale;
if (this.sim.panning?.velocity) {
obj.velocity.x += this.sim.panning.velocity.x;
obj.velocity.y += this.sim.panning.velocity.y;
@@ -239,12 +239,7 @@ export class System {
if (this.creatingObject !== undefined) {
const obj = this.objects[this.creatingObject];
- let massCreationRate = this.sim.getOption('param.massCreationRate');
- // Mass creation rate acceleration
- if (this.sim.getOption('param.massAcceleration')) {
- // TODO: Separate parameter for mass creation acceleration rate
- massCreationRate *= obj.rawAge;
- }
+ let massCreationRate = this.sim.getOption('param.massCreationRate') / this.sim.display.scale;
// Keep consistent time scale
obj.mass += massCreationRate * elapsedTime / this.sim.timeScale;
}
diff --git a/tool/utility.js b/tool/utility.js
index 46dccd6..ae5a5d3 100644
--- a/tool/utility.js
+++ b/tool/utility.js
@@ -39,7 +39,6 @@ export class UtilityTool extends Tool {
constructor(container) {
super(container);
- const zeroVelocity = document.createElement('button');
const clearTraces = document.createElement('button');
const currentTime = document.createElement('button');
const clearDebug = document.createElement('button');
@@ -47,39 +46,18 @@ export class UtilityTool extends Tool {
this.currentTimeEl = currentTime;
this.div.appendChild(currentTime);
- this.div.appendChild(zeroVelocity);
this.div.appendChild(clearTraces);
this.div.appendChild(clearDebug);
- zeroVelocity.classList.add(WIDE_CLASSNAME);
clearTraces.classList.add(WIDE_CLASSNAME);
currentTime.classList.add(TOOL_INFO_CLASSNAME);
currentTime.classList.add(WIDE_CLASSNAME);
clearDebug.classList.add(WIDE_CLASSNAME);
- zeroVelocity.innerHTML = 'Zero Momentum';
clearTraces.innerHTML = 'Clear Traces';
currentTime.innerHTML = this.timeText;
clearDebug.innerHTML = 'Clear Debug';
- zeroVelocity.addEventListener('click', () => {
- // Determine center of mass and average momentum
- const { totalMass, netMomentum } = this.sim.system.computeSystemCenter();
- const netVelocity = {
- x: netMomentum.x / totalMass,
- y: netMomentum.y / totalMass,
- };
-
- // Apply offset to all object velocities
- this.sim.system.forEachObject(obj => {
- obj.velocity.x -= netVelocity.x;
- obj.velocity.y -= netVelocity.y;
- });
-
- // Cancel panning
- this.sim.panning = undefined;
- });
-
clearTraces.addEventListener('click', () => {
// Obliterate object histories
this.sim.system.forEachObject(obj => {
diff --git a/tool/zoom.js b/tool/zoom.js
index c4b441b..0175640 100644
--- a/tool/zoom.js
+++ b/tool/zoom.js
@@ -3,7 +3,6 @@ import {
ZOOM_IN_FACTOR,
ZOOM_OUT_FACTOR,
WIDE_CLASSNAME,
- TALL_CLASSNAME,
TOOL_INFO_CLASSNAME,
} from '../config.js';
@@ -19,21 +18,22 @@ export class Zoom extends Tool {
const zoomOut = document.createElement('button');
const zoomIn = document.createElement('button');
const zoomAll = document.createElement('button');
+ const zeroVelocity = document.createElement('button');
this.div.appendChild(currentScale);
this.div.appendChild(zoomOut);
this.div.appendChild(zoomIn);
this.div.appendChild(zoomAll);
+ this.div.appendChild(zeroVelocity);
currentScale.classList.add(WIDE_CLASSNAME);
currentScale.classList.add(TOOL_INFO_CLASSNAME);
- zoomAll.classList.add(WIDE_CLASSNAME);
- zoomAll.classList.add(TALL_CLASSNAME);
currentScale.innerHTML = this.displayScaleText;
zoomOut.innerHTML = 'Zoom
Out';
zoomIn.innerHTML = 'Zoom
In';
zoomAll.innerHTML = 'Zoom to Fit';
+ zeroVelocity.innerHTML = 'Zero Momentum';
this.sim.onZoom(() => {
currentScale.innerHTML = this.displayScaleText;
@@ -60,7 +60,7 @@ export class Zoom extends Tool {
const y = (box.start.y + box.end.y) / 2;
const widthRatio = Math.abs(box.start.x - box.end.x) / this.sim.display.width;
const heightRatio = Math.abs(box.start.y - box.end.y) / this.sim.display.height;
- const ratio = Math.max(widthRatio, heightRatio) * 2.5;
+ const ratio = Math.max(widthRatio, heightRatio) * 4;
const factor = Math.ceil(Math.log2(1 / ratio));
// Determine average momentum and set panning velocity to match
@@ -71,5 +71,24 @@ export class Zoom extends Tool {
};
this.sim.scheduleZoom({x, y}, factor, netVelocity)
});
+
+ zeroVelocity.addEventListener('click', () => {
+ // Determine center of mass and average momentum
+ const { totalMass, netMomentum } = this.sim.system.computeSystemCenter();
+ const netVelocity = {
+ x: netMomentum.x / totalMass,
+ y: netMomentum.y / totalMass,
+ };
+
+ // Apply offset to all object velocities
+ this.sim.system.forEachObject(obj => {
+ obj.velocity.x -= netVelocity.x;
+ obj.velocity.y -= netVelocity.y;
+ });
+
+ // Cancel panning
+ this.sim.panning = undefined;
+ });
+
}
}