use serde::{Deserialize}; use crate::{known_stars::{KNOWN_STARS, StarNotFoundError}, timeman::Second}; use std::error::Error; const GRAVITATIONAL_CONSTANT: f64 = 6.67408e-11; pub type Kilograms = f64; pub type Kilometers = f64; pub type Percentage = f64; pub type Angle = f64; pub type BodyId = usize; pub type SystemId = usize; #[derive(Debug, Deserialize)] pub struct SerialOrbitalBody { name: String, orbits: BodyId, mass: Kilograms, radius: Kilometers, eccentricity: Percentage, inclination: Angle, long_asc_node: Angle, long_periapsis: Angle, sgp: f64, mean_long: Angle, semi_major_axis: Kilometers, } pub struct OrbitalBody { body: SerialOrbitalBody, position: Option<(Second, cgmath::Point3)> } pub struct SolarSystem { name: String, bodies: Vec, } impl SolarSystem { pub fn new_from_csv( data: &'static str) -> Result> { let data_reader = stringreader::StringReader::new(data); let mut body_reader = csv::Reader::from_reader(data_reader); let mut bodies = Vec::::new(); for result in body_reader.deserialize() { let record: SerialOrbitalBody = result?; println!("New body: {:?}", record); bodies.push(OrbitalBody { body: record, position: None }); } Ok(Self { name: bodies[0].name().clone(), bodies: bodies, }) } pub fn new_from_known_star( star: &'static str) -> Result> { let star_csv = match KNOWN_STARS.get(star).copied() { Some(csv) => csv, None => return Err(Box::new(StarNotFoundError { star: star })) }; SolarSystem::new_from_csv(star_csv) } pub fn name(&self) -> &String { &self.name } pub fn bodies(&self) -> &[OrbitalBody] { self.bodies.as_slice() } } impl OrbitalBody { pub fn name(&self) -> &String { &self.body.name } pub fn radius(&self) -> f32 { self.body.radius as f32 } pub fn position(&self, time: Second) -> Option> { match self.position { Some((cache_time, pos)) => { if time == cache_time { return Some(pos); } return None; }, None => None } } fn calculate_orbit( &self, time: i64) -> cgmath::Point3 { cgmath::Point3 { x: 0.0, y: 0.0, z: 0.0 } /*let arg_periapsis = self.long_periapsis - self.long_asc_node; let mean_angular_motion: f64 = ( self.sgp as f64 / (self.semi_major_axis as f64).powf(3.0) ).sqrt(); let mean_anomaly = (self.mean_long - self.long_periapsis) + (mean_angular_motion * time as f64) as f32; let mut eccentric_anomaly = mean_anomaly + self.eccentricity * mean_anomaly.sin(); for _ in 0..100 { let new_eccentric = eccentric_anomaly + (mean_anomaly - eccentric_anomaly + self.eccentricity * eccentric_anomaly.sin()) / (1.0 - self.eccentricity * eccentric_anomaly.cos()); if (new_eccentric - eccentric_anomaly).abs() < 1e-6 { eccentric_anomaly = new_eccentric; break; } eccentric_anomaly = new_eccentric; } let beta = self.eccentricity / 1.0 + (1.0 - self.eccentricity * self.eccentricity).sqrt(); let true_anomaly = eccentric_anomaly + 2.0 * ((beta * eccentric_anomaly.sin()) / (1.0 - beta * eccentric_anomaly.cos())).atan(); let radius: f64 = self.semi_major_axis * (1.0 - self.eccentricity * eccentric_anomaly.cos()) as f64; let ohm_sin = self.long_asc_node.sin(); let ohm_cos = self.long_asc_node.cos(); let inc_sin = self.inclination.sin(); let inc_cos = self.inclination.cos(); let per_anom_sin = (arg_periapsis + true_anomaly).sin(); let per_anom_cos = (arg_periapsis + true_anomaly).cos(); let x: f32 = (radius as f32) * ( (ohm_cos * per_anom_cos) - (ohm_sin * per_anom_sin * inc_cos)); let y: f32 = (radius as f32) * ( (ohm_sin * per_anom_cos) + (ohm_cos * per_anom_sin * inc_cos)); let z: f32 = (radius as f32) * (inc_sin * per_anom_sin); OrbitState { position: cgmath::Vector3::new(x, y, z) }*/ } }