summaryrefslogtreecommitdiffstats
path: root/src/solar_system.rs
blob: ad1f304d78f69cdb2b741f1c12c8b51b25436eb7 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
pub mod body;
pub mod ship;
pub mod orbit;

use self::body::*;
use self::ship::*;
use self::orbit::*;

use serde::{Deserialize};
use crate::known_stars::*;
use crate::timeman::Second;
use std::error::Error;

const GRAVITATIONAL_CONSTANT: f64 = 6.67408e-20;

pub type Kilograms = f64;
pub type Kilometers = f64;
pub type Percentage = f64;
pub type Angle = f64;

pub type SystemId = usize;

#[derive(Debug, Deserialize)]
pub struct CSVOrbitalBody
{
    name: String,
    orbits: Option<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 SolarSystem
{
    id: SystemId,
    name: String,
 
    bodies: Vec<OrbitalBody>,
    ships: Vec<Ship>
}

impl SolarSystem
{
    pub fn new_from_csv(
        id: SystemId,
        data: &'static str)
    -> Result<Self, Box<dyn Error>> {
        let data_reader = stringreader::StringReader::new(data);
        let mut body_reader = csv::Reader::from_reader(data_reader);
        
        let mut bodies = Vec::<OrbitalBody>::new();

        for result in body_reader.deserialize() {
            let mut record: CSVOrbitalBody = result?;

            match record.orbits {
                Some(orbits) => {
                    if record.sgp == 0.0 {
                        record.sgp = (bodies[orbits].mass() + record.mass) * GRAVITATIONAL_CONSTANT;
                    }
                }
                None => {}
            }
            if record.radius == 0.0 { continue; }
            println!("New body: {:?}", record);

            bodies.push(OrbitalBody::new_from_record(bodies.len(), record));
        }

        Ok(Self {
            id: id,
            name: bodies[0].name().clone(),
            bodies: bodies,
            ships: vec![]
        })
    }

    pub fn new_from_known_star(
        id: SystemId,
        star: &'static str)
    -> Result<Self, Box<dyn Error>> {
        let star_csv = match KNOWN_STARS.get(star).copied() {
            Some(csv) => csv,
            None => return Err(Box::new(StarNotFoundError { star: star }))
        };
        SolarSystem::new_from_csv(id, star_csv)
    }

    pub fn id(&self) -> SystemId { self.id }

    pub fn name(&self) -> &String { &self.name }

    pub fn bodies(&self)
        -> &[OrbitalBody]
    {
        self.bodies.as_slice()
    }

    pub fn body_position(
        &self,
        body: &OrbitalBody)
    -> cgmath::Vector3<Kilometers>
    {
        body.absolute_position(self)
    }

    pub fn update(
        &mut self,
        time: Second)
    {
        self.bodies.iter_mut().for_each(|body| {
            body.update(time);
        });
    }
}