summaryrefslogtreecommitdiffstats
path: root/projects/learning-rust/1.html
blob: be6bfa7d1eeeb7b9b4638577841920c1a8b13795 (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
<!DOCTYPE html>
<html>
<head>
    <title>1: Orbitals</title>

    <link rel="stylesheet" href="/style.css"/>
    <link rel="stylesheet" href="/prism/prism.css"/>
    <script src="/prism/prism.js"></script>
</head>
<body>
    <div class="window">
        <div class="window-title"><h2 style="padding: 0px; margin: 0px;">Learning Rust : Orbitals</h2></div>
        <i>How do I store non-owning references to collection members?</i>
        <div class="window-content">
            <a class="link-button" href="/projects/learning-rust">&lt;</a>
            <a class="link-button" href="/projects/learning-rust">Home</a>
            <a class="link-button" href="/projects/learning-rust/2.html">&gt;</a>
            <p>I want to make a data-driven viewer for the solar system, as part of a game inspired by <a href="https://www.aurora2.pentarch.org/">Aurora 4x</a> but Rust is an entirely different beast from C.</p>
            <p>So let's start with the types i'll use:</p>
            <pre><code class="language-rust">
pub const GRAVITATIONAL_CONSTANT : f64 = 6.67430e-11;

pub type Second = u64;
pub type Meter = f64;
pub type Rad = f64;
pub type Kilogram = f64;
            </code></pre>
            <p>I have prior experience writing systems like this, so I figured it would be as easy as:</p>
            <pre><code class="language-rust">
pub struct Orbital {
    //Some optional non-owning reference to the parent orbital
    mass : Kilogram,
    semi_major_axis : Rad,
    eccentricity : Rad,
    inclination : Rad,
    long_asc_node : Rad,
    argument_periapsis : Rad,
    mean_anomaly_epoch : Rad
}
            </code></pre>
            <p>The question then is: How do we store the reference to the parent orbital?</p>
            <p>note: by parent orbital, I mean the orbital body that the given orbital body orbits.</p>
            <p>In C, we would just store a pointer into the data of the owning container (i.e. a dynamic array).</p>
            <p>I understand that the method above could cause problems with object lifetimes and dead references, but in this case we are assuming a static lifetime with a fixed-width container.</p>
            <p>So my first instinct is to look in the Rust docs for a non-owning reference type.</p>
            <p>I wasted about a day researching Rc's and RefCell's when I had a revelation; what I wanted was over-engineered. Instead of storing a reference to the parent orbital, I could just store an index into the system's orbital container. All I need to do to make this work is pass a borrowed ref to the system object to the orbital's update function.</p>
            <p>But not every part of the update function needs the parent orbital's position, so I can split the update into two parts:</p>
            <p>1: Update the orbital elements relative to the parent object</p>
            <p>2: Use the parent orbital's position to transform the relative coordinates into absolute coordinates</p>
            <p>All the tick method needs is an immutable parent object to calculate the standard gravitational parameter of the one-body system being emulated.</p>
            <p>So here's what I came up with.</p>
            <pre><code class="language-rust">
pub struct Orbital {
    origin : Option&lt;usize&gt;,
    //Euler angles for a given time (T) relative to origin
    rel_pos : Option<(Second, Meter, Rad, Rad, Rad)>
    //Cartesian coordinates for a given time (T) relative to (0, 0, 0)
    abs_pos : Option<(Second, Meter, Meter, Meter)>
    //Orbital parameters
    mass : Kilogram,
    semi_major_axis : Meter,
    eccentricity : Rad,
    inclination : Rad,
    long_asc_node : Rad,
    argument_periapsis : Rad,
    mean_anomaly_epoch : Rad
}
//...
impl Orbital {
//...
    //Update relative 
    pub fn tick(&mut self, &system: System, t: Second) {
        //...
    }
    
    pub fn pos(&self, &system : System, t: Second) -> (Meter, Meter, Meter) {
        //...
    }
}
        </code></pre>
        <p>Now comes the daunting task of storing our orbitals in a usable manner. Ideally, I want to iterate through the list of orbitals in a way that also lets me access other members of the orbital list from the tick and pos functions. It's a lot harder than it should be.</p>
        </div>
    </div>
</body>
</html>