gravity-rk4.js

total 0
used 0
limit 0
/* categories: gravity raw files: ../point_src/core/head.js ../point_src/pointpen.js ../point_src/pointdraw.js ../point_src/math.js ../point_src/extras.js ../point_src/point-content.js ../point_src/pointlistpen.js ../point_src/pointlist.js ../point_src/events.js ../point_src/point.js ../point_src/distances.js ../point_src/dragging.js ../point_src/stage.js ../point_src/automouse.js ../point_src/functions/springs.js ../point_src/functions/clamp.js ../point_src/setunset.js ../point_src/stroke.js --- moved to functions/springs */ /** * @param {Point[]} points - Array of Point objects * @param {number} G - Gravitational constant * @param {number} dt - Timestep (e.g., 0.1, 0.01, etc.) */ // 1) Define your initial points (like your old "Point" objects) const points = new PointList( { x: 500, y: 300, vx: 0.2, vy: 0.2, mass: 10, radius: 10 }, { x: 400, y: 340, vx: 0.0, vy: 0.0, mass: 40, radius: 40 }, { x: 150, y: 200, vx: 0.7, vy: 0.1, mass: 5, radius: 5 }, // ... etc ).cast() // 2) Convert to an array-based state const N = points.length; const masses = new Array(N); const state = new Float64Array(4 * N); for (let i = 0; i < N; i++) { masses[i] = points[i].mass; // store mass state[4 * i + 0] = points[i].x; // x state[4 * i + 1] = points[i].y; // y state[4 * i + 2] = points[i].vx; // vx state[4 * i + 3] = points[i].vy; // vy } // 3) Parameters const G = 1; const dt = 1; // time step function animate() { // 4) Update the state using RK4 const newState = rk4Step(state, masses, G, dt); // 5) Copy newState back to 'state' state.set(newState); // 6) (Optional) Update your 'points' array if you want to draw them for (let i = 0; i < N; i++) { points[i].x = state[4 * i + 0]; points[i].y = state[4 * i + 1]; points[i].vx = state[4 * i + 2]; points[i].vy = state[4 * i + 3]; } // 7) Draw your points on canvas (or console, etc.) // renderPoints(points); } class MainStage extends Stage { // canvas = document.getElementById('playspace'); canvas = 'playspace' mounted(){ this.points = points this.dragging.add(...this.points) } // onDragStart(ev, p) { // this.dragPoint = p // } // onDragEnd(ev, p) { // this.dragPoint = undefined // } onWheel(ev, p) { p.mass = p.radius } draw(ctx){ this.clear(ctx) // updatePoints(this.points, 1, this.timestep); // Start animate(); points.pen.indicators(ctx) } } /** * Compute the derivatives of the system at a given state. * @param {Float64Array|number[]} state - The current system state [x0, y0, vx0, vy0, x1, y1, vx1, vy1, ...] * @param {number[]} masses - Array of masses for each body * @param {number} G - Gravitational constant * @returns {Float64Array} - The derivatives of the state (same length as state) */ function computeDerivatives(state, masses, G) { const N = masses.length; const derivatives = new Float64Array(4 * N); // For convenience, we can first compute all accelerations from pairwise forces const ax = new Float64Array(N); const ay = new Float64Array(N); // Pairwise gravitational interaction for (let i = 0; i < N; i++) { const xi = state[4 * i + 0]; const yi = state[4 * i + 1]; for (let j = i + 1; j < N; j++) { const xj = state[4 * j + 0]; const yj = state[4 * j + 1]; const dx = xj - xi; const dy = yj - yi; const distSq = dx * dx + dy * dy; const dist = Math.sqrt(distSq) || 1e-8; // avoid divide-by-zero // F = G*m1*m2 / r^2 const F = (G * masses[i] * masses[j]) / distSq; // Force direction const Fx = F * (dx / dist); const Fy = F * (dy / dist); // a = F/m ax[i] += Fx / masses[i]; ay[i] += Fy / masses[i]; ax[j] -= Fx / masses[j]; ay[j] -= Fy / masses[j]; } } // Now fill in derivatives for each body: (dx/dt, dy/dt, dvx/dt, dvy/dt) for (let i = 0; i < N; i++) { const vx = state[4 * i + 2]; const vy = state[4 * i + 3]; // dx/dt = vx derivatives[4 * i + 0] = vx; // dy/dt = vy derivatives[4 * i + 1] = vy; // dvx/dt = ax[i] derivatives[4 * i + 2] = ax[i]; // dvy/dt = ay[i] derivatives[4 * i + 3] = ay[i]; } return derivatives; } /** * Runge-Kutta 4 integrator: one step from state(t) to state(t + dt) * @param {Float64Array|number[]} state - The current system state * @param {number[]} masses - Mass array * @param {number} G - Gravitational constant * @param {number} dt - Time step * @returns {Float64Array} - The new state after time dt */ function rk4Step(state, masses, G, dt) { const N = masses.length; const k1 = computeDerivatives(state, masses, G); // For k2, we evaluate at (state + dt/2 * k1) const temp2 = new Float64Array(4 * N); for (let i = 0; i < 4 * N; i++) { temp2[i] = state[i] + 0.5 * dt * k1[i]; } const k2 = computeDerivatives(temp2, masses, G); // For k3, we evaluate at (state + dt/2 * k2) const temp3 = new Float64Array(4 * N); for (let i = 0; i < 4 * N; i++) { temp3[i] = state[i] + 0.5 * dt * k2[i]; } const k3 = computeDerivatives(temp3, masses, G); // For k4, we evaluate at (state + dt * k3) const temp4 = new Float64Array(4 * N); for (let i = 0; i < 4 * N; i++) { temp4[i] = state[i] + dt * k3[i]; } const k4 = computeDerivatives(temp4, masses, G); // Combine const newState = new Float64Array(4 * N); for (let i = 0; i < 4 * N; i++) { newState[i] = state[i] + (dt / 6) * (k1[i] + 2*k2[i] + 2*k3[i] + k4[i]); } return newState; } stage = MainStage.go(/*{ loop: true }*/)
Run
Meta Data
imports ()
files ('../point_src/core/head.js', '../point_src/pointpen.js', '../point_src/pointdraw.js', '../point_src/math.js', '../point_src/extras.js', '../point_src/point-content.js', '../point_src/pointlistpen.js', '../point_src/pointlist.js', '../point_src/events.js', '../point_src/point.js', '../point_src/distances.js', '../point_src/dragging.js', '../point_src/stage.js', '../point_src/automouse.js', '../point_src/functions/springs.js', '../point_src/functions/clamp.js', '../point_src/setunset.js', '../point_src/stroke.js')
unused_keys ('title',)
unknown_keys ('categories',)
categories ['', 'gravity', 'raw']
filepath_exists True
path gravity-rk4.js
filepath gravity-rk4.js
clean_files ('../point_src/core/head.js', '../point_src/pointpen.js', '../point_src/pointdraw.js', '../point_src/math.js', '../point_src/extras.js', '../point_src/compass.js', '../point_src/center.js', '../point_src/point-content.js', '../point_src/pointlistpen.js', '../point_src/pointlistdraw.js', '../point_src/pointlistgradient.js', '../point_src/pointlistshape.js', '../point_src/pointlistgenerator.js', '../point_src/unpack.js', '../point_src/pointlist.js', '../point_src/events.js', '../point_src/relative-xy.js', '../point_src/pointcast.js', '../point_src/point.js', '../point_src/distances.js', '../point_src/protractor.js', '../point_src/text/beta.js', '../point_src/dragging.js', '../point_src/stage-resize.js', '../point_src/functions/resolve.js', '../point_src/stage.js', '../point_src/automouse.js', '../point_src/functions/springs.js', '../point_src/functions/clamp.js', '../point_src/setunset.js', '../point_src/stroke.js')
markdown {'html': '<p>moved to functions/springs</p>', 'content': 'categories:\n gravity\n raw\nfiles:\n ../point_src/core/head.js\n ../point_src/pointpen.js\n ../point_src/pointdraw.js\n ../point_src/math.js\n ../point_src/extras.js\n ../point_src/point-content.js\n ../point_src/pointlistpen.js\n ../point_src/pointlist.js\n ../point_src/events.js\n ../point_src/point.js\n ../point_src/distances.js\n ../point_src/dragging.js\n ../point_src/stage.js\n ../point_src/automouse.js\n ../point_src/functions/springs.js\n ../point_src/functions/clamp.js\n ../point_src/setunset.js\n ../point_src/stroke.js\n---\n\nmoved to functions/springs'}