diff --git a/Cargo.toml b/Cargo.toml index 499a453..5a8cd2f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "solar-sim" -version = "0.3.1" +version = "0.4.0" authors = ["Ben Plate "] edition = "2018" description = "Physics simulator written in Rust WASM for use in Solar Sim website" diff --git a/rust-src/lib.rs b/rust-src/lib.rs index ca090fb..db797d5 100644 --- a/rust-src/lib.rs +++ b/rust-src/lib.rs @@ -3,7 +3,6 @@ extern crate lazy_static; mod utils; -use std::ptr; use std::sync::RwLock; use wasm_bindgen::prelude::*; use js_sys::Array; @@ -15,10 +14,11 @@ use js_sys::Array; static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; const BIG_G: f64 = 0.00000000006674; -const TIME_STEP: f64 = 1.0; lazy_static! { - static ref UNIVERSE: RwLock>> = RwLock::new(vec![]); + static ref UNIVERSE: RwLock> = RwLock::new(vec![]); + static ref TIME_STEP: RwLock = RwLock::new(0.2); + static ref NUM_SIMS_PER_STEP: RwLock = RwLock::new(5); } #[derive(Clone, Copy)] @@ -27,71 +27,62 @@ pub struct Vector2D { y: f64, } -pub struct Body<'a> { +#[derive(Clone, Copy)] +pub struct Body { mass: f64, position: Vector2D, velocity: Vector2D, - scene: &'a RwLock>>, } -impl Body<'_> { - fn next_velocity(&self) -> Vector2D { +impl Body { + fn next_velocity(&mut self, uni: &Vec) { if self.mass.abs() < 0.000001 { - return self.velocity; + return; } - let mut out: Vector2D = self.velocity; + let ts = *(TIME_STEP.read().unwrap()); - let uni = self.scene.read().unwrap(); for i in 0..uni.len() { - if !ptr::eq(&uni[i], self) && uni[i].mass.abs() > 0.000001 { + if uni[i].mass.abs() > 0.000001 { let dx = self.position.x - uni[i].position.x; let dy = self.position.y - uni[i].position.y; + let dist = dx.powf(2.0) + dy.powf(2.0); + if dist < 0.0001 { continue; } + let angle = dy.atan2(dx); - let delta_v = BIG_G * uni[i].mass / (dx.powf(2.0) + dy.powf(2.0)) * TIME_STEP; // (G(m1)(m2)/d^2) / m1 * t = G(m2)/d^2 * t = at = delta_v + let delta_v = (BIG_G * uni[i].mass / dist) * ts; // (G(m1)(m2)/d^2) / m1 * t = G(m2)/d^2 * t = at = delta_v - out.x += delta_v * -angle.cos(); - out.y += delta_v * -angle.sin(); + self.velocity.x += delta_v * -angle.cos(); + self.velocity.y += delta_v * -angle.sin(); } } - - return out; } - fn next_position(&self) -> Vector2D { - return Vector2D { x: self.position.x + self.velocity.x * TIME_STEP, y: self.position.y + self.velocity.y * TIME_STEP }; // x_new = x_old + vt + fn next_position(&mut self) { + let ts = *(TIME_STEP.read().unwrap()); + + self.position.x += self.velocity.x * ts; + self.position.y += self.velocity.y * ts; } } #[wasm_bindgen] pub fn step_time() { - let mut next_velocities: Vec = vec![]; - let mut next_positions: Vec = vec![]; - - { - let uni = UNIVERSE.read().unwrap(); - for i in 0..uni.len() { - next_velocities.push(uni[i].next_velocity()); - } - } - { - let mut uni = UNIVERSE.write().unwrap(); - for i in 0..uni.len() { - uni[i].velocity = next_velocities[i]; - } - } - { - let uni = UNIVERSE.read().unwrap(); - for i in 0..uni.len() { - next_positions.push(uni[i].next_position()); + let mut uni = UNIVERSE.write().unwrap(); + let num_bodies = uni.len(); + + let nsps = *(NUM_SIMS_PER_STEP.read().unwrap()); + + for _ in 0..nsps { + for i in 0..num_bodies { + let mut body = uni[i]; + body.next_velocity(&uni); + uni[i] = body; } - } - { - let mut uni = UNIVERSE.write().unwrap(); - for i in 0..uni.len() { - uni[i].position = next_positions[i]; + for i in 0..num_bodies { + uni[i].next_position(); } } } @@ -108,7 +99,6 @@ pub fn add_body(mass: f64, position_x: f64, position_y: f64, velocity_x: f64, ve x: velocity_x, y: velocity_y, }, - scene: &UNIVERSE, }; UNIVERSE.write().unwrap().push(new_body); @@ -139,3 +129,12 @@ pub fn get_positions() -> Array { return out; } + +#[wasm_bindgen] +pub fn set_simulation_accuracy(time_step: f64, num_sims_per_step: i32) { + let mut ts = TIME_STEP.write().unwrap(); + *ts = time_step; + + let mut nsps = NUM_SIMS_PER_STEP.write().unwrap(); + *nsps = num_sims_per_step; +} \ No newline at end of file diff --git a/website-src/index.html b/website-src/index.html index 06d2e2e..7153126 100644 --- a/website-src/index.html +++ b/website-src/index.html @@ -25,6 +25,33 @@ +

Settings:

+
+

Trail quality:

+
+ +
+ +
+ +
+ +
+
+
+
+

Simulation Accuracy:

+
+ +
+ +
+ +
+
+
+
+ Enable Debug (slightly lowers performance)

# of bodies: 6

