Skip to main content

fyrox_math/
lib.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21// Clippy complains about normal mathematical symbols like A, B, C for quadratic equation.
22#![allow(clippy::many_single_char_names)]
23
24pub mod aabb;
25pub mod curve;
26pub mod frustum;
27pub mod octree;
28pub mod plane;
29pub mod ray;
30pub mod segment;
31pub mod triangulator;
32
33use crate::ray::IntersectionResult;
34use bytemuck::{Pod, Zeroable};
35use nalgebra::{
36    Matrix3, Matrix4, RealField, Scalar, SimdRealField, UnitQuaternion, Vector2, Vector3,
37};
38use std::{
39    fmt::Debug,
40    hash::{Hash, Hasher},
41    ops::{Index, IndexMut},
42};
43
44pub use rectutils::*;
45
46#[derive(Copy, Clone)]
47pub enum PlaneClass {
48    XY,
49    YZ,
50    XZ,
51}
52
53#[inline]
54#[allow(clippy::useless_let_if_seq)]
55pub fn classify_plane(normal: Vector3<f32>) -> PlaneClass {
56    let mut longest = 0.0f32;
57    let mut class = PlaneClass::XY;
58
59    if normal.x.abs() > longest {
60        longest = normal.x.abs();
61        class = PlaneClass::YZ;
62    }
63
64    if normal.y.abs() > longest {
65        longest = normal.y.abs();
66        class = PlaneClass::XZ;
67    }
68
69    if normal.z.abs() > longest {
70        class = PlaneClass::XY;
71    }
72
73    class
74}
75
76#[inline]
77pub fn get_polygon_normal(polygon: &[Vector3<f32>]) -> Result<Vector3<f32>, &'static str> {
78    let mut normal = Vector3::default();
79
80    for (i, current) in polygon.iter().enumerate() {
81        let next = polygon[(i + 1) % polygon.len()];
82        normal.x += (current.y - next.y) * (current.z + next.z);
83        normal.y += (current.z - next.z) * (current.x + next.x);
84        normal.z += (current.x - next.x) * (current.y + next.y);
85    }
86
87    normal
88        .try_normalize(f32::EPSILON)
89        .ok_or("Unable to get normal of degenerated polygon!")
90}
91
92#[inline]
93pub fn get_signed_triangle_area(v1: Vector2<f32>, v2: Vector2<f32>, v3: Vector2<f32>) -> f32 {
94    0.5 * (v1.x * (v3.y - v2.y) + v2.x * (v1.y - v3.y) + v3.x * (v2.y - v1.y))
95}
96
97#[inline]
98pub fn vec3_to_vec2_by_plane(
99    plane_class: PlaneClass,
100    normal: Vector3<f32>,
101    point: Vector3<f32>,
102) -> Vector2<f32> {
103    match plane_class {
104        PlaneClass::XY => {
105            if normal.z < 0.0 {
106                Vector2::new(point.y, point.x)
107            } else {
108                Vector2::new(point.x, point.y)
109            }
110        }
111        PlaneClass::XZ => {
112            if normal.y < 0.0 {
113                Vector2::new(point.x, point.z)
114            } else {
115                Vector2::new(point.z, point.x)
116            }
117        }
118        PlaneClass::YZ => {
119            if normal.x < 0.0 {
120                Vector2::new(point.z, point.y)
121            } else {
122                Vector2::new(point.y, point.z)
123            }
124        }
125    }
126}
127
128#[inline]
129pub fn is_point_inside_2d_triangle(
130    point: Vector2<f32>,
131    pt_a: Vector2<f32>,
132    pt_b: Vector2<f32>,
133    pt_c: Vector2<f32>,
134) -> bool {
135    let ba = pt_b - pt_a;
136    let ca = pt_c - pt_a;
137
138    let vp = point - pt_a;
139
140    let ba_dot_ba = ba.dot(&ba);
141    let ca_dot_ba = ca.dot(&ba);
142    let ca_dot_ca = ca.dot(&ca);
143
144    let dot_02 = ca.dot(&vp);
145    let dot_12 = ba.dot(&vp);
146
147    let inv_denom = 1.0 / (ca_dot_ca * ba_dot_ba - ca_dot_ba.powi(2));
148
149    // calculate barycentric coordinates
150    let u = (ba_dot_ba * dot_02 - ca_dot_ba * dot_12) * inv_denom;
151    let v = (ca_dot_ca * dot_12 - ca_dot_ba * dot_02) * inv_denom;
152
153    (u >= 0.0) && (v >= 0.0) && (u + v < 1.0)
154}
155
156#[inline]
157pub fn wrap_angle(angle: f32) -> f32 {
158    let two_pi = 2.0 * std::f32::consts::PI;
159
160    if angle > 0.0 {
161        angle % two_pi
162    } else {
163        (angle + two_pi) % two_pi
164    }
165}
166
167/// There are two versions of remainder, the standard `%` operator which does `x - (x/y).trunc()*y` and IEEE remainder which does `x - (x/y).round()*y`.
168#[inline]
169pub fn ieee_remainder(x: f32, y: f32) -> f32 {
170    x - (x / y).round() * y
171}
172
173#[inline]
174pub fn round_to_step(x: f32, step: f32) -> f32 {
175    x - ieee_remainder(x, step)
176}
177
178#[inline]
179pub fn wrapf(mut n: f32, mut min_limit: f32, mut max_limit: f32) -> f32 {
180    if n >= min_limit && n <= max_limit {
181        return n;
182    }
183
184    if max_limit == 0.0 && min_limit == 0.0 {
185        return 0.0;
186    }
187
188    max_limit -= min_limit;
189
190    let offset = min_limit;
191    min_limit = 0.0;
192    n -= offset;
193
194    let num_of_max = (n / max_limit).abs().floor();
195
196    if n >= max_limit {
197        n -= num_of_max * max_limit;
198    } else if n < min_limit {
199        n += (num_of_max + 1.0) * max_limit;
200    }
201
202    n + offset
203}
204
205#[inline(always)]
206pub fn lerpf(a: f32, b: f32, t: f32) -> f32 {
207    a + (b - a) * t
208}
209
210// https://en.wikipedia.org/wiki/Cubic_Hermite_spline
211#[inline]
212pub fn cubicf(p0: f32, p1: f32, t: f32, m0: f32, m1: f32) -> f32 {
213    let t2 = t * t;
214    let t3 = t2 * t;
215    let scale = (p1 - p0).abs();
216
217    (2.0 * t3 - 3.0 * t2 + 1.0) * p0
218        + (t3 - 2.0 * t2 + t) * m0 * scale
219        + (-2.0 * t3 + 3.0 * t2) * p1
220        + (t3 - t2) * m1 * scale
221}
222
223#[inline]
224pub fn cubicf_derivative(p0: f32, p1: f32, t: f32, m0: f32, m1: f32) -> f32 {
225    let t2 = t * t;
226    let scale = (p1 - p0).abs();
227
228    (6.0 * t2 - 6.0 * t) * p0
229        + (3.0 * t2 - 4.0 * t + 1.0) * m0 * scale
230        + (6.0 * t - 6.0 * t2) * p1
231        + (3.0 * t2 - 2.0 * t) * m1 * scale
232}
233
234#[inline]
235pub fn inf_sup_cubicf(p0: f32, p1: f32, m0: f32, m1: f32) -> (f32, f32) {
236    // Find two `t`s where derivative of cubicf is zero - these will be
237    // extreme points of the spline. Then get the values at those `t`s
238    let d = -(9.0 * p0 * p0 + 6.0 * p0 * (-3.0 * p1 + m1 + m0) + 9.0 * p1 * p1
239        - 6.0 * p1 * (m1 + m0)
240        + m1 * m1
241        + m1 * m0
242        + m0 * m0)
243        .sqrt();
244    let k = 3.0 * (2.0 * p0 - 2.0 * p1 + m1 + m0);
245    let v = 3.0 * p0 - 3.0 * p1 + m1 + 2.0 * m0;
246    let t0 = (-d + v) / k;
247    let t1 = (d + v) / k;
248    (cubicf(p0, p1, t0, m0, m1), cubicf(p0, p1, t1, m0, m1))
249}
250
251#[inline]
252pub fn get_farthest_point(points: &[Vector3<f32>], dir: Vector3<f32>) -> Vector3<f32> {
253    let mut n_farthest = 0;
254    let mut max_dot = -f32::MAX;
255    for (i, point) in points.iter().enumerate() {
256        let dot = dir.dot(point);
257        if dot > max_dot {
258            n_farthest = i;
259            max_dot = dot
260        }
261    }
262    points[n_farthest]
263}
264
265#[inline]
266pub fn get_barycentric_coords(
267    p: &Vector3<f32>,
268    a: &Vector3<f32>,
269    b: &Vector3<f32>,
270    c: &Vector3<f32>,
271) -> (f32, f32, f32) {
272    let v0 = *b - *a;
273    let v1 = *c - *a;
274    let v2 = *p - *a;
275
276    let d00 = v0.dot(&v0);
277    let d01 = v0.dot(&v1);
278    let d11 = v1.dot(&v1);
279    let d20 = v2.dot(&v0);
280    let d21 = v2.dot(&v1);
281    let denom = d00 * d11 - d01.powi(2);
282
283    let v = (d11 * d20 - d01 * d21) / denom;
284    let w = (d00 * d21 - d01 * d20) / denom;
285    let u = 1.0 - v - w;
286
287    (u, v, w)
288}
289
290#[inline]
291pub fn get_barycentric_coords_2d(
292    p: Vector2<f32>,
293    a: Vector2<f32>,
294    b: Vector2<f32>,
295    c: Vector2<f32>,
296) -> (f32, f32, f32) {
297    let v0 = b - a;
298    let v1 = c - a;
299    let v2 = p - a;
300
301    let d00 = v0.dot(&v0);
302    let d01 = v0.dot(&v1);
303    let d11 = v1.dot(&v1);
304    let d20 = v2.dot(&v0);
305    let d21 = v2.dot(&v1);
306    let inv_denom = 1.0 / (d00 * d11 - d01.powi(2));
307
308    let v = (d11 * d20 - d01 * d21) * inv_denom;
309    let w = (d00 * d21 - d01 * d20) * inv_denom;
310    let u = 1.0 - v - w;
311
312    (u, v, w)
313}
314
315#[inline]
316pub fn barycentric_to_world(
317    bary: (f32, f32, f32),
318    pa: Vector3<f32>,
319    pb: Vector3<f32>,
320    pc: Vector3<f32>,
321) -> Vector3<f32> {
322    pa.scale(bary.0) + pb.scale(bary.1) + pc.scale(bary.2)
323}
324
325#[inline]
326pub fn barycentric_is_inside(bary: (f32, f32, f32)) -> bool {
327    (bary.0 >= 0.0) && (bary.1 >= 0.0) && (bary.0 + bary.1 < 1.0)
328}
329
330#[inline]
331pub fn is_point_inside_triangle(p: &Vector3<f32>, vertices: &[Vector3<f32>; 3]) -> bool {
332    let ba = vertices[1] - vertices[0];
333    let ca = vertices[2] - vertices[0];
334    let vp = *p - vertices[0];
335
336    let ba_dot_ba = ba.dot(&ba);
337    let ca_dot_ba = ca.dot(&ba);
338    let ca_dot_ca = ca.dot(&ca);
339
340    let dot02 = ca.dot(&vp);
341    let dot12 = ba.dot(&vp);
342
343    let inv_denom = 1.0 / (ca_dot_ca * ba_dot_ba - ca_dot_ba.powi(2));
344
345    // Calculate barycentric coordinates
346    let u = (ba_dot_ba * dot02 - ca_dot_ba * dot12) * inv_denom;
347    let v = (ca_dot_ca * dot12 - ca_dot_ba * dot02) * inv_denom;
348
349    (u >= 0.0) && (v >= 0.0) && (u + v < 1.0)
350}
351
352#[inline]
353pub fn triangle_area(a: Vector3<f32>, b: Vector3<f32>, c: Vector3<f32>) -> f32 {
354    (b - a).cross(&(c - a)).norm() * 0.5
355}
356
357#[inline]
358pub fn solve_quadratic(a: f32, b: f32, c: f32) -> Option<[f32; 2]> {
359    let discriminant = b * b - 4.0 * a * c;
360    if discriminant < 0.0 {
361        // No real roots
362        None
363    } else {
364        // Dont care if quadratic equation has only one root (discriminant == 0), this is edge-case
365        // which requires additional branching instructions which is not good for branch-predictor in CPU.
366        let _2a = 2.0 * a;
367        let discr_root = discriminant.sqrt();
368        let r1 = (-b + discr_root) / _2a;
369        let r2 = (-b - discr_root) / _2a;
370        Some([r1, r2])
371    }
372}
373
374#[inline]
375pub fn spherical_to_cartesian(azimuth: f32, elevation: f32, radius: f32) -> Vector3<f32> {
376    let x = radius * elevation.sin() * azimuth.sin();
377    let y = radius * elevation.cos();
378    let z = -radius * elevation.sin() * azimuth.cos();
379    Vector3::new(x, y, z)
380}
381
382#[inline]
383pub fn ray_rect_intersection(
384    rect: Rect<f32>,
385    origin: Vector2<f32>,
386    dir: Vector2<f32>,
387) -> Option<IntersectionResult> {
388    let min = rect.left_top_corner();
389    let max = rect.right_bottom_corner();
390
391    let (mut tmin, mut tmax) = if dir.x >= 0.0 {
392        ((min.x - origin.x) / dir.x, (max.x - origin.x) / dir.x)
393    } else {
394        ((max.x - origin.x) / dir.x, (min.x - origin.x) / dir.x)
395    };
396
397    let (tymin, tymax) = if dir.y >= 0.0 {
398        ((min.y - origin.y) / dir.y, (max.y - origin.y) / dir.y)
399    } else {
400        ((max.y - origin.y) / dir.y, (min.y - origin.y) / dir.y)
401    };
402
403    if tmin > tymax || tymin > tmax {
404        return None;
405    }
406    if tymin > tmin {
407        tmin = tymin;
408    }
409    if tymax < tmax {
410        tmax = tymax;
411    }
412    if tmin <= 1.0 && tmax >= 0.0 {
413        Some(IntersectionResult {
414            min: tmin,
415            max: tmax,
416        })
417    } else {
418        None
419    }
420}
421
422#[derive(Clone, Copy, Debug, Default)]
423#[repr(C)]
424pub struct TriangleEdge {
425    pub a: u32,
426    pub b: u32,
427}
428
429impl PartialEq for TriangleEdge {
430    fn eq(&self, other: &Self) -> bool {
431        self.a == other.a && self.b == other.b || self.a == other.b && self.b == other.a
432    }
433}
434
435impl Eq for TriangleEdge {}
436
437impl Hash for TriangleEdge {
438    fn hash<H: Hasher>(&self, state: &mut H) {
439        // Direction-agnostic hash.
440        (self.a as u64 + self.b as u64).hash(state)
441    }
442}
443
444#[derive(Clone, Copy, PartialEq, Eq, Debug, Default, Hash, Pod, Zeroable)]
445#[repr(C)]
446pub struct TriangleDefinition(pub [u32; 3]);
447
448impl TriangleDefinition {
449    #[inline]
450    pub fn indices(&self) -> &[u32] {
451        self.as_ref()
452    }
453
454    #[inline]
455    pub fn indices_mut(&mut self) -> &mut [u32] {
456        self.as_mut()
457    }
458
459    #[inline]
460    pub fn edges(&self) -> [TriangleEdge; 3] {
461        [
462            TriangleEdge {
463                a: self.0[0],
464                b: self.0[1],
465            },
466            TriangleEdge {
467                a: self.0[1],
468                b: self.0[2],
469            },
470            TriangleEdge {
471                a: self.0[2],
472                b: self.0[0],
473            },
474        ]
475    }
476
477    #[inline]
478    pub fn add(&self, i: u32) -> Self {
479        Self([self.0[0] + i, self.0[1] + i, self.0[2] + i])
480    }
481}
482
483impl Index<usize> for TriangleDefinition {
484    type Output = u32;
485
486    #[inline]
487    fn index(&self, index: usize) -> &Self::Output {
488        &self.0[index]
489    }
490}
491
492impl IndexMut<usize> for TriangleDefinition {
493    #[inline]
494    fn index_mut(&mut self, index: usize) -> &mut Self::Output {
495        &mut self.0[index]
496    }
497}
498
499pub trait PositionProvider: Sized {
500    fn position(&self) -> Vector3<f32>;
501}
502
503impl PositionProvider for Vector3<f32> {
504    #[inline]
505    fn position(&self) -> Vector3<f32> {
506        *self
507    }
508}
509
510impl AsRef<[u32]> for TriangleDefinition {
511    #[inline]
512    fn as_ref(&self) -> &[u32] {
513        &self.0
514    }
515}
516
517impl AsMut<[u32]> for TriangleDefinition {
518    #[inline]
519    fn as_mut(&mut self) -> &mut [u32] {
520        &mut self.0
521    }
522}
523
524/// Tries to find a point closest to given point.
525///
526/// # Notes
527///
528/// O(n) complexity.
529#[inline]
530pub fn get_closest_point<P: PositionProvider>(points: &[P], point: Vector3<f32>) -> Option<usize> {
531    let mut closest_sqr_distance = f32::MAX;
532    let mut closest_index = None;
533    for (i, vertex) in points.iter().enumerate() {
534        let sqr_distance = (vertex.position() - point).norm_squared();
535        if sqr_distance < closest_sqr_distance {
536            closest_sqr_distance = sqr_distance;
537            closest_index = Some(i);
538        }
539    }
540    closest_index
541}
542
543/// Returns a tuple of (point index; triangle index) closest to the given point.
544#[inline]
545pub fn get_closest_point_triangles<P>(
546    points: &[P],
547    triangles: &[TriangleDefinition],
548    triangle_indices: impl Iterator<Item = usize>,
549    point: Vector3<f32>,
550) -> Option<(usize, usize)>
551where
552    P: PositionProvider,
553{
554    let mut closest_sqr_distance = f32::MAX;
555    let mut closest_index = None;
556    for triangle_index in triangle_indices {
557        let triangle = triangles.get(triangle_index).unwrap();
558        for point_index in triangle.0.iter() {
559            let vertex = points.get(*point_index as usize).unwrap();
560            let sqr_distance = (vertex.position() - point).norm_squared();
561            if sqr_distance < closest_sqr_distance {
562                closest_sqr_distance = sqr_distance;
563                closest_index = Some((*point_index as usize, triangle_index));
564            }
565        }
566    }
567    closest_index
568}
569
570#[inline]
571pub fn get_arbitrary_line_perpendicular(
572    begin: Vector3<f32>,
573    end: Vector3<f32>,
574) -> Option<Vector3<f32>> {
575    let dir = (end - begin).try_normalize(f32::EPSILON)?;
576    for axis in [Vector3::z(), Vector3::y(), Vector3::x()] {
577        let perp = dir.cross(&axis);
578        if perp.norm_squared().ne(&0.0) {
579            return Some(perp);
580        }
581    }
582    None
583}
584
585/// Returns a tuple of (point index; triangle index) closest to the given point.
586#[inline]
587pub fn get_closest_point_triangle_set<P>(
588    points: &[P],
589    triangles: &[TriangleDefinition],
590    point: Vector3<f32>,
591) -> Option<(usize, usize)>
592where
593    P: PositionProvider,
594{
595    let mut closest_sqr_distance = f32::MAX;
596    let mut closest_index = None;
597    for (triangle_index, triangle) in triangles.iter().enumerate() {
598        for point_index in triangle.0.iter() {
599            let vertex = points.get(*point_index as usize).unwrap();
600            let sqr_distance = (vertex.position() - point).norm_squared();
601            if sqr_distance < closest_sqr_distance {
602                closest_sqr_distance = sqr_distance;
603                closest_index = Some((*point_index as usize, triangle_index));
604            }
605        }
606    }
607    closest_index
608}
609
610#[derive(Debug, PartialEq, Clone)]
611pub struct SmoothAngle {
612    /// Current angle in radians.
613    pub angle: f32,
614
615    /// Target angle in radians.
616    pub target: f32,
617
618    /// Turn speed in radians per second (rad/s)
619    pub speed: f32,
620}
621
622impl SmoothAngle {
623    #[inline]
624    pub fn new(angle: f32, speed: f32) -> Self {
625        Self {
626            angle,
627            target: angle,
628            speed,
629        }
630    }
631
632    #[inline]
633    pub fn set_target(&mut self, angle: f32) -> &mut Self {
634        self.target = angle;
635        self
636    }
637
638    #[inline]
639    pub fn update(&mut self, dt: f32) -> &mut Self {
640        self.target = wrap_angle(self.target);
641        self.angle = wrap_angle(self.angle);
642        if !self.at_target() {
643            let delta = self.speed * dt;
644            if self.distance().abs() > delta {
645                self.angle += self.turn_direction() * delta;
646            } else {
647                self.angle = self.target;
648            }
649        }
650        self
651    }
652
653    #[inline]
654    pub fn set_speed(&mut self, speed: f32) -> &mut Self {
655        self.speed = speed;
656        self
657    }
658
659    #[inline]
660    pub fn set_angle(&mut self, angle: f32) -> &mut Self {
661        self.angle = angle;
662        self
663    }
664
665    #[inline]
666    pub fn angle(&self) -> f32 {
667        self.angle
668    }
669
670    #[inline]
671    pub fn at_target(&self) -> bool {
672        (self.target - self.angle).abs() <= f32::EPSILON
673    }
674
675    #[inline]
676    pub fn distance(&self) -> f32 {
677        let diff = (self.target - self.angle + std::f32::consts::PI) % std::f32::consts::TAU
678            - std::f32::consts::PI;
679        if diff < -std::f32::consts::PI {
680            diff + std::f32::consts::TAU
681        } else {
682            diff
683        }
684    }
685
686    #[inline]
687    fn turn_direction(&self) -> f32 {
688        let distance = self.distance();
689
690        if distance < 0.0 {
691            if distance < -std::f32::consts::PI {
692                1.0
693            } else {
694                -1.0
695            }
696        } else if distance > std::f32::consts::PI {
697            -1.0
698        } else {
699            1.0
700        }
701    }
702}
703
704impl Default for SmoothAngle {
705    fn default() -> Self {
706        Self {
707            angle: 0.0,
708            target: 0.0,
709            speed: 1.0,
710        }
711    }
712}
713
714#[derive(Copy, Clone, Hash, PartialOrd, PartialEq, Ord, Eq)]
715pub enum RotationOrder {
716    XYZ,
717    XZY,
718    YZX,
719    YXZ,
720    ZXY,
721    ZYX,
722}
723
724#[inline]
725pub fn quat_from_euler<T: SimdRealField + RealField + Copy + Clone>(
726    euler_radians: Vector3<T>,
727    order: RotationOrder,
728) -> UnitQuaternion<T> {
729    let qx = UnitQuaternion::from_axis_angle(&Vector3::x_axis(), euler_radians.x);
730    let qy = UnitQuaternion::from_axis_angle(&Vector3::y_axis(), euler_radians.y);
731    let qz = UnitQuaternion::from_axis_angle(&Vector3::z_axis(), euler_radians.z);
732    match order {
733        RotationOrder::XYZ => qz * qy * qx,
734        RotationOrder::XZY => qy * qz * qx,
735        RotationOrder::YZX => qx * qz * qy,
736        RotationOrder::YXZ => qz * qx * qy,
737        RotationOrder::ZXY => qy * qx * qz,
738        RotationOrder::ZYX => qx * qy * qz,
739    }
740}
741
742pub trait Matrix4Ext<T: Scalar> {
743    fn side(&self) -> Vector3<T>;
744    fn up(&self) -> Vector3<T>;
745    fn look(&self) -> Vector3<T>;
746    fn position(&self) -> Vector3<T>;
747    fn basis(&self) -> Matrix3<T>;
748}
749
750impl<T: Scalar + Default + Copy + Clone> Matrix4Ext<T> for Matrix4<T> {
751    #[inline]
752    fn side(&self) -> Vector3<T> {
753        Vector3::new(self[0], self[1], self[2])
754    }
755
756    #[inline]
757    fn up(&self) -> Vector3<T> {
758        Vector3::new(self[4], self[5], self[6])
759    }
760
761    #[inline]
762    fn look(&self) -> Vector3<T> {
763        Vector3::new(self[8], self[9], self[10])
764    }
765
766    #[inline]
767    fn position(&self) -> Vector3<T> {
768        Vector3::new(self[12], self[13], self[14])
769    }
770
771    #[inline]
772    fn basis(&self) -> Matrix3<T> {
773        self.fixed_resize::<3, 3>(T::default())
774    }
775}
776
777pub trait Matrix3Ext<T: Scalar> {
778    fn side(&self) -> Vector3<T>;
779    fn up(&self) -> Vector3<T>;
780    fn look(&self) -> Vector3<T>;
781}
782
783impl<T: Scalar + Copy + Clone> Matrix3Ext<T> for Matrix3<T> {
784    #[inline]
785    fn side(&self) -> Vector3<T> {
786        Vector3::new(self[0], self[1], self[2])
787    }
788
789    #[inline]
790    fn up(&self) -> Vector3<T> {
791        Vector3::new(self[3], self[4], self[5])
792    }
793
794    #[inline]
795    fn look(&self) -> Vector3<T> {
796        Vector3::new(self[6], self[7], self[8])
797    }
798}
799
800pub trait Vector3Ext {
801    fn follow(&mut self, other: &Self, fraction: f32);
802
803    fn sqr_distance(&self, other: &Self) -> f32;
804
805    fn non_uniform_scale(&self, other: &Self) -> Self;
806}
807
808impl Vector3Ext for Vector3<f32> {
809    #[inline]
810    fn follow(&mut self, other: &Self, fraction: f32) {
811        self.x += (other.x - self.x) * fraction;
812        self.y += (other.y - self.y) * fraction;
813        self.z += (other.z - self.z) * fraction;
814    }
815
816    #[inline]
817    fn sqr_distance(&self, other: &Self) -> f32 {
818        (self - other).norm_squared()
819    }
820
821    #[inline]
822    fn non_uniform_scale(&self, other: &Self) -> Self {
823        Self::new(self.x * other.x, self.y * other.y, self.z * other.z)
824    }
825}
826
827pub trait Vector2Ext {
828    fn follow(&mut self, other: &Self, fraction: f32);
829
830    fn per_component_min(&self, other: &Self) -> Self;
831    fn per_component_max(&self, other: &Self) -> Self;
832}
833
834impl Vector2Ext for Vector2<f32> {
835    #[inline]
836    fn follow(&mut self, other: &Self, fraction: f32) {
837        self.x += (other.x - self.x) * fraction;
838        self.y += (other.y - self.y) * fraction;
839    }
840
841    #[inline]
842    fn per_component_min(&self, other: &Self) -> Self {
843        Self::new(self.x.min(other.x), self.y.min(other.y))
844    }
845
846    #[inline]
847    fn per_component_max(&self, other: &Self) -> Self {
848        Self::new(self.x.max(other.x), self.y.max(other.y))
849    }
850}
851
852/// Returns rotation quaternion that represents rotation basis with Z axis aligned on `vec`.
853/// This function handles singularities for you.
854#[inline]
855pub fn vector_to_quat(vec: Vector3<f32>) -> UnitQuaternion<f32> {
856    if vec.norm() == 0.0 {
857        return Default::default();
858    }
859
860    let dot = vec.normalize().dot(&Vector3::y());
861
862    if dot.abs() > 1.0 - 10.0 * f32::EPSILON {
863        // Handle singularity when vector is collinear with Y axis.
864        UnitQuaternion::from_axis_angle(&Vector3::x_axis(), -dot.signum() * 90.0f32.to_radians())
865    } else {
866        UnitQuaternion::face_towards(&vec, &Vector3::y())
867    }
868}
869
870#[inline]
871pub fn m4x4_approx_eq(a: &Matrix4<f32>, b: &Matrix4<f32>) -> bool {
872    a.iter()
873        .zip(b.iter())
874        .all(|(a, b)| (*a - *b).abs() <= 0.001)
875}
876
877#[cfg(test)]
878mod test {
879    use nalgebra::{Matrix3, Matrix4, UnitQuaternion, Vector3};
880    use num_traits::Zero;
881
882    use super::{
883        barycentric_is_inside, barycentric_to_world, cubicf_derivative, get_barycentric_coords,
884        get_barycentric_coords_2d, get_closest_point, get_closest_point_triangle_set,
885        get_closest_point_triangles, get_farthest_point, get_signed_triangle_area, ieee_remainder,
886        inf_sup_cubicf, quat_from_euler, round_to_step, spherical_to_cartesian, triangle_area,
887        wrap_angle, wrapf, Matrix3Ext, Matrix4Ext, PositionProvider, Rect, RotationOrder,
888        SmoothAngle, TriangleDefinition, TriangleEdge, Vector2Ext, Vector3Ext,
889    };
890    use nalgebra::Vector2;
891
892    #[test]
893    fn ray_rect_intersection() {
894        let rect = Rect::new(0.0, 0.0, 10.0, 10.0);
895
896        // Edge-case: Horizontal ray.
897        assert!(super::ray_rect_intersection(
898            rect,
899            Vector2::new(-1.0, 5.0),
900            Vector2::new(1.0, 0.0)
901        )
902        .is_some());
903
904        // Edge-case: Vertical ray.
905        assert!(super::ray_rect_intersection(
906            rect,
907            Vector2::new(5.0, -1.0),
908            Vector2::new(0.0, 1.0)
909        )
910        .is_some());
911    }
912
913    #[test]
914    fn smooth_angle() {
915        let mut angle = SmoothAngle {
916            angle: 290.0f32.to_radians(),
917            target: 90.0f32.to_radians(),
918            speed: 100.0f32.to_radians(),
919        };
920
921        while !angle.at_target() {
922            println!("{}", angle.update(1.0).angle().to_degrees());
923        }
924    }
925
926    #[test]
927    fn default_for_rect() {
928        assert_eq!(
929            Rect::<f32>::default(),
930            Rect {
931                position: Vector2::new(Zero::zero(), Zero::zero()),
932                size: Vector2::new(Zero::zero(), Zero::zero()),
933            }
934        );
935    }
936
937    #[test]
938    fn rect_with_position() {
939        let rect = Rect::new(0, 0, 1, 1);
940
941        assert_eq!(
942            rect.with_position(Vector2::new(1, 1)),
943            Rect::new(1, 1, 1, 1)
944        );
945    }
946
947    #[test]
948    fn rect_with_size() {
949        let rect = Rect::new(0, 0, 1, 1);
950
951        assert_eq!(
952            rect.with_size(Vector2::new(10, 10)),
953            Rect::new(0, 0, 10, 10)
954        );
955    }
956
957    #[test]
958    fn rect_inflate() {
959        let rect = Rect::new(0, 0, 1, 1);
960
961        assert_eq!(rect.inflate(5, 5), Rect::new(-5, -5, 11, 11));
962    }
963
964    #[test]
965    fn rect_deflate() {
966        let rect = Rect::new(-5, -5, 11, 11);
967
968        assert_eq!(rect.deflate(5, 5), Rect::new(0, 0, 1, 1));
969    }
970
971    #[test]
972    fn rect_contains() {
973        let rect = Rect::new(0, 0, 10, 10);
974
975        assert!(rect.contains(Vector2::new(0, 0)));
976        assert!(rect.contains(Vector2::new(0, 10)));
977        assert!(rect.contains(Vector2::new(10, 0)));
978        assert!(rect.contains(Vector2::new(10, 10)));
979        assert!(rect.contains(Vector2::new(5, 5)));
980
981        assert!(!rect.contains(Vector2::new(0, 20)));
982    }
983
984    #[test]
985    fn rect_center() {
986        let rect = Rect::new(0, 0, 10, 10);
987
988        assert_eq!(rect.center(), Vector2::new(5, 5));
989    }
990
991    #[test]
992    fn rect_push() {
993        let mut rect = Rect::new(10, 10, 11, 11);
994
995        rect.push(Vector2::new(0, 0));
996        assert_eq!(rect, Rect::new(0, 0, 21, 21));
997
998        rect.push(Vector2::new(0, 20));
999        assert_eq!(rect, Rect::new(0, 0, 21, 21));
1000
1001        rect.push(Vector2::new(20, 20));
1002        assert_eq!(rect, Rect::new(0, 0, 21, 21));
1003
1004        rect.push(Vector2::new(30, 30));
1005        assert_eq!(rect, Rect::new(0, 0, 30, 30));
1006    }
1007
1008    #[test]
1009    fn rect_getters() {
1010        let rect = Rect::new(0, 0, 1, 1);
1011
1012        assert_eq!(rect.left_top_corner(), Vector2::new(0, 0));
1013        assert_eq!(rect.left_bottom_corner(), Vector2::new(0, 1));
1014        assert_eq!(rect.right_top_corner(), Vector2::new(1, 0));
1015        assert_eq!(rect.right_bottom_corner(), Vector2::new(1, 1));
1016
1017        assert_eq!(rect.x(), 0);
1018        assert_eq!(rect.y(), 0);
1019        assert_eq!(rect.w(), 1);
1020        assert_eq!(rect.h(), 1);
1021    }
1022
1023    #[test]
1024    fn rect_clip_by() {
1025        let rect = Rect::new(0, 0, 10, 10);
1026
1027        assert_eq!(
1028            rect.clip_by(Rect::new(2, 2, 1, 1)).unwrap(),
1029            Rect::new(2, 2, 1, 1)
1030        );
1031        assert_eq!(
1032            rect.clip_by(Rect::new(0, 0, 15, 15)).unwrap(),
1033            Rect::new(0, 0, 10, 10)
1034        );
1035
1036        // When there is no intersection.
1037        assert!(rect.clip_by(Rect::new(-2, 1, 1, 1)).is_none());
1038        assert!(rect.clip_by(Rect::new(11, 1, 1, 1)).is_none());
1039        assert!(rect.clip_by(Rect::new(1, -2, 1, 1)).is_none());
1040        assert!(rect.clip_by(Rect::new(1, 11, 1, 1)).is_none());
1041    }
1042
1043    #[test]
1044    fn rect_translate() {
1045        let rect = Rect::new(0, 0, 10, 10);
1046
1047        assert_eq!(rect.translate(Vector2::new(5, 5)), Rect::new(5, 5, 10, 10));
1048    }
1049
1050    #[test]
1051    fn rect_intersects_circle() {
1052        let rect = Rect::new(0.0, 0.0, 1.0, 1.0);
1053
1054        assert!(!rect.intersects_circle(Vector2::new(5.0, 5.0), 1.0));
1055        assert!(rect.intersects_circle(Vector2::new(0.0, 0.0), 1.0));
1056        assert!(rect.intersects_circle(Vector2::new(-0.5, -0.5), 1.0));
1057    }
1058
1059    #[test]
1060    fn rect_extend_to_contain() {
1061        let mut rect = Rect::new(0.0, 0.0, 1.0, 1.0);
1062
1063        rect.extend_to_contain(Rect::new(1.0, 1.0, 1.0, 1.0));
1064        assert_eq!(rect, Rect::new(0.0, 0.0, 2.0, 2.0));
1065
1066        rect.extend_to_contain(Rect::new(-1.0, -1.0, 1.0, 1.0));
1067        assert_eq!(rect, Rect::new(-1.0, -1.0, 3.0, 3.0));
1068    }
1069
1070    #[test]
1071    fn rect_transform() {
1072        let rect = Rect::new(0.0, 0.0, 1.0, 1.0);
1073
1074        assert_eq!(
1075            rect.transform(&Matrix3::new(
1076                1.0, 0.0, 0.0, //
1077                0.0, 1.0, 0.0, //
1078                0.0, 0.0, 1.0,
1079            )),
1080            rect,
1081        );
1082
1083        assert_eq!(
1084            rect.transform(&Matrix3::new(
1085                2.0, 0.0, 0.0, //
1086                0.0, 2.0, 0.0, //
1087                0.0, 0.0, 2.0,
1088            )),
1089            Rect::new(0.0, 0.0, 2.0, 2.0),
1090        );
1091    }
1092
1093    #[test]
1094    fn test_get_signed_triangle_area() {
1095        assert_eq!(
1096            get_signed_triangle_area(
1097                Vector2::new(0.0, 0.0),
1098                Vector2::new(0.0, 1.0),
1099                Vector2::new(1.0, 0.0)
1100            ),
1101            0.5
1102        );
1103        assert_eq!(
1104            get_signed_triangle_area(
1105                Vector2::new(1.0, 1.0),
1106                Vector2::new(0.0, 1.0),
1107                Vector2::new(1.0, 0.0)
1108            ),
1109            -0.5
1110        );
1111    }
1112
1113    #[test]
1114    fn test_wrap_angle() {
1115        let angle = 0.5 * std::f32::consts::PI;
1116        assert_eq!(wrap_angle(angle), angle);
1117        assert_eq!(wrap_angle(-angle), 3.0 * angle);
1118    }
1119
1120    #[test]
1121    fn test_ieee_remainder() {
1122        assert_eq!(ieee_remainder(1.0, 2.0), -1.0);
1123        assert_eq!(ieee_remainder(3.0, 2.0), -1.0);
1124
1125        assert_eq!(ieee_remainder(1.0, 3.0), 1.0);
1126        assert_eq!(ieee_remainder(4.0, 3.0), 1.0);
1127
1128        assert_eq!(ieee_remainder(-1.0, 2.0), 1.0);
1129        assert_eq!(ieee_remainder(-3.0, 2.0), 1.0);
1130    }
1131
1132    #[test]
1133    fn test_round_to_step() {
1134        assert_eq!(round_to_step(1.0, 2.0), 2.0);
1135        assert_eq!(round_to_step(3.0, 2.0), 4.0);
1136
1137        assert_eq!(round_to_step(-1.0, 2.0), -2.0);
1138        assert_eq!(round_to_step(-3.0, 2.0), -4.0);
1139    }
1140
1141    #[test]
1142    fn test_wrapf() {
1143        assert_eq!(wrapf(5.0, 0.0, 10.0), 5.0);
1144        assert_eq!(wrapf(5.0, 0.0, 0.0), 0.0);
1145        assert_eq!(wrapf(2.0, 5.0, 10.0), 7.0);
1146        assert_eq!(wrapf(12.0, 5.0, 10.0), 7.0);
1147    }
1148
1149    #[test]
1150    fn test_cubicf_derivative() {
1151        assert_eq!(cubicf_derivative(1.0, 1.0, 1.0, 1.0, 1.0), 0.0);
1152        assert_eq!(cubicf_derivative(2.0, 1.0, 1.0, 1.0, 1.0), 1.0);
1153    }
1154
1155    #[test]
1156    fn test_inf_sup_cubicf() {
1157        assert_eq!(inf_sup_cubicf(1.0, 1.0, 1.0, 1.0), (1.0, 1.0));
1158        assert_eq!(inf_sup_cubicf(2.0, 2.0, 1.0, 1.0), (2.0, 2.0));
1159    }
1160
1161    #[test]
1162    fn test_get_farthest_point() {
1163        let points = [
1164            Vector3::new(0.0, 0.0, 0.0),
1165            Vector3::new(1.0, 0.0, 0.0),
1166            Vector3::new(0.0, 1.0, 0.0),
1167            Vector3::new(0.0, 0.0, 1.0),
1168            Vector3::new(1.0, 1.0, 1.0),
1169        ];
1170
1171        assert_eq!(
1172            get_farthest_point(&points, Vector3::new(1.0, 0.0, 0.0)),
1173            Vector3::new(1.0, 0.0, 0.0)
1174        );
1175        assert_eq!(
1176            get_farthest_point(&points, Vector3::new(10.0, 0.0, 0.0)),
1177            Vector3::new(1.0, 0.0, 0.0)
1178        );
1179        assert_eq!(
1180            get_farthest_point(&points, Vector3::new(1.0, 1.0, 0.0)),
1181            Vector3::new(1.0, 1.0, 1.0)
1182        );
1183    }
1184
1185    #[test]
1186    fn test_get_barycentric_coords() {
1187        assert_eq!(
1188            get_barycentric_coords(
1189                &Vector3::new(0.0, 0.0, 0.0),
1190                &Vector3::new(1.0, 0.0, 0.0),
1191                &Vector3::new(0.0, 1.0, 0.0),
1192                &Vector3::new(0.0, 0.0, 1.0),
1193            ),
1194            (0.33333328, 0.33333334, 0.33333334)
1195        );
1196    }
1197
1198    #[test]
1199    fn test_get_barycentric_coords_2d() {
1200        assert_eq!(
1201            get_barycentric_coords_2d(
1202                Vector2::new(0.0, 0.0),
1203                Vector2::new(1.0, 0.0),
1204                Vector2::new(0.0, 1.0),
1205                Vector2::new(0.0, 0.0),
1206            ),
1207            (0.0, 0.0, 1.0)
1208        );
1209    }
1210
1211    #[test]
1212    fn test_barycentric_to_world() {
1213        assert_eq!(
1214            barycentric_to_world(
1215                (2.0, 2.0, 2.0),
1216                Vector3::new(1.0, 0.0, 0.0),
1217                Vector3::new(0.0, 1.0, 0.0),
1218                Vector3::new(0.0, 0.0, 1.0),
1219            ),
1220            Vector3::new(2.0, 2.0, 2.0)
1221        );
1222    }
1223
1224    #[test]
1225    fn test_barycentric_is_inside() {
1226        assert!(barycentric_is_inside((0.0, 0.0, 0.0)));
1227        assert!(barycentric_is_inside((0.5, 0.49, 0.0)));
1228
1229        assert!(!barycentric_is_inside((0.5, 0.5, 0.0)));
1230        assert!(!barycentric_is_inside((-0.5, 0.49, 0.0)));
1231        assert!(!barycentric_is_inside((0.5, -0.49, 0.0)));
1232        assert!(!barycentric_is_inside((-0.5, -0.49, 0.0)));
1233    }
1234
1235    #[test]
1236    fn test_triangle_area() {
1237        assert_eq!(
1238            triangle_area(
1239                Vector3::new(0.0, 0.0, 0.0),
1240                Vector3::new(0.0, 1.0, 0.0),
1241                Vector3::new(0.0, 0.0, 1.0),
1242            ),
1243            0.5
1244        );
1245    }
1246
1247    #[test]
1248    fn test_spherical_to_cartesian() {
1249        assert_eq!(
1250            spherical_to_cartesian(0.0, 0.0, 1.0),
1251            Vector3::new(0.0, 1.0, 0.0)
1252        );
1253    }
1254
1255    #[test]
1256    fn partial_eq_for_triangle_edge() {
1257        let te = TriangleEdge { a: 2, b: 5 };
1258        let te2 = TriangleEdge { a: 2, b: 5 };
1259        let te3 = TriangleEdge { a: 5, b: 2 };
1260
1261        assert_eq!(te, te2);
1262        assert_eq!(te, te3);
1263    }
1264
1265    #[test]
1266    fn triangle_definition_indices() {
1267        assert_eq!(TriangleDefinition([0, 0, 0]).indices(), &[0, 0, 0]);
1268    }
1269
1270    #[test]
1271    fn triangle_definition_indices_mut() {
1272        assert_eq!(TriangleDefinition([0, 0, 0]).indices_mut(), &mut [0, 0, 0]);
1273    }
1274
1275    #[test]
1276    fn triangle_definition_edges() {
1277        let t = TriangleDefinition([0, 1, 2]);
1278        assert_eq!(
1279            t.edges(),
1280            [
1281                TriangleEdge { a: 0, b: 1 },
1282                TriangleEdge { a: 1, b: 2 },
1283                TriangleEdge { a: 2, b: 0 }
1284            ]
1285        );
1286    }
1287
1288    #[test]
1289    fn index_for_triangle_definition() {
1290        let t = TriangleDefinition([0, 1, 2]);
1291
1292        assert_eq!(t[0], 0);
1293        assert_eq!(t[1], 1);
1294        assert_eq!(t[2], 2);
1295    }
1296
1297    #[test]
1298    fn index_mut_for_triangle_definition() {
1299        let mut t = TriangleDefinition([5, 5, 5]);
1300        t[0] = 0;
1301        t[1] = 1;
1302        t[2] = 2;
1303
1304        assert_eq!(t[0], 0);
1305        assert_eq!(t[1], 1);
1306        assert_eq!(t[2], 2);
1307    }
1308
1309    #[test]
1310    fn position_provider_for_vector3() {
1311        let v = Vector3::new(0.0, 1.0, 2.0);
1312
1313        assert_eq!(v.position(), v);
1314    }
1315
1316    #[test]
1317    fn as_ref_for_triangle_definition() {
1318        let t = TriangleDefinition([0, 1, 2]);
1319
1320        assert_eq!(t.as_ref(), &[0, 1, 2]);
1321    }
1322
1323    #[test]
1324    fn as_mut_for_triangle_definition() {
1325        let mut t = TriangleDefinition([0, 1, 2]);
1326
1327        assert_eq!(t.as_mut(), &mut [0, 1, 2]);
1328    }
1329
1330    #[test]
1331    fn test_get_closest_point() {
1332        let points = [
1333            Vector3::new(1.0, 0.0, 0.0),
1334            Vector3::new(0.0, 1.0, 0.0),
1335            Vector3::new(0.0, 0.0, 1.0),
1336        ];
1337
1338        assert_eq!(
1339            get_closest_point(&points, Vector3::new(0.0, 0.0, 0.0)),
1340            Some(0),
1341        );
1342        assert_eq!(
1343            get_closest_point(&points, Vector3::new(0.0, 1.0, 1.0)),
1344            Some(1),
1345        );
1346        assert_eq!(
1347            get_closest_point(&points, Vector3::new(0.0, 0.0, 10.0)),
1348            Some(2),
1349        );
1350    }
1351
1352    #[test]
1353    fn test_get_closest_point_triangles() {
1354        let points = [
1355            Vector3::new(0.0, 0.0, 0.0),
1356            Vector3::new(1.0, 0.0, 0.0),
1357            Vector3::new(0.0, 1.0, 0.0),
1358            Vector3::new(0.0, 0.0, 1.0),
1359        ];
1360        let triangles = [TriangleDefinition([0, 1, 2]), TriangleDefinition([1, 2, 3])];
1361
1362        assert_eq!(
1363            get_closest_point_triangles(
1364                &points,
1365                &triangles,
1366                [0, 1].into_iter(),
1367                Vector3::new(1.0, 1.0, 1.0)
1368            ),
1369            Some((1, 0))
1370        );
1371    }
1372
1373    #[test]
1374    fn test_get_closest_point_triangle_set() {
1375        let points = [
1376            Vector3::new(0.0, 0.0, 0.0),
1377            Vector3::new(1.0, 0.0, 0.0),
1378            Vector3::new(0.0, 1.0, 0.0),
1379            Vector3::new(0.0, 0.0, 1.0),
1380        ];
1381        let triangles = [TriangleDefinition([0, 1, 2]), TriangleDefinition([1, 2, 3])];
1382
1383        assert_eq!(
1384            get_closest_point_triangle_set(&points, &triangles, Vector3::new(1.0, 1.0, 1.0)),
1385            Some((1, 0))
1386        );
1387    }
1388
1389    #[test]
1390    fn smooth_angle_setters() {
1391        let mut sa = SmoothAngle {
1392            angle: 0.0,
1393            speed: 0.0,
1394            target: 0.0,
1395        };
1396
1397        assert_eq!(sa.angle(), 0.0);
1398
1399        sa.set_angle(std::f32::consts::PI);
1400        assert_eq!(sa.angle(), std::f32::consts::PI);
1401
1402        sa.set_target(std::f32::consts::PI);
1403        assert_eq!(sa.target, std::f32::consts::PI);
1404
1405        sa.set_speed(1.0);
1406        assert_eq!(sa.speed, 1.0);
1407    }
1408
1409    #[test]
1410    fn smooth_angle_turn_direction() {
1411        assert_eq!(
1412            SmoothAngle {
1413                angle: 0.0,
1414                speed: 0.0,
1415                target: std::f32::consts::PI * 1.1,
1416            }
1417            .turn_direction(),
1418            -1.0
1419        );
1420
1421        assert_eq!(
1422            SmoothAngle {
1423                angle: 0.0,
1424                speed: 0.0,
1425                target: -std::f32::consts::PI * 1.1,
1426            }
1427            .turn_direction(),
1428            1.0
1429        );
1430
1431        assert_eq!(
1432            SmoothAngle {
1433                angle: 0.0,
1434                speed: 0.0,
1435                target: -std::f32::consts::PI * 0.9,
1436            }
1437            .turn_direction(),
1438            -1.0
1439        );
1440
1441        assert_eq!(
1442            SmoothAngle {
1443                angle: 0.0,
1444                speed: 0.0,
1445                target: std::f32::consts::PI * 0.9,
1446            }
1447            .turn_direction(),
1448            1.0
1449        );
1450    }
1451
1452    #[test]
1453    fn default_for_smooth_angle() {
1454        let sa = SmoothAngle::default();
1455
1456        assert_eq!(sa.angle, 0.0);
1457        assert_eq!(sa.target, 0.0);
1458        assert_eq!(sa.speed, 1.0);
1459    }
1460
1461    #[test]
1462    fn test_quat_from_euler() {
1463        assert_eq!(
1464            quat_from_euler(
1465                Vector3::new(
1466                    std::f32::consts::PI,
1467                    std::f32::consts::PI,
1468                    std::f32::consts::PI
1469                ),
1470                RotationOrder::XYZ
1471            ),
1472            UnitQuaternion::from_euler_angles(
1473                std::f32::consts::PI,
1474                std::f32::consts::PI,
1475                std::f32::consts::PI
1476            )
1477        );
1478    }
1479
1480    #[test]
1481    fn matrix4_ext_for_matrix4() {
1482        let m = Matrix4::new(
1483            1.0, 0.0, 0.0, 0.0, //
1484            0.0, 1.0, 0.0, 0.0, //
1485            0.0, 0.0, 1.0, 0.0, //
1486            0.0, 0.0, 0.0, 1.0,
1487        );
1488
1489        assert_eq!(m.side(), Vector3::new(1.0, 0.0, 0.0));
1490        assert_eq!(m.up(), Vector3::new(0.0, 1.0, 0.0));
1491        assert_eq!(m.look(), Vector3::new(0.0, 0.0, 1.0));
1492        assert_eq!(m.position(), Vector3::new(0.0, 0.0, 0.0));
1493        assert_eq!(
1494            m.basis(),
1495            Matrix3::new(
1496                1.0, 0.0, 0.0, //
1497                0.0, 1.0, 0.0, //
1498                0.0, 0.0, 1.0,
1499            )
1500        );
1501    }
1502
1503    #[test]
1504    fn matrix3_ext_for_matrix3() {
1505        let m = Matrix3::new(
1506            1.0, 0.0, 0.0, //
1507            0.0, 1.0, 0.0, //
1508            0.0, 0.0, 1.0,
1509        );
1510
1511        assert_eq!(m.side(), Vector3::new(1.0, 0.0, 0.0));
1512        assert_eq!(m.up(), Vector3::new(0.0, 1.0, 0.0));
1513        assert_eq!(m.look(), Vector3::new(0.0, 0.0, 1.0));
1514    }
1515
1516    #[test]
1517    fn vector3_ext_for_vector3() {
1518        let mut v = Vector3::new(2.0, 2.0, 2.0);
1519
1520        assert_eq!(v.sqr_distance(&Vector3::new(0.0, 1.0, 1.0)), 6.0);
1521
1522        assert_eq!(
1523            v.non_uniform_scale(&Vector3::new(3.0, 3.0, 3.0)),
1524            Vector3::new(6.0, 6.0, 6.0)
1525        );
1526
1527        v.follow(&Vector3::new(0.5, 0.5, 0.5), 2.0);
1528        assert_eq!(v, Vector3::new(-1.0, -1.0, -1.0));
1529    }
1530
1531    #[test]
1532    fn vector2_ext_for_vector2() {
1533        let mut v = Vector2::new(2.0, 2.0);
1534
1535        assert_eq!(
1536            v.per_component_min(&Vector2::new(0.0, 4.0)),
1537            Vector2::new(0.0, 2.0)
1538        );
1539
1540        assert_eq!(
1541            v.per_component_max(&Vector2::new(0.0, 4.0)),
1542            Vector2::new(2.0, 4.0)
1543        );
1544
1545        v.follow(&Vector2::new(0.5, 0.5), 2.0);
1546        assert_eq!(v, Vector2::new(-1.0, -1.0));
1547    }
1548
1549    #[test]
1550    fn test_m4x4_approx_eq() {
1551        assert!(crate::m4x4_approx_eq(
1552            &Matrix4::new(
1553                1.0, 0.0, 0.0, 0.0, //
1554                0.0, 1.0, 0.0, 0.0, //
1555                0.0, 0.0, 1.0, 0.0, //
1556                0.0, 0.0, 0.0, 1.0,
1557            ),
1558            &Matrix4::new(
1559                1.0001, 0.0001, 0.0001, 0.0001, //
1560                0.0001, 1.0001, 0.0001, 0.0001, //
1561                0.0001, 0.0001, 1.0001, 0.0001, //
1562                0.0001, 0.0001, 0.0001, 1.0001,
1563            )
1564        ),);
1565    }
1566}