Compare commits

..

2 Commits

Author SHA1 Message Date
Ladd
c882749786 no extra ssh on commit 2025-12-28 22:28:08 -06:00
Ladd
a6678ced37 Revert "no extra ssh on commit"
This reverts commit 403ce4b6830bf3943c03bc772b0a0d9648b270cb.
2025-12-28 22:22:05 -06:00
5 changed files with 80 additions and 6 deletions

View File

@ -8,7 +8,7 @@ Uses `npm` for `eslint`.
TODO TODO
---- ----
[ ] Numeric Option Type [x] Numeric Option Type
[ ] Time Indicator [ ] Time Indicator
[ ] Selection Box [ ] Selection Box
[ ] Object List [ ] Object List

View File

@ -2,7 +2,6 @@ import { MassObject } from './object.js';
import { import {
MASS_CREATION_RATE, MASS_CREATION_RATE,
DISPLAY_OBJECTS_INFO, DISPLAY_OBJECTS_INFO,
GRAVITATIONAL_CONSTANT,
ZOOM_TO_FIT_PADDING, ZOOM_TO_FIT_PADDING,
} from './config.js'; } from './config.js';
@ -169,6 +168,7 @@ export class Objects {
} }
computeForces() { computeForces() {
const gravity = this.sim.getOption('param.gravity');
if (this.objects.length < 2) return; if (this.objects.length < 2) return;
this.forEachObject(obj => { this.forEachObject(obj => {
obj.forces = []; obj.forces = [];
@ -179,7 +179,7 @@ export class Objects {
const dy = (B.position.y - A.position.y); const dy = (B.position.y - A.position.y);
const dSquared = dx ** 2 + dy ** 2; const dSquared = dx ** 2 + dy ** 2;
const d = Math.sqrt(dSquared); const d = Math.sqrt(dSquared);
const F = GRAVITATIONAL_CONSTANT * A.mass * B.mass / dSquared; const F = gravity * A.mass * B.mass / dSquared;
const Fx = F * dx / d; const Fx = F * dx / d;
const Fy = F * dy / d; const Fy = F * dy / d;
A.forces.push({ x: Fx, y: Fy }); A.forces.push({ x: Fx, y: Fy });

View File

@ -47,7 +47,7 @@ div.lhg-toolbar div.lhg-tool {
border-color: #282; border-color: #282;
} }
div.lhg-tool button { div.lhg-tool button, div.lhg-tool input {
font-family: monospace; font-family: monospace;
font-size: 10pt; font-size: 10pt;
width: 6em; width: 6em;
@ -66,6 +66,10 @@ div.lhg-tool button {
margin-right: 0; margin-right: 0;
} }
div.lhg-tool input {
width: 5EM;
}
div.lhg-tool button:hover { div.lhg-tool button:hover {
background-color: #444; background-color: #444;
} }
@ -86,16 +90,24 @@ div.lhg-toolbar-header > * {
display: inline-block; display: inline-block;
} }
div.lhg-tool button.lhg-tool-info { div.lhg-tool .lhg-tool-info {
background-color: #111; background-color: #111;
border-color: #282; border-color: #282;
border-width: 0px; border-width: 0px;
} }
div.lhg-tool button.lhg-wide { div.lhg-tool .lhg-wide {
width: 12em; width: 12em;
} }
div.lhg-tool input.lhg-wide {
width: 11em;
}
div.lhg-tool .lhg-tool-info.lhg-wide {
width: 11em;
}
div.lhg-tool > div { div.lhg-tool > div {
/* border: 2px red solid; */ /* border: 2px red solid; */
} }

View File

@ -2,10 +2,12 @@
import { import {
DISPLAY_ACCELERATION_VECTORS, DISPLAY_ACCELERATION_VECTORS,
DISPLAY_VELOCITY_VECTORS, DISPLAY_VELOCITY_VECTORS,
GRAVITATIONAL_CONSTANT,
MERGE_ON_COLLIDE, MERGE_ON_COLLIDE,
PATH_TRACES_DASHED, PATH_TRACES_DASHED,
PAUSE_DURING_CREATION, PAUSE_DURING_CREATION,
PAUSE_DURING_SELECTION, PAUSE_DURING_SELECTION,
TOOL_INFO_CLASSNAME,
WIDE_CLASSNAME, WIDE_CLASSNAME,
} from '../config.js'; } from '../config.js';
import {Tool} from '../tool.js'; import {Tool} from '../tool.js';
@ -30,6 +32,11 @@ export class Options extends Tool {
items: [ items: [
{type: 'boolean', name: 'merge', title: 'Merge Masses', default: MERGE_ON_COLLIDE, wide: true}, {type: 'boolean', name: 'merge', title: 'Merge Masses', default: MERGE_ON_COLLIDE, wide: true},
] ]
}, {
type: 'group', name: 'param', title: 'Parameters',
items: [
{type: 'number', name: 'gravity', title: 'Gravity', default: GRAVITATIONAL_CONSTANT},
]
}]; }];
values = {}; values = {};
@ -62,6 +69,32 @@ export class Options extends Tool {
}); });
return button; return button;
} }
case 'number': {
const div = document.createElement('div');
const title = document.createElement('button');
const input = document.createElement('input');
const maxLength = item.maxLength || 8;
div.appendChild(title);
div.appendChild(input);
div.classList.add(WIDE_CLASSNAME);
title.classList.add(TOOL_INFO_CLASSNAME);
if (item.wide) {
// title.classList.add(WIDE_CLASSNAME);
input.classList.add(WIDE_CLASSNAME);
}
title.innerHTML = item.title;
input.value = item.default;
this.setOption(path, item.default);
input.addEventListener('input', () => {
input.value = input.value.slice(0, maxLength);
});
input.addEventListener('change', () => {
this.setOption(path, input.value);
});
return div;
}
default: default:
throw new Error('unknown option type'); throw new Error('unknown option type');
} }

