You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

164 lines
5.6 KiB

2 years ago
class Manager {
1 year ago
pendula: Pendulum[] = []
2 years ago
timescale: number;
gravity: number;
playing = false;
2 years ago
static SubSteps: number;
static Size = 20;
init(){
// @ts-ignore
const {createApp} = Vue;
createApp({
data() {
return {
gravity: 0,
timescale: 0,
subSteps: 0,
playingBtn: "play"
};
},
watch: {
gravity(newGravity: number) {
manager.gravity = newGravity;
},
timescale(newScale: number){
manager.timescale = newScale;
},
subSteps(newSteps: number){
Manager.SubSteps = newSteps;
}
},
methods: {
togglePlay(){
manager.playing = !manager.playing;
this.playingBtn = manager.playing ? "pause" : "play";
},
resetSimulationControls(){
this.gravity = 9.81;
this.timescale = 1;
this.subSteps = 30;
}
},
mounted() {
this.resetSimulationControls();
},
name: "Simulation"
}).mount("#simulation");
let app = createApp({
data(){
return {
segmentCount: 1,
maxSegmentCount: 30,
masses: [],
lengths: [],
startAngle: 90,
color: "#ffffff",
rainbow: false,
multiple: false,
pendulumCount: 10,
changeProperty: "angle",
changeAmount: 0.0005,
changeIndex: 0
}
},
methods: {
add() {
if (this.multiple){
let changeAmount = this.changeAmount;
let changeIndex = this.changeIndex;
let color = p.color(this.color);
p.colorMode(p.HSB, 100);
for (let i = 0; i < this.pendulumCount; i++){
let M = this.masses.slice(0, this.segmentCount);
let L = this.lengths.slice(0, this.segmentCount);
let startAngle = this.startAngle;
let progress = i / this.pendulumCount - 0.5;
switch (this.changeProperty){
case "angle":
startAngle += progress * 360 * changeAmount;
break;
case "mass":
M[changeIndex] += progress * M[changeIndex] * changeAmount;
break;
case "length":
L[changeIndex] += progress * L[changeIndex] * changeAmount;
break;
}
if (this.rainbow){
let hue = (progress + 0.5) * 100;
color = p.color(hue, 100, 100);
}
let newPendulum = new Pendulum(M, L, color, startAngle);
manager.pendula.push(newPendulum);
}
p.colorMode(p.RGB);
} else {
let M = this.masses.slice(0, this.segmentCount);
let L = this.lengths.slice(0, this.segmentCount);
let color = p.color(this.color);
let newPendulum = new Pendulum(M, L, color, this.startAngle);
manager.pendula.push(newPendulum);
}
1 year ago
},
deleteAll(){
if (confirm("Delete all pendula?")){
1 year ago
manager.pendula.splice(0);
}
},
resetMasses(){
for (let i = 0; i < this.maxSegmentCount; i++)
this.masses[i] = 1;
},
resetLengths() {
for (let i = 0; i < this.maxSegmentCount; i++)
this.lengths[i] = 1;
},
normalize(){
let L: [number] = this.lengths;
let sum = L.slice(0, this.segmentCount).reduce((p, n) => p + n);
let maxLength = Manager.Size / 2;
let factor = maxLength / sum;
for (let i = 0; i < this.segmentCount; i++)
this.lengths[i] *= factor;
}
},
mounted() {
this.resetMasses();
this.resetLengths();
},
name: "Add Pendula"
});
app.config.globalProperties.$filters = {
round(value: number, n: number){
if (!value)
return "0";
return +value.toFixed(n);
}
}
app.mount("#preparation");
2 years ago
}
update(){
if (this.playing) {
const h = this.timescale / Math.max(p.frameRate(), 30);
1 year ago
this.pendula.forEach(p => p.update(h));
}
2 years ago
}
draw(){
p.push()
p.translate(p.width / 2, p.height / 2);
1 year ago
this.pendula.forEach(p => p.draw());
2 years ago
p.pop();
}
}