diff --git a/website-src/index.js b/website-src/index.js index 8d8f701..4f85785 100644 --- a/website-src/index.js +++ b/website-src/index.js @@ -24,23 +24,23 @@ let bodies = [ name: "L1", mass: 1, radius: 4, - position: [WIDTH / 2 + 173.9772874357808, HEIGHT / 2], - initialVelocity: [0, 1.592], + position: [WIDTH / 2 + 174.3684756886812, HEIGHT / 2], + initialVelocity: [0, 1.57386005], color: "#969696", }, { name: "L2", mass: 1, radius: 4, - position: [WIDTH / 2 + 147, HEIGHT / 2], - initialVelocity: [0, 1.29], + position: [WIDTH / 2 + 146.4437229236931, HEIGHT / 2], + initialVelocity: [0, 1.321809565], color: "#969696", }, { name: "L3", mass: 1, radius: 4, - position: [WIDTH / 2 - 160, HEIGHT / 2], + position: [WIDTH / 2 - 159.813705852, HEIGHT / 2], initialVelocity: [0, -1.444169311403618], color: "#4b964b", }, @@ -49,7 +49,7 @@ let bodies = [ mass: 1, radius: 4, position: [WIDTH / 2 + 80, HEIGHT / 2 + (Math.sqrt(3)/2) * 160], - initialVelocity: [-1.444169311403618 * Math.sqrt(3) / 2, 1.444169311403618 * 1/2], + initialVelocity: [-1.25180591705918, 0.7227304831872841], color: "#4b964b", }, { @@ -57,7 +57,7 @@ let bodies = [ mass: 1, radius: 4, position: [WIDTH / 2 + 80, HEIGHT / 2 - (Math.sqrt(3)/2) * 160], - initialVelocity: [1.444169311403618 * Math.sqrt(3) / 2, 1.444169311403618 * 1/2], + initialVelocity: [1.25180591705918, 0.7227304831872841], color: "#4b964b", }, ]; @@ -92,11 +92,46 @@ debugElem.addEventListener("click", (elem, e) => { else document.getElementById("debugSection").style.visibility = "hidden"; }) +const highTrailQualityElem = document.getElementById("highTrailQuality"); +const mediumTrailQualityElem = document.getElementById("mediumTrailQuality"); +const lowTrailQualityElem = document.getElementById("lowTrailQuality"); +const noneTrailQualityElem = document.getElementById("noneTrailQuality"); +const highSimAccuracyElem = document.getElementById("highSimAccuracy"); +const mediumSimAccuracyElem = document.getElementById("mediumSimAccuracy"); +const lowSimAccuracyElem = document.getElementById("lowSimAccuracy"); + const canvas = document.getElementById("scene"); const canvas2 = document.getElementById("trails"); const ctx = canvas.getContext("2d"); const ctx2 = canvas2.getContext("2d"); +let numTrailParticles = highTrailQualityElem.checked ? 100 : mediumTrailQualityElem.checked ? 50 : lowTrailQualityElem.checked ? 10 : 0; + +highTrailQualityElem.addEventListener("click", (elem, e) => { + numTrailParticles = 100; + for(let i = 0; i < trails.length; i++) trails[i] = []; + ctx2.clearRect(0, 0, WIDTH, HEIGHT); +}); +mediumTrailQualityElem.addEventListener("click", (elem, e) => { + numTrailParticles = 50; + for(let i = 0; i < trails.length; i++) trails[i] = []; + ctx2.clearRect(0, 0, WIDTH, HEIGHT); +}); +lowTrailQualityElem.addEventListener("click", (elem, e) => { + numTrailParticles = 10; + for(let i = 0; i < trails.length; i++) trails[i] = []; + ctx2.clearRect(0, 0, WIDTH, HEIGHT); +}); +noneTrailQualityElem.addEventListener("click", (elem, e) => { + numTrailParticles = 0; + for(let i = 0; i < trails.length; i++) trails[i] = []; + ctx2.clearRect(0, 0, WIDTH, HEIGHT); +}); + +highSimAccuracyElem.addEventListener("click", (elem, e) => { SolarSim.set_simulation_accuracy(0.05, 20) }) +mediumSimAccuracyElem.addEventListener("click", (elem, e) => { SolarSim.set_simulation_accuracy(0.2, 5) }) +lowSimAccuracyElem.addEventListener("click", (elem, e) => { SolarSim.set_simulation_accuracy(1.0, 1) }) + let playing = true; let tickTime = performance.now(); @@ -130,8 +165,8 @@ function step(simulate) { ctx.fill(); } - if(simulate) { - if(trails[i].length >= 100 || (!inBounds && trails[i].length > 0)) { + if(simulate && numTrailParticles > 0 && count % (100 / numTrailParticles) == 0) { + if(trails[i].length >= numTrailParticles || (!inBounds && trails[i].length > 0)) { let toRemove = trails[i].shift(); ctx2.fillStyle = "black"; ctx2.fillRect(toRemove[0] - 1, toRemove[1] - 1, 5, 5); diff --git a/website-src/package-lock.json b/website-src/package-lock.json index 434fc7d..ade35e1 100644 --- a/website-src/package-lock.json +++ b/website-src/package-lock.json @@ -1,12 +1,12 @@ { "name": "solar-sim-app", - "version": "0.3.1", + "version": "0.4.0", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "solar-sim-app", - "version": "0.3.1", + "version": "0.4.0", "license": "MIT", "dependencies": { "solar-sim": "file:../pkg" diff --git a/website-src/package.json b/website-src/package.json index 6649768..3ddef9d 100644 --- a/website-src/package.json +++ b/website-src/package.json @@ -1,6 +1,6 @@ { "name": "solar-sim-app", - "version": "0.3.1", + "version": "0.4.0", "description": "Creates the Solar Sim website.", "main": "index.js", "scripts": {