Skip to main content

ferroui_base/numerics/
vector4.rs

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