summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJon Santmyer <jon@jonsantmyer.com>2024-09-30 12:01:07 -0400
committerJon Santmyer <jon@jonsantmyer.com>2024-09-30 12:01:07 -0400
commit63bd19127f66dda81007fcd0d8857e978740101f (patch)
tree781e971abde6f79b35b457927129066df42d955e
downloadsystemic-master.tar.gz
systemic-master.tar.bz2
systemic-master.zip
First commitHEADmaster
-rw-r--r--.gitignore3
-rw-r--r--Cargo.toml9
-rw-r--r--shell.nix22
-rw-r--r--src/main.rs52
-rw-r--r--src/orbital.rs164
-rw-r--r--src/system.rs78
-rw-r--r--src/units.rs13
7 files changed, 341 insertions, 0 deletions
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 <nixpkgs> {};
+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<usize>,
+
+ //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<usize>,
+ 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<usize> { 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<RefCell<Vec<Orbital>>>,
+}
+
+pub struct SystemBuilder
+{
+ orbitals : Rc<RefCell<Vec<Orbital>>>,
+}
+
+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 }
+