Skip to main content

ferroui_base/numerics/
vector3.rs

1//! A vector with three single-precision components.
2
3use std::fmt;
4use std::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
5
6use super::single::{self, InvariantF32};
7use super::{Matrix4x4, Quaternion, Vector2};
8use crate::Vector3D;
9
10/// A vector with three single-precision components.
11///
12/// The layout is the one of the reference runtime and is relied on when the
13/// value is passed to a graphics API by address (as a vertex attribute, for
14/// example): three consecutive singles, `x`, `y`, `z`.
15#[derive(Clone, Copy, Debug, PartialEq, Default)]
16#[repr(C)]
17pub struct Vector3 {
18    /// The X component of the vector.
19    pub x: f32,
20    /// The Y component of the vector.
21    pub y: f32,
22    /// The Z component of the vector.
23    pub z: f32,
24}
25
26impl Vector3 {
27    /// The vector `(0, 0, 0)`.
28    pub const ZERO: Vector3 = Vector3::new(0.0, 0.0, 0.0);
29    /// The vector `(1, 1, 1)`.
30    pub const ONE: Vector3 = Vector3::new(1.0, 1.0, 1.0);
31    /// The vector `(1, 0, 0)`.
32    pub const UNIT_X: Vector3 = Vector3::new(1.0, 0.0, 0.0);
33    /// The vector `(0, 1, 0)`.
34    pub const UNIT_Y: Vector3 = Vector3::new(0.0, 1.0, 0.0);
35    /// The vector `(0, 0, 1)`.
36    pub const UNIT_Z: Vector3 = Vector3::new(0.0, 0.0, 1.0);
37
38    /// Creates a vector from its components.
39    #[inline]
40    pub const fn new(x: f32, y: f32, z: f32) -> Self {
41        Self { x, y, z }
42    }
43
44    /// Creates a vector whose components all have the same value.
45    #[inline]
46    pub const fn from_value(value: f32) -> Self {
47        Self::new(value, value, value)
48    }
49
50    /// Creates a vector from a [`Vector2`] and a Z component.
51    #[inline]
52    pub const fn from_vector2(value: Vector2, z: f32) -> Self {
53        Self::new(value.x, value.y, z)
54    }
55
56    /// Returns a vector whose elements are the absolute values of each of the
57    /// specified vector's elements.
58    #[inline]
59    pub fn abs(value: Vector3) -> Vector3 {
60        Vector3::new(value.x.abs(), value.y.abs(), value.z.abs())
61    }
62
63    /// Restricts a vector between a minimum and a maximum value
64    /// (`min(max(value, min), max)`, so `max` wins when the bounds are inverted).
65    #[inline]
66    pub fn clamp(value1: Vector3, min: Vector3, max: Vector3) -> Vector3 {
67        Vector3::min(Vector3::max(value1, min), max)
68    }
69
70    /// Computes the cross product of two vectors.
71    #[inline]
72    pub fn cross(vector1: Vector3, vector2: Vector3) -> Vector3 {
73        Vector3::new(
74            (vector1.y * vector2.z) - (vector1.z * vector2.y),
75            (vector1.z * vector2.x) - (vector1.x * vector2.z),
76            (vector1.x * vector2.y) - (vector1.y * vector2.x),
77        )
78    }
79
80    /// Computes the Euclidean distance between the two given points.
81    #[inline]
82    pub fn distance(value1: Vector3, value2: Vector3) -> f32 {
83        Vector3::distance_squared(value1, value2).sqrt()
84    }
85
86    /// Returns the Euclidean distance squared between two specified points.
87    #[inline]
88    pub fn distance_squared(value1: Vector3, value2: Vector3) -> f32 {
89        (value1 - value2).length_squared()
90    }
91
92    /// Returns the dot product of two vectors.
93    #[inline]
94    pub fn dot(vector1: Vector3, vector2: Vector3) -> f32 {
95        (vector1.x * vector2.x) + (vector1.y * vector2.y) + (vector1.z * vector2.z)
96    }
97
98    /// Returns the length of the vector.
99    #[inline]
100    pub fn length(&self) -> f32 {
101        self.length_squared().sqrt()
102    }
103
104    /// Returns the length of the vector squared.
105    #[inline]
106    pub fn length_squared(&self) -> f32 {
107        Vector3::dot(*self, *self)
108    }
109
110    /// Performs a linear interpolation between two vectors based on the given weighting.
111    #[inline]
112    pub fn lerp(value1: Vector3, value2: Vector3, amount: f32) -> Vector3 {
113        (value1 * (1.0 - amount)) + (value2 * amount)
114    }
115
116    /// Returns a vector whose elements are the maximum of each of the pairs of
117    /// elements in two specified vectors.
118    #[inline]
119    pub fn max(value1: Vector3, value2: Vector3) -> Vector3 {
120        Vector3::new(
121            single::max(value1.x, value2.x),
122            single::max(value1.y, value2.y),
123            single::max(value1.z, value2.z),
124        )
125    }
126
127    /// Returns a vector whose elements are the minimum of each of the pairs of
128    /// elements in two specified vectors.
129    #[inline]
130    pub fn min(value1: Vector3, value2: Vector3) -> Vector3 {
131        Vector3::new(
132            single::min(value1.x, value2.x),
133            single::min(value1.y, value2.y),
134            single::min(value1.z, value2.z),
135        )
136    }
137
138    /// Returns a vector with the same direction as the specified vector, but
139    /// with a length of one (NaN components for a zero-length vector).
140    #[inline]
141    pub fn normalize(value: Vector3) -> Vector3 {
142        value / value.length()
143    }
144
145    /// Returns a vector whose elements are the square root of each of a
146    /// specified vector's elements.
147    #[inline]
148    pub fn square_root(value: Vector3) -> Vector3 {
149        Vector3::new(value.x.sqrt(), value.y.sqrt(), value.z.sqrt())
150    }
151
152    /// Transforms a vector by a specified 4x4 matrix.
153    #[inline]
154    pub fn transform(position: Vector3, matrix: Matrix4x4) -> Vector3 {
155        Vector3::new(
156            (position.x * matrix.m11) + (position.y * matrix.m21) + (position.z * matrix.m31) + matrix.m41,
157            (position.x * matrix.m12) + (position.y * matrix.m22) + (position.z * matrix.m32) + matrix.m42,
158            (position.x * matrix.m13) + (position.y * matrix.m23) + (position.z * matrix.m33) + matrix.m43,
159        )
160    }
161
162    /// Transforms a vector by the specified rotation.
163    pub fn transform_quaternion(value: Vector3, rotation: Quaternion) -> Vector3 {
164        let x2 = rotation.x + rotation.x;
165        let y2 = rotation.y + rotation.y;
166        let z2 = rotation.z + rotation.z;
167
168        let wx2 = rotation.w * x2;
169        let wy2 = rotation.w * y2;
170        let wz2 = rotation.w * z2;
171        let xx2 = rotation.x * x2;
172        let xy2 = rotation.x * y2;
173        let xz2 = rotation.x * z2;
174        let yy2 = rotation.y * y2;
175        let yz2 = rotation.y * z2;
176        let zz2 = rotation.z * z2;
177
178        Vector3::new(
179            value.x * (1.0 - yy2 - zz2) + value.y * (xy2 - wz2) + value.z * (xz2 + wy2),
180            value.x * (xy2 + wz2) + value.y * (1.0 - xx2 - zz2) + value.z * (yz2 - wx2),
181            value.x * (xz2 - wy2) + value.y * (yz2 + wx2) + value.z * (1.0 - xx2 - yy2),
182        )
183    }
184
185    /// Transforms a vector normal by the given 4x4 matrix.
186    #[inline]
187    pub fn transform_normal(normal: Vector3, matrix: Matrix4x4) -> Vector3 {
188        Vector3::new(
189            (normal.x * matrix.m11) + (normal.y * matrix.m21) + (normal.z * matrix.m31),
190            (normal.x * matrix.m12) + (normal.y * matrix.m22) + (normal.z * matrix.m32),
191            (normal.x * matrix.m13) + (normal.y * matrix.m23) + (normal.z * matrix.m33),
192        )
193    }
194}
195
196/// The narrowing conversion of the double-precision vector.
197impl From<Vector3D> for Vector3 {
198    #[inline]
199    fn from(value: Vector3D) -> Vector3 {
200        Vector3::new(value.x as f32, value.y as f32, value.z as f32)
201    }
202}
203
204/// The widening conversion to the double-precision vector.
205impl From<Vector3> for Vector3D {
206    #[inline]
207    fn from(value: Vector3) -> Vector3D {
208        Vector3D::new(value.x as f64, value.y as f64, value.z as f64)
209    }
210}
211
212impl Add for Vector3 {
213    type Output = Vector3;
214    #[inline]
215    fn add(self, right: Vector3) -> Vector3 {
216        Vector3::new(self.x + right.x, self.y + right.y, self.z + right.z)
217    }
218}
219
220impl Sub for Vector3 {
221    type Output = Vector3;
222    #[inline]
223    fn sub(self, right: Vector3) -> Vector3 {
224        Vector3::new(self.x - right.x, self.y - right.y, self.z - right.z)
225    }
226}
227
228impl Mul for Vector3 {
229    type Output = Vector3;
230    #[inline]
231    fn mul(self, right: Vector3) -> Vector3 {
232        Vector3::new(self.x * right.x, self.y * right.y, self.z * right.z)
233    }
234}
235
236impl Mul<f32> for Vector3 {
237    type Output = Vector3;
238    #[inline]
239    fn mul(self, right: f32) -> Vector3 {
240        Vector3::new(self.x * right, self.y * right, self.z * right)
241    }
242}
243
244impl Mul<Vector3> for f32 {
245    type Output = Vector3;
246    #[inline]
247    fn mul(self, right: Vector3) -> Vector3 {
248        right * self
249    }
250}
251
252impl Div for Vector3 {
253    type Output = Vector3;
254    #[inline]
255    fn div(self, right: Vector3) -> Vector3 {
256        Vector3::new(self.x / right.x, self.y / right.y, self.z / right.z)
257    }
258}
259
260impl Div<f32> for Vector3 {
261    type Output = Vector3;
262    #[inline]
263    fn div(self, right: f32) -> Vector3 {
264        Vector3::new(self.x / right, self.y / right, self.z / right)
265    }
266}
267
268impl Neg for Vector3 {
269    type Output = Vector3;
270    #[inline]
271    fn neg(self) -> Vector3 {
272        Vector3::new(-self.x, -self.y, -self.z)
273    }
274}
275
276impl AddAssign for Vector3 {
277    #[inline]
278    fn add_assign(&mut self, right: Vector3) {
279        *self = *self + right;
280    }
281}
282
283impl SubAssign for Vector3 {
284    #[inline]
285    fn sub_assign(&mut self, right: Vector3) {
286        *self = *self - right;
287    }
288}
289
290impl MulAssign for Vector3 {
291    #[inline]
292    fn mul_assign(&mut self, right: Vector3) {
293        *self = *self * right;
294    }
295}
296
297impl MulAssign<f32> for Vector3 {
298    #[inline]
299    fn mul_assign(&mut self, right: f32) {
300        *self = *self * right;
301    }
302}
303
304impl DivAssign for Vector3 {
305    #[inline]
306    fn div_assign(&mut self, right: Vector3) {
307        *self = *self / right;
308    }
309}
310
311impl DivAssign<f32> for Vector3 {
312    #[inline]
313    fn div_assign(&mut self, right: f32) {
314        *self = *self / right;
315    }
316}
317
318impl fmt::Display for Vector3 {
319    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
320        write!(
321            f,
322            "<{}, {}, {}>",
323            InvariantF32(self.x),
324            InvariantF32(self.y),
325            InvariantF32(self.z)
326        )
327    }
328}