open_dis_rust/common/
vector3_float.rs

1//     open-dis-rust - Rust implementation of the IEEE 1278.1-2012 Distributed Interactive
2//                     Simulation (DIS) application protocol
3//     Copyright (C) 2023 Cameron Howell
4//
5//     Licensed under the BSD 2-Clause License
6
7use bytes::{Buf, BufMut, BytesMut};
8
9#[derive(Copy, Clone, Debug, Default, PartialEq)]
10/// Custom vector type containing 3 single precision fields
11pub struct Vector3Float {
12    /// The first value within the vector
13    pub x: f32,
14    /// The second value within the vector
15    pub y: f32,
16    /// The third value within the vector
17    pub z: f32,
18}
19
20impl Vector3Float {
21    /// Creates a new vector with the given components.
22    #[must_use]
23    pub const fn new(x: f32, y: f32, z: f32) -> Self {
24        Vector3Float { x, y, z }
25    }
26
27    /// Creates a new vector with all components set to zero.
28    #[must_use]
29    pub const fn zero() -> Self {
30        Self::new(0.0, 0.0, 0.0)
31    }
32
33    /// Creates a new vector with all components set to one.
34    #[must_use]
35    pub const fn one() -> Self {
36        Self::new(1.0, 1.0, 1.0)
37    }
38
39    /// Creates a unit vector along the X axis.
40    #[must_use]
41    pub const fn unit_x() -> Self {
42        Self::new(1.0, 0.0, 0.0)
43    }
44
45    /// Creates a unit vector along the Y axis.
46    #[must_use]
47    pub const fn unit_y() -> Self {
48        Self::new(0.0, 1.0, 0.0)
49    }
50
51    /// Creates a unit vector along the Z axis.
52    #[must_use]
53    pub const fn unit_z() -> Self {
54        Self::new(0.0, 0.0, 1.0)
55    }
56
57    /// Computes the dot product with another vector.
58    #[must_use]
59    pub fn dot(&self, other: &Self) -> f32 {
60        self.x * other.x + self.y * other.y + self.z * other.z
61    }
62
63    /// Computes the cross product with another vector.
64    #[must_use]
65    pub fn cross(&self, other: &Self) -> Self {
66        Self::new(
67            self.y * other.z - self.z * other.y,
68            self.z * other.x - self.x * other.z,
69            self.x * other.y - self.y * other.x,
70        )
71    }
72
73    /// Computes the magnitude (length) of the vector.
74    #[must_use]
75    pub fn magnitude(&self) -> f32 {
76        (self.x * self.x + self.y * self.y + self.z * self.z).sqrt()
77    }
78
79    /// Returns a normalized version of this vector (unit length).
80    #[must_use]
81    pub fn normalize(&self) -> Option<Self> {
82        let mag = self.magnitude();
83        if mag == 0.0 {
84            None
85        } else {
86            Some(Self::new(self.x / mag, self.y / mag, self.z / mag))
87        }
88    }
89
90    pub fn serialize(&self, buf: &mut BytesMut) {
91        buf.put_f32(self.x);
92        buf.put_f32(self.y);
93        buf.put_f32(self.z);
94    }
95
96    pub fn deserialize(buf: &mut BytesMut) -> Vector3Float {
97        Vector3Float {
98            x: buf.get_f32(),
99            y: buf.get_f32(),
100            z: buf.get_f32(),
101        }
102    }
103}
104
105impl std::ops::Add for Vector3Float {
106    type Output = Self;
107
108    fn add(self, other: Self) -> Self {
109        Self::new(self.x + other.x, self.y + other.y, self.z + other.z)
110    }
111}
112
113impl std::ops::Sub for Vector3Float {
114    type Output = Self;
115
116    fn sub(self, other: Self) -> Self {
117        Self::new(self.x - other.x, self.y - other.y, self.z - other.z)
118    }
119}
120
121impl std::ops::Mul<f32> for Vector3Float {
122    type Output = Self;
123
124    fn mul(self, scalar: f32) -> Self {
125        Self::new(self.x * scalar, self.y * scalar, self.z * scalar)
126    }
127}
128
129impl std::ops::Div<f32> for Vector3Float {
130    type Output = Self;
131
132    fn div(self, scalar: f32) -> Self {
133        Self::new(self.x / scalar, self.y / scalar, self.z / scalar)
134    }
135}
136
137#[cfg(test)]
138mod tests {
139    use super::*;
140
141    #[test]
142    fn test_vector_operations() {
143        let v1 = Vector3Float::new(1.0, 2.0, 3.0);
144        let v2 = Vector3Float::new(4.0, 5.0, 6.0);
145
146        // Test addition
147        let sum = v1 + v2;
148        assert_eq!(sum, Vector3Float::new(5.0, 7.0, 9.0));
149
150        // Test dot product
151        let dot = v1.dot(&v2);
152        assert_eq!(dot, 32.0);
153
154        // Test cross product
155        let cross = v1.cross(&v2);
156        assert_eq!(cross, Vector3Float::new(-3.0, 6.0, -3.0));
157
158        // Test scalar multiplication
159        let scaled = v1 * 2.0;
160        assert_eq!(scaled, Vector3Float::new(2.0, 4.0, 6.0));
161
162        // Test normalization
163        let normalized = v1.normalize().unwrap();
164        let mag = normalized.magnitude();
165        assert!((mag - 1.0).abs() < f32::EPSILON);
166    }
167
168    #[test]
169    fn test_const_constructors() {
170        let zero = Vector3Float::zero();
171        assert_eq!(zero, Vector3Float::new(0.0, 0.0, 0.0));
172
173        let unit_x = Vector3Float::unit_x();
174        assert_eq!(unit_x, Vector3Float::new(1.0, 0.0, 0.0));
175    }
176}