sim_lib_interference_core/
geometry.rs1use crate::{InterferenceError, Metres};
4
5fn canonical_zero(value: f64) -> f64 {
6 if value == 0.0 { 0.0 } else { value }
7}
8
9#[derive(Clone, Copy, Debug, PartialEq)]
14pub struct Point3M {
15 x: Metres,
16 y: Metres,
17 z: Metres,
18}
19
20impl Point3M {
21 pub fn new(x: Metres, y: Metres, z: Metres) -> Self {
23 Self { x, y, z }
24 }
25
26 pub fn from_metres(x: f64, y: f64, z: f64) -> Result<Self, InterferenceError> {
28 Ok(Self::new(Metres::new(x)?, Metres::new(y)?, Metres::new(z)?))
29 }
30
31 pub fn x(self) -> Metres {
33 self.x
34 }
35
36 pub fn y(self) -> Metres {
38 self.y
39 }
40
41 pub fn z(self) -> Metres {
43 self.z
44 }
45
46 pub fn coordinates_metres(self) -> [f64; 3] {
48 [self.x.get(), self.y.get(), self.z.get()]
49 }
50
51 pub fn distance_to(self, other: Self) -> f64 {
56 let [x, y, z] = self.coordinates_metres();
57 let [other_x, other_y, other_z] = other.coordinates_metres();
58 (x - other_x).hypot(y - other_y).hypot(z - other_z)
59 }
60}
61
62#[derive(Clone, Copy, Debug, PartialEq)]
67pub struct UnitVector3 {
68 x: f64,
69 y: f64,
70 z: f64,
71}
72
73impl UnitVector3 {
74 pub fn new(x: f64, y: f64, z: f64) -> Result<Self, InterferenceError> {
76 if !x.is_finite() || !y.is_finite() || !z.is_finite() {
77 return Err(InterferenceError::InvalidDirection { x, y, z });
78 }
79 let scale = x.abs().max(y.abs()).max(z.abs());
80 if scale == 0.0 {
81 return Err(InterferenceError::InvalidDirection { x, y, z });
82 }
83
84 let scaled_x = x / scale;
85 let scaled_y = y / scale;
86 let scaled_z = z / scale;
87 let norm = scaled_x.hypot(scaled_y).hypot(scaled_z);
88
89 Ok(Self {
90 x: canonical_zero(scaled_x / norm),
91 y: canonical_zero(scaled_y / norm),
92 z: canonical_zero(scaled_z / norm),
93 })
94 }
95
96 pub fn components(self) -> [f64; 3] {
98 [self.x, self.y, self.z]
99 }
100
101 pub fn signed_distance_metres(self, from: Point3M, to: Point3M) -> f64 {
106 let [from_x, from_y, from_z] = from.coordinates_metres();
107 let [to_x, to_y, to_z] = to.coordinates_metres();
108 self.x * (to_x - from_x) + self.y * (to_y - from_y) + self.z * (to_z - from_z)
109 }
110}