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
//! Ray implementation.

use crate::{
    access,
    math::{Dir3, Pos3, Rot3, Vec3},
};

/// Ray structure.
#[derive(Clone)]
pub struct Ray {
    /// Ray origin.
    pos: Pos3,
    /// Ray direction.
    dir: Dir3,
}

impl Ray {
    access!(pos, pos_mut, Pos3);
    access!(dir, dir_mut, Dir3);

    /// Construct a new instance.
    #[inline]
    #[must_use]
    pub fn new(pos: Pos3, mut dir: Dir3) -> Self {
        dir.renormalize();
        Self { pos, dir }
    }

    /// Destruct self into components.
    #[inline]
    #[must_use]
    pub const fn destruct(self) -> (Pos3, Dir3) {
        (self.pos, self.dir)
    }

    /// Move along the direction of travel a given distance.
    #[inline]
    pub fn travel(&mut self, dist: f64) {
        debug_assert!(dist > 0.0);

        self.pos += self.dir.as_ref() * dist;
    }

    /// Rotate the photon with a given pitch and subsequent roll manoeuvre.
    #[inline]
    pub fn rotate(&mut self, pitch: f64, roll: f64) {
        let arbitrary_axis = if (1.0 - self.dir.z.abs()) >= 1.0e-1 {
            Vec3::z_axis()
        } else {
            Vec3::y_axis()
        };

        let pitch_axis = Dir3::new_normalize(self.dir.cross(&arbitrary_axis));
        let pitch_rot = Rot3::from_axis_angle(&pitch_axis, pitch);

        let roll_rot = Rot3::from_axis_angle(&self.dir, roll);

        self.dir = roll_rot * pitch_rot * self.dir;
        self.dir.renormalize();
    }
}