From 63bd19127f66dda81007fcd0d8857e978740101f Mon Sep 17 00:00:00 2001 From: Jon Santmyer Date: Mon, 30 Sep 2024 12:01:07 -0400 Subject: First commit --- .gitignore | 3 ++ Cargo.toml | 9 ++++ shell.nix | 22 ++++++++ src/main.rs | 52 ++++++++++++++++++ src/orbital.rs | 164 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/system.rs | 78 +++++++++++++++++++++++++++ src/units.rs | 13 +++++ 7 files changed, 341 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 shell.nix create mode 100644 src/main.rs create mode 100644 src/orbital.rs create mode 100644 src/system.rs create mode 100644 src/units.rs diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..a793def --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +*.lock +target + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..2b2065e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,9 @@ +[package] +name = "systemic" +version = "0.1.0" +authors = [ "crupette" ] + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +raylib = { version = "5.0.2", features = [ "wayland" ] } diff --git a/shell.nix b/shell.nix new file mode 100644 index 0000000..f2e5ae4 --- /dev/null +++ b/shell.nix @@ -0,0 +1,22 @@ +with import {}; +stdenv.mkDerivation { + name = "systemic-env"; + nativeBuildInputs = [ + rustc cargo + + pkg-config + cmake + + clang + stdenv.cc + stdenv.cc.libc stdenv.cc.libc_dev + glibc.static + ]; + + buildInputs = [ + glfw + wayland.dev + ]; + + LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..94b0930 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,52 @@ +extern crate raylib; + +mod units; +mod orbital; +mod system; + +use self::system::*; +use self::units::*; +use std::rc::Rc; +use std::cell::RefCell; +use raylib::prelude::*; + +fn main() { + let sol_system_builder = SystemBuilder::new(); + + let sol_ind = sol_system_builder + .add_body(orbital::OrbitalBuilder::new() + .name("Sol".to_string()) + .mass(1.988416e30) + .radius(695700.0) + .build()); + + let earth_ind = sol_system_builder + .add_body(orbital::OrbitalBuilder::new() + .name("Earth".to_string()) + .orbits(sol_ind) + .mass(5.972168e24) + .radius(6371.0) + .semi_major_axis(149598023.0) + .eccentricity(0.0167086) + .inclination(to_rad(7.155)) + .long_asc_node(to_rad(-11.26064)) + .argument_periapsis(to_rad(114.20783)) + .mean_anomaly_epoch(to_rad(358.617)) + .build()); + + let sol_system = sol_system_builder.build(); + sol_system.tick(0); + + let (mut rl_handle, rl_thread) = raylib::init() + .size(640, 480) + .title("Hello, World!") + .build(); + + while !rl_handle.window_should_close() + { + let mut draw_handle = rl_handle.begin_drawing(&rl_thread); + + draw_handle.clear_background(Color::BLACK); + draw_handle.draw_text("Hello, World!", 12, 12, 20, Color::WHITE); + } +} diff --git a/src/orbital.rs b/src/orbital.rs new file mode 100644 index 0000000..178273a --- /dev/null +++ b/src/orbital.rs @@ -0,0 +1,164 @@ +use super::units::*; +use super::system::System; +use std::vec::Vec; +use std::rc::Rc; +use std::cell::RefCell; + +pub struct Orbital +{ + origin : Option, + + //Euler angles for a given time (T) relative to origin + rel_pos : Option<(Second, Meter, Rad, Rad, Rad)>, + //Position for a given time (T) in absolute system coordinates + abs_pos : Option<(Second, Meter, Meter, Meter)>, + + name : String, + + //Physical parameters + mass : Kilogram, + radius : Meter, + + //Orbital parameters + semi_major_axis : Meter, + eccentricity : f64, + inclination : Rad, + longitude_asc_node : Rad, + argument_periapsis : Rad, + mean_anomaly_epoch : Rad, +} + +pub struct OrbitalBuilder +{ + origin : Option, + name : String, + mass : Kilogram, + radius : Meter, + semi_major_axis : Meter, + eccentricity : f64, + inclination : Rad, + longitude_asc_node : Rad, + argument_periapsis : Rad, + mean_anomaly_epoch : Rad, +} + +impl Orbital +{ + pub fn tick(&mut self, + origin : &mut Orbital, + t : Second) + { + match self.rel_pos { + None => {}, + Some(rel_pos) => { + if rel_pos.0 == t { return; } + } + } + + let origin_mass = origin.mass; + + let std_grav_param = GRAVITATIONAL_CONSTANT * (origin_mass + self.mass); + let mean_angular_motion = f64::sqrt(std_grav_param / self.semi_major_axis.powi(3)); + let mean_anomaly = self.mean_anomaly_epoch + (mean_angular_motion * t as f64); + + let mut eccentric_anomaly = mean_anomaly; + loop { + let de = (eccentric_anomaly - + self.eccentricity * eccentric_anomaly.sin() - + mean_anomaly) / + (1.0 - self.eccentricity * eccentric_anomaly.cos()); + eccentric_anomaly -= de; + if de.abs() < 1e6 { break; } + } + + //True anomaly + let beta = self.eccentricity / + (1.0 + f64::sqrt(1.0 - self.eccentricity.powi(2))); + let true_anomaly = eccentric_anomaly * 2.0 * + f64::atan((beta * eccentric_anomaly.sin()) / + (1.0 - beta * eccentric_anomaly.cos())); + + let distance = self.semi_major_axis * + (1.0 - self.eccentricity * eccentric_anomaly.cos()); + + self.rel_pos = Some((t, distance, self.longitude_asc_node, self.inclination, true_anomaly)); + println!("{0:?}", self.rel_pos.unwrap()); + } + + pub fn pos(&mut self, + system : &System, + t : Second) + -> (Meter, Meter, Meter) + { + (0.0, 0.0, 0.0) + } + + pub fn name(&self) -> &String { &self.name } + + pub fn origin(&self) -> Option { self.origin } +} + +impl OrbitalBuilder +{ + pub fn new() -> OrbitalBuilder { + OrbitalBuilder { + origin : None, + name : "".to_string(), + mass : 0.0, + radius : 0.0, + semi_major_axis : 0.0, + eccentricity : 0.0, + inclination : 0.0, + longitude_asc_node : 0.0, + argument_periapsis : 0.0, + mean_anomaly_epoch : 0.0, + } + } + pub fn orbits(mut self, parent : usize) -> OrbitalBuilder + { self.origin = Some(parent); self } + + pub fn name(mut self, name : String) -> OrbitalBuilder + { self.name = name; self } + + pub fn mass(mut self, mass : Kilogram) -> OrbitalBuilder + { self.mass = mass; self } + + pub fn radius(mut self, radius : Meter) -> OrbitalBuilder + { self.radius = radius; self } + + pub fn semi_major_axis(mut self, sma : Meter) -> OrbitalBuilder + { self.semi_major_axis = sma; self } + + pub fn eccentricity(mut self, e : Rad) -> OrbitalBuilder + { self.eccentricity = e; self } + + pub fn inclination(mut self, i : Rad) -> OrbitalBuilder + { self.inclination = i; self } + + pub fn long_asc_node(mut self, omega : Rad) -> OrbitalBuilder + { self.longitude_asc_node = omega; self } + + pub fn argument_periapsis(mut self, w : Rad) -> OrbitalBuilder + { self.argument_periapsis = w; self } + + pub fn mean_anomaly_epoch(mut self, mean_anomaly : Rad) -> OrbitalBuilder + { self.mean_anomaly_epoch = mean_anomaly; self } + + pub fn build(self) -> Orbital + { + Orbital { + origin : self.origin, + rel_pos : None, + abs_pos : None, + name : self.name, + mass : self.mass, + radius : self.radius, + semi_major_axis : self.semi_major_axis, + eccentricity : self.eccentricity, + inclination : self.inclination, + longitude_asc_node : self.longitude_asc_node, + argument_periapsis : self.argument_periapsis, + mean_anomaly_epoch : self.mean_anomaly_epoch + } + } +} diff --git a/src/system.rs b/src/system.rs new file mode 100644 index 0000000..d11ea3a --- /dev/null +++ b/src/system.rs @@ -0,0 +1,78 @@ +use super::units::*; +use super::orbital::*; +use std::vec::Vec; +use std::rc::Rc; +use std::cell::RefCell; + +pub struct System +{ + pub orbitals : Rc>>, +} + +pub struct SystemBuilder +{ + orbitals : Rc>>, +} + +impl System +{ + fn orbital_set(&self, orbitals : &mut [Orbital], i : usize) + -> (&mut Orbital, Option<&mut Orbital>) + { + //The orbital vector must first be converted to a mutable span, so that I can access the raw data. + assert!(i < orbitals.len()); + unsafe { + //From the orbital span, take a raw pointer from the given index, + //cast to a pointer to a mutable Orbital, and dereference. + let orbital = &mut *(orbitals.get_unchecked_mut(i) as *mut Orbital); + //Assuming the orbital is a valid object, check for the parent orbital. + match orbital.origin() { + Some(origin_i) => { + //Make sure the origin index does not break rules. + assert!(origin_i != i, "Object cannot orbit itself"); + assert!(origin_i < orbitals.len()); + let origin = &mut *(orbitals.get_unchecked_mut(origin_i) as *mut Orbital); + (orbital, Some(origin)) + }, + None => (orbital, None) + } + } + } + + pub fn tick(&self, t : Second) + { + let orbitals = &mut self.orbitals.borrow_mut()[..]; + for i in 0..orbitals.len() { + let orbital_set = self.orbital_set(orbitals, i); + match orbital_set.1 { + Some(origin) => { orbital_set.0.tick(origin, t); }, + None => {} + } + } + } +} + +impl SystemBuilder +{ + pub fn new() -> SystemBuilder + { + SystemBuilder { + orbitals : Rc::new(RefCell::new(vec![])) + } + } + + pub fn add_body(&self, orbital : Orbital) -> usize + { + let mut orbitals = self.orbitals.borrow_mut(); + let new_ind = orbitals.len(); + orbitals.push(orbital); + new_ind + } + + pub fn build(self) -> System + { + System { + orbitals : self.orbitals + } + } +} diff --git a/src/units.rs b/src/units.rs new file mode 100644 index 0000000..cc04098 --- /dev/null +++ b/src/units.rs @@ -0,0 +1,13 @@ +use std::f64::consts::PI; + +pub const GRAVITATIONAL_CONSTANT : f64 = 6.67430e-11; +pub const AU : f64 = 1.495979e11; + +pub type Second = u64; +pub type Meter = f64; +pub type Rad = f64; +pub type Kilogram = f64; + +pub fn to_rad(deg : f64) -> Rad +{ (deg / 180.0) * PI } + -- cgit v1.2.1