ranim_core/utils/
math.rs

1use glam::{DVec2, DVec3, IVec2, dvec2};
2
3/// Cross product of 2d points
4pub fn cross2d(a: DVec2, b: DVec2) -> f64 {
5    a.x * b.y - b.x * a.y
6}
7
8/// Get the intersection point of two ray
9pub fn intersection(p1: DVec3, v1: DVec3, p2: DVec3, v2: DVec3) -> Option<DVec3> {
10    // println!("p1: {:?}, v1: {:?}, p2: {:?}, v2: {:?}", p1, v1, p2, v2);
11    let cross = v1.cross(v2);
12    let denom = cross.length_squared();
13    if denom < f64::EPSILON {
14        return None;
15    }
16
17    let diff = p2 - p1;
18    let t = (diff).cross(v2).dot(cross) / denom;
19    let s = (diff).cross(v1).dot(cross) / denom;
20
21    let point1 = p1 + v1 * t;
22    let point2 = p2 + v2 * s;
23
24    if (point1 - point2).length_squared() < f64::EPSILON {
25        Some(point1)
26    } else {
27        None
28    }
29}
30
31/// A rectangle in 2D space
32#[derive(Debug, Clone, Copy)]
33pub struct Rect {
34    min: DVec2,
35    max: DVec2,
36}
37
38impl Rect {
39    /// Get the union of two rectangle
40    pub fn union(&self, other: &Self) -> Self {
41        let min = self.min.min(other.min);
42        let max = self.max.max(other.max);
43        Self { min, max }
44    }
45    /// Get the intersection of two rectangle
46    pub fn intersection(&self, other: &Self) -> Self {
47        let min = self.min.max(other.min);
48        let max = self.max.min(other.max);
49        Self { min, max }
50    }
51    /// Get the center of the rectangle
52    pub fn center(&self) -> DVec2 {
53        (self.min + self.max) / 2.0
54    }
55
56    /// Get the point of the rectangle
57    /// ```text
58    /// (-1,-1)-----(0,-1)-----(1,-1)
59    ///    |          |          |
60    /// (-1, 0)-----(0, 0)-----(1, 0)
61    ///    |          |          |
62    /// (-1, 1)-----(0, 1)-----(1, 1)
63    /// ```
64    pub fn point(&self, edge: IVec2) -> DVec2 {
65        let min = self.min;
66        let center = self.center();
67        let max = self.max;
68
69        let x = match edge.x {
70            -1 => min.y,
71            0 => center.y,
72            1 => max.y,
73            _ => unreachable!(),
74        };
75        let y = match edge.y {
76            -1 => min.y,
77            0 => center.y,
78            1 => max.y,
79            _ => unreachable!(),
80        };
81
82        dvec2(x, y)
83    }
84}
85
86/// Interpolate between two integers
87///
88/// return integer and the sub progress to the next integer
89pub fn interpolate_usize(a: usize, b: usize, t: f64) -> (usize, f64) {
90    assert!(b >= a);
91    let t = t.clamp(0.0, 1.0);
92    let v = b - a;
93
94    let p = v as f64 * t;
95
96    (a + p.floor() as usize, p.fract())
97}
98
99#[cfg(test)]
100mod test {
101    use core::f64;
102
103    use super::*;
104
105    #[test]
106    fn test_interpolate_usize() {
107        let test = |(x, t): (usize, f64), (expected_x, expected_t): (usize, f64)| {
108            assert_eq!(x, expected_x);
109            assert!((t - expected_t).abs() < f64::EPSILON);
110        };
111
112        test(interpolate_usize(0, 10, 0.0), (0, 0.0));
113        test(interpolate_usize(0, 10, 0.5), (5, 0.0));
114        test(interpolate_usize(0, 10, 1.0), (10, 0.0));
115
116        test(interpolate_usize(0, 1, 0.0), (0, 0.0));
117        test(interpolate_usize(0, 1, 0.5), (0, 0.5));
118        test(interpolate_usize(0, 1, 1.0), (1, 0.0));
119
120        test(interpolate_usize(0, 2, 0.0), (0, 0.0));
121        test(interpolate_usize(0, 2, 0.2), (0, 0.4));
122        test(interpolate_usize(0, 2, 0.4), (0, 0.8));
123        test(interpolate_usize(0, 2, 0.6), (1, 0.2));
124        test(interpolate_usize(0, 2, 0.8), (1, 0.6));
125        test(interpolate_usize(0, 2, 1.0), (2, 0.0));
126    }
127
128    #[test]
129    fn test_intersection() {
130        use glam::dvec3;
131
132        // 1. 垂直相交
133        let p1 = dvec3(0.0, 0.0, 0.0);
134        let v1 = dvec3(1.0, 0.0, 0.0);
135        let p2 = dvec3(0.0, 1.0, 0.0);
136        let v2 = dvec3(0.0, -1.0, 0.0);
137        assert_eq!(intersection(p1, v1, p2, v2), Some(dvec3(0.0, 0.0, 0.0)));
138
139        // 2. 斜交
140        let p1 = dvec3(1.0, 1.0, 0.0);
141        let v1 = dvec3(1.0, 2.0, 0.0);
142        let p2 = dvec3(3.0, 1.0, 0.0);
143        let v2 = dvec3(-1.0, 2.0, 0.0);
144        assert_eq!(intersection(p1, v1, p2, v2), Some(dvec3(2.0, 3.0, 0.0)));
145
146        // 3. 重合直线(应返回 None)
147        let p1 = dvec3(0.0, 0.0, 0.0);
148        let v1 = dvec3(1.0, 1.0, 1.0);
149        let p2 = dvec3(1.0, 1.0, 1.0);
150        let v2 = dvec3(2.0, 2.0, 2.0);
151        assert!(intersection(p1, v1, p2, v2).is_none());
152
153        // 4. 平行直线(应返回 None)
154        let p1 = dvec3(0.0, 0.0, 0.0);
155        let v1 = dvec3(1.0, 1.0, 0.0);
156        let p2 = dvec3(1.0, 0.0, 0.0);
157        let v2 = dvec3(1.0, 1.0, 0.0);
158        assert!(intersection(p1, v1, p2, v2).is_none());
159
160        // 5. 异面直线(应返回 None)
161        let p1 = dvec3(0.0, 0.0, 0.0);
162        let v1 = dvec3(1.0, 0.0, 1.0);
163        let p2 = dvec3(0.0, 1.0, 0.0);
164        let v2 = dvec3(1.0, 0.0, -1.0);
165        assert!(intersection(p1, v1, p2, v2).is_none());
166    }
167}