From a13f42b7affe4270f52b4b7a77def1327e4d2ba8 Mon Sep 17 00:00:00 2001 From: Marco Date: Sun, 7 Jul 2024 15:47:49 +0200 Subject: [PATCH] Make a simple two-planet system work. More planets must be tested. --- src/canvas.rs | 28 ++++++++++------------- src/gravity.rs | 62 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/main.rs | 39 +++++++++++++++++++------------ src/physics.rs | 10 -------- src/planet.rs | 24 +++++++++++++++++++ 5 files changed, 123 insertions(+), 40 deletions(-) create mode 100644 src/gravity.rs diff --git a/src/canvas.rs b/src/canvas.rs index 5d34fab..427e990 100644 --- a/src/canvas.rs +++ b/src/canvas.rs @@ -1,41 +1,37 @@ use opengl_graphics::GlGraphics; -use piston::{RenderArgs, UpdateArgs}; +use piston::RenderArgs; -use super::planet::Planet; +use crate::planet::Planet; + +pub const WHITE: [f32; 4] = [1.0, 1.0, 1.0, 1.0]; +pub const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0]; +pub const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; +pub const GREEN: [f32; 4] = [0.0, 1.0, 0.0, 1.0]; +pub const BLUE: [f32; 4] = [0.0, 0.0, 1.0, 1.0]; pub struct Canvas { pub gl: GlGraphics, - pub planets: Vec, } impl Canvas { - pub fn render(&mut self, args: &RenderArgs) { + pub fn render(&mut self, planets: &Vec, args: &RenderArgs) { use graphics::*; - const BLACK: [f32; 4] = [0.0, 0.0, 0.0, 1.0]; - const RED: [f32; 4] = [1.0, 0.0, 0.0, 1.0]; - let middle = (args.window_size[0] / 2.0, args.window_size[1] / 2.0); self.gl.draw(args.viewport(), |c, gl| { - clear(BLACK, gl); + clear(WHITE, gl); //get all planets and draw them here - for planet in &self.planets { + for planet in planets { let circle = ellipse::circle(0.0, 0.0, planet.radius); let transform = c .transform .trans(middle.0, middle.1) .trans(planet.pos[0], planet.pos[1]); - ellipse(RED, circle, transform, gl); + ellipse(planet.color, circle, transform, gl); } }); } - - pub fn update(&mut self, args: &UpdateArgs) { - for planet in self.planets.iter_mut() { - planet.pos = vec![planet.pos[0] + 1.0 * args.dt, planet.pos[1] + 1.0 * args.dt]; - } - } } diff --git a/src/gravity.rs b/src/gravity.rs new file mode 100644 index 0000000..c022253 --- /dev/null +++ b/src/gravity.rs @@ -0,0 +1,62 @@ +use crate::planet::Planet; +const GRAVITATIONAL_CONTANT: f64 = 6.67430e-11; + +#[derive(Clone)] +pub struct GravityCalculator { + pub planets: Vec, +} + +impl GravityCalculator { + pub fn new(planets: Vec) -> Self { + return GravityCalculator { planets }; + } + + pub fn calculate_forces_newtonian(&mut self) { + let orig_set_of_planets = self.planets.clone(); + + for this_planet in self.planets.iter_mut() { + let mut sum_of_forces: Vec = vec![0.0, 0.0]; + + for other_planet in orig_set_of_planets.iter() { + let distance = this_planet.distance_to(&other_planet); + + if distance == 0.0 { + continue; + } + + let force = Self::force_between(this_planet, &other_planet); + sum_of_forces = vec![sum_of_forces[0] + force[0], sum_of_forces[1] + force[1]]; + } + this_planet.force_affecting = sum_of_forces; + } + } + + pub fn update_positions(&mut self, dt: f64) { + for this_planet in self.planets.iter_mut() { + let x = this_planet.pos[0]; + let y = this_planet.pos[1]; + let fx = this_planet.force_affecting[0]; + let fy = this_planet.force_affecting[1]; + let vx = this_planet.velocity[0]; + let vy = this_planet.velocity[1]; + + let accelaration = vec![fx / this_planet.mass, fy / this_planet.mass]; + let delta_v = [accelaration[0] * dt, accelaration[1] * dt]; + let velocity = vec![vx + delta_v[0], vy + delta_v[1]]; + this_planet.velocity = velocity; + this_planet.pos = vec![ + x + this_planet.velocity[0] * dt, + y + this_planet.velocity[1] * dt, + ]; + } + } + + pub fn force_between(p1: &Planet, p2: &Planet) -> Vec { + let dist = p1.distance_to(p2); + let norm_vec = p1.normal_vec_to(p2); + + let scalar_part = GRAVITATIONAL_CONTANT * p1.get_mass() * p2.get_mass() / dist.powf(2.0); + + vec![scalar_part * norm_vec[0], scalar_part * norm_vec[1]] + } +} diff --git a/src/main.rs b/src/main.rs index f264b53..9477885 100644 --- a/src/main.rs +++ b/src/main.rs @@ -4,6 +4,7 @@ extern crate opengl_graphics; extern crate piston; mod canvas; +mod gravity; mod physics; mod planet; @@ -22,30 +23,40 @@ fn main() { .build() .unwrap(); + let planets = vec![ + planet::PlanetBuilder::new() + .with_name(String::from("Earth")) + .with_velocity(vec![-0.0002, 0.0]) + .with_positsion(0.0, -25.0) + .with_mass(100000.0) + .with_radius(5.0) + .with_color(canvas::GREEN) + .build(), + planet::PlanetBuilder::new() + .with_name(String::from("Moon")) + .with_velocity(vec![0.0002, 0.0]) + .with_positsion(0.0, 25.0) + .with_mass(100000.0) + .with_radius(5.0) + .with_color(canvas::RED) + .build(), + ]; + let mut canvas = canvas::Canvas { gl: GlGraphics::new(opengl), - planets: vec![ - planet::PlanetBuilder::new() - .with_positsion(-100.0, 0.0) - .with_mass(100.0) - .with_radius(40.0) - .build(), - planet::PlanetBuilder::new() - .with_positsion(100.0, 0.0) - .with_mass(10.0) - .with_radius(20.0) - .build(), - ], }; + let mut calculator = gravity::GravityCalculator::new(planets); + let mut events = Events::new(EventSettings::new()); while let Some(e) = events.next(&mut window) { if let Some(args) = e.render_args() { - canvas.render(&args); + canvas.render(&calculator.planets.clone(), &args); } if let Some(args) = e.update_args() { - canvas.update(&args); + calculator.calculate_forces_newtonian(); + calculator.update_positions(100000.0 * args.dt); } } } diff --git a/src/physics.rs b/src/physics.rs index d622dae..139597f 100644 --- a/src/physics.rs +++ b/src/physics.rs @@ -1,12 +1,2 @@ -use crate::planet::Planet; -const GRAVITATIONAL_CONTANT: f64 = 6.67430e-11; -pub fn force_between(p1: &Planet, p2: &Planet) -> Vec { - let dist = p1.distance_to(p2); - let norm_vec = p1.normal_vec_to(p2); - - let scalar_part = GRAVITATIONAL_CONTANT * p1.get_mass() * p2.get_mass() / dist.powf(2.0); - - vec![scalar_part * norm_vec[0], scalar_part * norm_vec[1]] -} diff --git a/src/planet.rs b/src/planet.rs index daf9f53..11e68b9 100644 --- a/src/planet.rs +++ b/src/planet.rs @@ -1,7 +1,12 @@ +#[derive(Clone)] pub struct Planet { + pub name: String, pub mass: f64, pub pos: Vec, pub radius: f64, + pub force_affecting: Vec, + pub velocity: Vec, + pub color: [f32; 4], } impl Planet { @@ -35,18 +40,37 @@ impl PlanetBuilder { pub fn new() -> PlanetBuilder { return PlanetBuilder { planet: Planet { + name: "".to_string(), mass: 0.0, pos: vec![0.0, 0.0], radius: 0.0, + force_affecting: vec![0.0, 0.0], + velocity: vec![0.0, 0.0], + color: [0.0; 4], }, }; } + pub fn with_name(mut self, name: String) -> PlanetBuilder { + self.planet.name = name; + self + } + + pub fn with_color(mut self, color: [f32; 4]) -> PlanetBuilder { + self.planet.color = color; + self + } + pub fn with_mass(mut self, mass: f64) -> PlanetBuilder { self.planet.mass = mass; self } + pub fn with_velocity(mut self, velocity: Vec) -> PlanetBuilder { + self.planet.velocity = velocity; + self + } + pub fn with_positsion(mut self, x: f64, y: f64) -> PlanetBuilder { self.planet.pos = vec![x, y]; self