Make a simple two-planet system work. More planets must be tested.
This commit is contained in:
parent
75bed957c4
commit
a13f42b7af
@ -1,41 +1,37 @@
|
|||||||
use opengl_graphics::GlGraphics;
|
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 struct Canvas {
|
||||||
pub gl: GlGraphics,
|
pub gl: GlGraphics,
|
||||||
pub planets: Vec<Planet>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Canvas {
|
impl Canvas {
|
||||||
pub fn render(&mut self, args: &RenderArgs) {
|
pub fn render(&mut self, planets: &Vec<Planet>, args: &RenderArgs) {
|
||||||
use graphics::*;
|
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);
|
let middle = (args.window_size[0] / 2.0, args.window_size[1] / 2.0);
|
||||||
|
|
||||||
self.gl.draw(args.viewport(), |c, gl| {
|
self.gl.draw(args.viewport(), |c, gl| {
|
||||||
clear(BLACK, gl);
|
clear(WHITE, gl);
|
||||||
|
|
||||||
//get all planets and draw them here
|
//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 circle = ellipse::circle(0.0, 0.0, planet.radius);
|
||||||
|
|
||||||
let transform = c
|
let transform = c
|
||||||
.transform
|
.transform
|
||||||
.trans(middle.0, middle.1)
|
.trans(middle.0, middle.1)
|
||||||
.trans(planet.pos[0], planet.pos[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];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
62
src/gravity.rs
Normal file
62
src/gravity.rs
Normal file
@ -0,0 +1,62 @@
|
|||||||
|
use crate::planet::Planet;
|
||||||
|
const GRAVITATIONAL_CONTANT: f64 = 6.67430e-11;
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct GravityCalculator {
|
||||||
|
pub planets: Vec<Planet>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl GravityCalculator {
|
||||||
|
pub fn new(planets: Vec<Planet>) -> 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<f64> = 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<f64> {
|
||||||
|
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]]
|
||||||
|
}
|
||||||
|
}
|
39
src/main.rs
39
src/main.rs
@ -4,6 +4,7 @@ extern crate opengl_graphics;
|
|||||||
extern crate piston;
|
extern crate piston;
|
||||||
|
|
||||||
mod canvas;
|
mod canvas;
|
||||||
|
mod gravity;
|
||||||
mod physics;
|
mod physics;
|
||||||
mod planet;
|
mod planet;
|
||||||
|
|
||||||
@ -22,30 +23,40 @@ fn main() {
|
|||||||
.build()
|
.build()
|
||||||
.unwrap();
|
.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 {
|
let mut canvas = canvas::Canvas {
|
||||||
gl: GlGraphics::new(opengl),
|
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());
|
let mut events = Events::new(EventSettings::new());
|
||||||
while let Some(e) = events.next(&mut window) {
|
while let Some(e) = events.next(&mut window) {
|
||||||
if let Some(args) = e.render_args() {
|
if let Some(args) = e.render_args() {
|
||||||
canvas.render(&args);
|
canvas.render(&calculator.planets.clone(), &args);
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(args) = e.update_args() {
|
if let Some(args) = e.update_args() {
|
||||||
canvas.update(&args);
|
calculator.calculate_forces_newtonian();
|
||||||
|
calculator.update_positions(100000.0 * args.dt);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,12 +1,2 @@
|
|||||||
use crate::planet::Planet;
|
|
||||||
|
|
||||||
const GRAVITATIONAL_CONTANT: f64 = 6.67430e-11;
|
|
||||||
|
|
||||||
pub fn force_between(p1: &Planet, p2: &Planet) -> Vec<f64> {
|
|
||||||
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]]
|
|
||||||
}
|
|
||||||
|
@ -1,7 +1,12 @@
|
|||||||
|
#[derive(Clone)]
|
||||||
pub struct Planet {
|
pub struct Planet {
|
||||||
|
pub name: String,
|
||||||
pub mass: f64,
|
pub mass: f64,
|
||||||
pub pos: Vec<f64>,
|
pub pos: Vec<f64>,
|
||||||
pub radius: f64,
|
pub radius: f64,
|
||||||
|
pub force_affecting: Vec<f64>,
|
||||||
|
pub velocity: Vec<f64>,
|
||||||
|
pub color: [f32; 4],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Planet {
|
impl Planet {
|
||||||
@ -35,18 +40,37 @@ impl PlanetBuilder {
|
|||||||
pub fn new() -> PlanetBuilder {
|
pub fn new() -> PlanetBuilder {
|
||||||
return PlanetBuilder {
|
return PlanetBuilder {
|
||||||
planet: Planet {
|
planet: Planet {
|
||||||
|
name: "".to_string(),
|
||||||
mass: 0.0,
|
mass: 0.0,
|
||||||
pos: vec![0.0, 0.0],
|
pos: vec![0.0, 0.0],
|
||||||
radius: 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 {
|
pub fn with_mass(mut self, mass: f64) -> PlanetBuilder {
|
||||||
self.planet.mass = mass;
|
self.planet.mass = mass;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn with_velocity(mut self, velocity: Vec<f64>) -> PlanetBuilder {
|
||||||
|
self.planet.velocity = velocity;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
pub fn with_positsion(mut self, x: f64, y: f64) -> PlanetBuilder {
|
pub fn with_positsion(mut self, x: f64, y: f64) -> PlanetBuilder {
|
||||||
self.planet.pos = vec![x, y];
|
self.planet.pos = vec![x, y];
|
||||||
self
|
self
|
||||||
|
Loading…
Reference in New Issue
Block a user