Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Release 0.4.0 #12

Merged
merged 6 commits into from Jun 17, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion Cargo.toml
@@ -1,6 +1,6 @@
[package]
name = "solar-sim"
version = "0.3.1"
version = "0.4.0"
authors = ["Ben Plate <bplate9583@gmail.com>"]
edition = "2018"
description = "Physics simulator written in Rust WASM for use in Solar Sim website"
Expand Down
85 changes: 42 additions & 43 deletions rust-src/lib.rs
Expand Up @@ -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;
Expand All @@ -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<Vec<Body<'static>>> = RwLock::new(vec![]);
static ref UNIVERSE: RwLock<Vec<Body>> = RwLock::new(vec![]);
static ref TIME_STEP: RwLock<f64> = RwLock::new(0.2);
static ref NUM_SIMS_PER_STEP: RwLock<i32> = RwLock::new(5);
}

#[derive(Clone, Copy)]
Expand All @@ -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<Vec<Body<'a>>>,
}

impl Body<'_> {
fn next_velocity(&self) -> Vector2D {
impl Body {
fn next_velocity(&mut self, uni: &Vec<Body>) {
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<Vector2D> = vec![];
let mut next_positions: Vec<Vector2D> = 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();
}
}
}
Expand All @@ -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);
Expand Down Expand Up @@ -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;
}
27 changes: 27 additions & 0 deletions website-src/index.html
Expand Up @@ -25,6 +25,33 @@
<button id="spawn">Spawn</button>
</div>

<p>Settings:</p>
<div style="color:white;float:left;padding-right:25px">
<p>Trail quality:</p>
<div>
<input type="radio" id="highTrailQuality" name="trailQuality" value="high" checked="checked"/>
<label for="highTrailQuality">High</label><br />
<input type="radio" id="mediumTrailQuality" name="trailQuality" value="medium" />
<label for="mediumTrailQuality">Medium</label><br />
<input type="radio" id="lowTrailQuality" name="trailQuality" value="low" />
<label for="lowTrailQuality">Low</label><br />
<input type="radio" id="noneTrailQuality" name="trailQuality" value="none" />
<label for="noneTrailQuality">None</label><br />
</div>
</div>
<div style="color:white;float:left;padding-right:25px">
<p>Simulation Accuracy:</p>
<div>
<input type="radio" id="highSimAccuracy" name="simAccuracy" value="high" />
<label for="highSimAccuracy">High</label><br />
<input type="radio" id="mediumSimAccuracy" name="simAccuracy" value="medium" checked="checked" />
<label for="mediumSimAccuracy">Medium</label><br />
<input type="radio" id="lowSimAccuracy" name="simAccuracy" value="low" />
<label for="lowSimAccuracy">Low</label><br />
</div>
</div>
<div style="clear:left;height:50px"></div>

<input type="checkbox" id="debug" /><span style="color:white">Enable Debug (slightly lowers performance)</span>
<div id="debugSection" style="color:white">
<p># of bodies: <span id="numBodies">6</span></p>
Expand Down
53 changes: 44 additions & 9 deletions website-src/index.js
Expand Up @@ -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",
},
Expand All @@ -49,15 +49,15 @@ 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",
},
{
name: "L5",
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",
},
];
Expand Down Expand Up @@ -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();

Expand Down Expand Up @@ -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);
Expand Down
4 changes: 2 additions & 2 deletions website-src/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion 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": {
Expand Down