1use crate::NearlyEqual;
2
3#[derive(Copy, Clone, Debug, PartialEq)]
5#[repr(C)]
6pub struct Vector2 {
7 pub x: f32,
8 pub y: f32,
9}
10
11#[derive(Copy, Clone, Debug, PartialEq)]
13#[repr(C)]
14pub struct Vector3 {
15 pub x: f32,
16 pub y: f32,
17 pub z: f32,
18}
19
20#[derive(Copy, Clone, Debug, PartialEq)]
22#[repr(C)]
23pub struct Point {
24 pub x: f32,
25 pub y: f32,
26 pub z: f32,
27}
28
29#[derive(Copy, Clone, Debug, PartialEq)]
31#[repr(C)]
32pub struct Vector4 {
33 pub x: f32,
34 pub y: f32,
35 pub z: f32,
36 pub w: f32,
37}
38
39macro_rules! implement_operator {
40 (impl $Op:ident<$S:ident> for $T:ident {
42 fn $op:ident($x:ident, $s:ident) -> $Output:ty $body:block
43 }) => {
44 impl std::ops::$Op<$S> for $T {
45 type Output = $Output;
46
47 fn $op($x, $s: $S) -> Self::Output $body
48 }
49 };
50 (impl $Op:ident<$S:ident> for $T:ident {
52 fn $op:ident(&mut $x:ident, $s:ident) $body:block
53 }) => {
54 impl std::ops::$Op<$S> for $T {
55 fn $op(&mut $x, $s: $S) $body
56 }
57 };
58}
59
60macro_rules! implement_vector {
61 ($VectorT:ident { $($field:ident),+ }) => {
62 impl $VectorT {
63 pub const fn new($($field: f32),+) -> Self {
65 Self { $($field),+ }
66 }
67
68 pub const fn from_scalar(s: f32) -> Self {
70 Self { $($field: s),+ }
71 }
72
73 pub const fn zero() -> Self {
75 Self { $($field: 0.0),+ }
76 }
77
78 pub const fn one() -> Self {
80 Self { $($field: 1.0),+ }
81 }
82
83 pub fn dot(&self, rhs: Self) -> f32 {
85 [$(self.$field * rhs.$field),+].iter().sum()
86 }
87
88 pub fn lerp(&self, rhs: Self, factor: f32) -> Self {
90 let t = factor.min(1.0).max(0.0);
91 Self::new($(self.$field * (1.0 - t) + rhs.$field * t),+)
92 }
93
94 pub fn min(&self, rhs: Self) -> Self {
96 Self::new($(self.$field.min(rhs.$field)),+)
97 }
98
99 pub fn max(&self, rhs: Self) -> Self {
101 Self::new($(self.$field.max(rhs.$field)),+)
102 }
103
104 pub fn magnitude_squared(&self) -> f32 {
106 self.dot(*self)
107 }
108
109 pub fn magnitude(&self) -> f32 {
111 self.magnitude_squared().sqrt()
112 }
113
114 pub fn normalized(&self) -> Self {
116 let d = self.magnitude();
117 if d > 0.0 {
118 let d = 1.0 / d;
119 *self * d
120 } else {
121 *self
122 }
123 }
124
125 pub fn as_slice(&self) -> &[f32] {
126 unsafe { std::slice::from_raw_parts(&self.x, std::mem::size_of::<Self>() / std::mem::size_of::<f32>()) }
127 }
128 }
129
130 impl std::ops::Neg for $VectorT {
131 type Output = $VectorT;
132 fn neg(self) -> $VectorT { $VectorT::new($(-self.$field),+) }
133 }
134
135 implement_operator!(impl Add<f32> for $VectorT {
136 fn add(self, t) -> $VectorT { $VectorT::new($(self.$field + t),+) }
137 });
138 implement_operator!(impl Sub<f32> for $VectorT {
139 fn sub(self, t) -> $VectorT { $VectorT::new($(self.$field - t),+) }
140 });
141 implement_operator!(impl Mul<f32> for $VectorT {
142 fn mul(self, t) -> $VectorT { $VectorT::new($(self.$field * t),+) }
143 });
144 implement_operator!(impl Div<f32> for $VectorT {
145 fn div(self, t) -> $VectorT { $VectorT::new($(self.$field / t),+) }
146 });
147
148 implement_operator!(impl AddAssign<f32> for $VectorT {
149 fn add_assign(&mut self, t) { $(self.$field += t);+ }
150 });
151 implement_operator!(impl SubAssign<f32> for $VectorT {
152 fn sub_assign(&mut self, t) { $(self.$field -= t);+ }
153 });
154 implement_operator!(impl MulAssign<f32> for $VectorT {
155 fn mul_assign(&mut self, t) { $(self.$field *= t);+ }
156 });
157 implement_operator!(impl DivAssign<f32> for $VectorT {
158 fn div_assign(&mut self, t) { $(self.$field /= t);+ }
159 });
160
161 implement_operator!(impl Mul<$VectorT> for f32 {
162 fn mul(self, t) -> $VectorT { $VectorT::new($(self * t.$field),+) }
163 });
164 implement_operator!(impl Div<$VectorT> for f32 {
165 fn div(self, t) -> $VectorT { $VectorT::new($(self / t.$field),+) }
166 });
167
168 impl std::ops::Index<usize> for $VectorT {
169 type Output = f32;
170 fn index(&self, i: usize) -> &f32 {
171 [$(&self.$field),+][i]
172 }
173 }
174
175 impl std::ops::IndexMut<usize> for $VectorT {
176 fn index_mut(&mut self, i: usize) -> &mut f32 {
177 [$(&mut self.$field),+][i]
178 }
179 }
180
181 impl NearlyEqual for &$VectorT {
182 fn nearly_equals(self, rhs: Self) -> bool {
183 $(self.$field.nearly_equals(rhs.$field))&&+
184 }
185 }
186 }
187}
188
189implement_vector!(Vector2 { x, y });
190implement_vector!(Vector3 { x, y, z });
191implement_vector!(Point { x, y, z });
192implement_vector!(Vector4 { x, y, z, w });
193
194impl Vector2 {
195 pub fn cross(&self, rhs: Self) -> f32 {
199 self.x * rhs.y - self.y * rhs.x
200 }
201}
202
203impl Vector3 {
204 pub fn cross(&self, rhs: Self) -> Self {
206 Self {
207 x: self.y * rhs.z - self.z * rhs.y,
208 y: self.z * rhs.x - self.x * rhs.z,
209 z: self.x * rhs.y - self.y * rhs.x,
210 }
211 }
212}
213
214impl From<Point> for Vector3 {
215 fn from(p: Point) -> Self {
217 Vector3 {
218 x: p.x,
219 y: p.y,
220 z: p.z,
221 }
222 }
223}
224
225impl From<Vector4> for Vector3 {
226 fn from(v: Vector4) -> Self {
228 Vector3 {
229 x: v.x,
230 y: v.y,
231 z: v.z,
232 }
233 }
234}
235
236impl From<Vector3> for Point {
237 fn from(v: Vector3) -> Self {
239 Point {
240 x: v.x,
241 y: v.y,
242 z: v.z,
243 }
244 }
245}
246
247impl From<Vector4> for Point {
248 fn from(v: Vector4) -> Self {
250 Point {
251 x: v.x,
252 y: v.y,
253 z: v.z,
254 }
255 }
256}
257
258impl From<Vector3> for Vector4 {
259 fn from(v: Vector3) -> Self {
261 Vector4 {
262 x: v.x,
263 y: v.y,
264 z: v.z,
265 w: 0.0,
266 }
267 }
268}
269
270impl From<Point> for Vector4 {
271 fn from(p: Point) -> Self {
273 Vector4 {
274 x: p.x,
275 y: p.y,
276 z: p.z,
277 w: 1.0,
278 }
279 }
280}
281
282#[cfg(test)]
283mod tests {
284 use crate::*;
285
286 #[test]
287 fn products() {
288 let a = Vector3::new(3.0, -5.0, 4.0);
289 let b = Vector3::new(2.0, 6.0, 5.0);
290
291 assert!(a.dot(b).nearly_equals(-4.0));
292 assert_eq!(a.cross(b), Vector3::new(-49.0, -7.0, 28.0));
293 }
294
295 #[test]
296 fn lerp() {
297 let a = Vector3::new(1.0, 0.0, 0.0);
298 let b = Vector3::new(0.0, 1.0, 0.0);
299
300 assert_eq!(a.lerp(b, 0.75), Vector3::new(0.25, 0.75, 0.0));
301 }
302
303 #[test]
304 fn slice() {
305 let a = Vector3::new(1.0, 2.0, 3.0);
306
307 assert_eq!(a.as_slice(), &[1.0, 2.0, 3.0]);
308 }
309}