View File

@ -22,19 +22,23 @@ export class Zoom extends Tool {
const zoomOut = document.createElement('button'); const zoomOut = document.createElement('button');
const zoomIn = document.createElement('button'); const zoomIn = document.createElement('button');
const zoomAll = document.createElement('button'); const zoomAll = document.createElement('button');
const zeroVelocity = document.createElement('button');
this.div.appendChild(currentScale); this.div.appendChild(currentScale);
this.div.appendChild(zoomOut); this.div.appendChild(zoomOut);
this.div.appendChild(zoomIn); this.div.appendChild(zoomIn);
this.div.appendChild(zoomAll); this.div.appendChild(zoomAll);
this.div.appendChild(zeroVelocity);
zoomAll.classList.add(WIDE_CLASSNAME); zoomAll.classList.add(WIDE_CLASSNAME);
zeroVelocity.classList.add(WIDE_CLASSNAME);
currentScale.classList.add(WIDE_CLASSNAME); currentScale.classList.add(WIDE_CLASSNAME);
currentScale.classList.add(TOOL_INFO_CLASSNAME); currentScale.classList.add(TOOL_INFO_CLASSNAME);
zoomOut.innerHTML = 'Zoom<br>Out'; zoomOut.innerHTML = 'Zoom<br>Out';
zoomIn.innerHTML = 'Zoom<br>In'; zoomIn.innerHTML = 'Zoom<br>In';
zoomAll.innerHTML = 'Zoom to Fit'; zoomAll.innerHTML = 'Zoom to Fit';
zeroVelocity.innerHTML = 'Zero Net Velocity';
currentScale.innerHTML = this.displayScaleText; currentScale.innerHTML = this.displayScaleText;
this.sim.onZoom(() => { this.sim.onZoom(() => {
@ -84,5 +88,30 @@ export class Zoom extends Tool {
}; };
this.sim.scheduleZoom({x, y}, factor, netVelocity) this.sim.scheduleZoom({x, y}, factor, netVelocity)
}); });
zeroVelocity.addEventListener('click', () => {
// Determine average momentum
const netMomentum = {x: 0, y: 0};
let totalMass = 0;
let count = 0;
this.sim.objects.forEachObject(obj => {
count++;
netMomentum.x += obj.mass * obj.velocity.x;
netMomentum.y += obj.mass * obj.velocity.y;
totalMass += obj.mass;
});
if (!count) {
return;
}
const netVelocity = {
x: netMomentum.x / totalMass,
y: netMomentum.y / totalMass,
};
// Apply offset to all object velocities
this.sim.objects.forEachObject(obj => {
obj.velocity.x -= netVelocity.x;
obj.velocity.y -= netVelocity.y;
});
});
} }
} }