ranim_core/utils/
mod.rs

1/// Bezier related stuffs
2pub mod bezier;
3/// Math stuffs
4pub mod math;
5/// The rate functions
6pub mod rate_functions;
7// /// Svg related stuffs
8// pub mod svg;
9// /// Typst related stuffs
10// pub mod typst;
11// pub(crate) mod wgpu;
12
13use std::{
14    hash::{DefaultHasher, Hash, Hasher},
15    iter::Sum,
16    ops::Div,
17};
18
19use glam::{DVec3, Mat3, Vec2, Vec3, vec2, vec3};
20
21/// Projects a 3D point onto a plane defined by a unit normal vector.
22pub fn project(p: Vec3, unit_normal: Vec3) -> Vec3 {
23    p - unit_normal * unit_normal.dot(p)
24}
25
26/// Generate basis vecs for a surface from a unit normal vec
27pub fn generate_basis(unit_normal: Vec3) -> (Vec3, Vec3) {
28    // trace!("generating basis for {:?}", unit_normal);
29    let u = if unit_normal.x != 0.0 || unit_normal.y != 0.0 {
30        vec3(-unit_normal.y, unit_normal.x, 0.0)
31    } else {
32        vec3(1.0, 0.0, 0.0)
33    }
34    .normalize();
35    let v = unit_normal.cross(u).normalize();
36    (u, v)
37}
38
39/// Get a 3d point's 2d coordinate on a 3d plane
40pub fn convert_to_2d(p: Vec3, origin: Vec3, basis: (Vec3, Vec3)) -> Vec2 {
41    // trace!("converting {:?} by {:?} and {:?}", p, origin, basis);
42    let p_local = p - origin;
43    vec2(basis.0.dot(p_local), basis.1.dot(p_local))
44}
45
46/// Get a 2d point's 3d coordinate on a 3d plane
47pub fn convert_to_3d(p: Vec2, origin: Vec3, basis: (Vec3, Vec3)) -> Vec3 {
48    origin + basis.0 * p.x + basis.1 * p.y
49}
50
51/// Get a rotation matrix from `v1` to `v2`
52pub fn rotation_between_vectors(v1: Vec3, v2: Vec3) -> Mat3 {
53    // trace!("rotation_between_vectors: v1: {:?}, v2: {:?}", v1, v2);
54
55    if (v2 - v1).length() < f32::EPSILON {
56        return Mat3::IDENTITY;
57    }
58    let mut axis = v1.cross(v2);
59    if axis.length() < f32::EPSILON {
60        axis = v1.cross(Vec3::Y);
61    }
62    if axis.length() < f32::EPSILON {
63        axis = v1.cross(Vec3::Z);
64    }
65    // trace!("axis: {:?}", axis);
66
67    let angle = angle_between_vectors(v1, v2);
68    // trace!("angle: {:?}", angle);
69    Mat3::from_axis_angle(axis, angle)
70}
71
72/// Get data's avg
73pub fn avg<T: Clone + Sum + Div<f64, Output = T>>(data: &[T]) -> T {
74    data.iter().cloned().sum::<T>() / data.len() as f64
75}
76
77/// Get angle between vectors
78pub fn angle_between_vectors(v1: Vec3, v2: Vec3) -> f32 {
79    if v1.length() == 0.0 || v2.length() == 0.0 {
80        return 0.0;
81    }
82
83    (v1.dot(v2) / (v1.length() * v2.length()))
84        .clamp(-1.0, 1.0)
85        .acos()
86}
87
88/// Resize the vec while preserving the order
89pub fn resize_preserving_order<T: Clone>(vec: &[T], new_len: usize) -> Vec<T> {
90    let indices = (0..new_len).map(|i| i * vec.len() / new_len);
91    indices.map(|i| vec[i].clone()).collect()
92}
93
94/// Resize the vec while preserving the order
95///
96/// returns the repeated idxs
97/// ```ignore
98///                     *     *     *     *  repeated
99/// [0, 1, 2, 3] -> [0, 0, 1, 1, 2, 2, 3 ,3]
100/// ```
101pub fn resize_preserving_order_with_repeated_indices<T: Clone>(
102    vec: &[T],
103    new_len: usize,
104) -> (Vec<T>, Vec<usize>) {
105    let mut res = Vec::with_capacity(new_len);
106    let mut added_idxs = Vec::with_capacity(new_len);
107    let mut prev_index = None;
108    for i in 0..new_len {
109        let index = i * vec.len() / new_len;
110        if prev_index.map(|i| i == index).unwrap_or(false) {
111            added_idxs.push(res.len());
112        }
113        res.push(vec[index].clone());
114        prev_index = Some(index);
115    }
116    (res, added_idxs)
117}
118
119/// Resize the vec while preserving the order
120///
121/// returns the repeated cnt of each value
122/// ```ignore
123///                 [2  2][2  2][2  2][2  2]
124/// [0, 1, 2, 3] -> [0, 0, 1, 1, 2, 2, 3 ,3]
125/// ```
126pub fn resize_preserving_order_with_repeated_cnt<T: Clone>(
127    vec: &[T],
128    new_len: usize,
129) -> (Vec<T>, Vec<usize>) {
130    let mut res = Vec::with_capacity(new_len);
131    let mut cnts = vec![0; vec.len()];
132
133    let mut src_indices = Vec::with_capacity(new_len);
134    for i in 0..new_len {
135        let index = i * vec.len() / new_len;
136        cnts[index] += 1;
137        res.push(vec[index].clone());
138        src_indices.push(index);
139    }
140    (res, src_indices.into_iter().map(|i| cnts[i]).collect())
141}
142
143/// Extend the vec with last element
144pub fn extend_with_last<T: Clone + Default>(vec: &mut Vec<T>, new_len: usize) {
145    let v = vec![vec.last().cloned().unwrap_or_default(); new_len - vec.len()];
146    vec.extend(v)
147}
148
149// f.a + b.a * (1.0 - f.a)
150fn merge_alpha(alpha: f32, n: usize) -> f32 {
151    let mut result = alpha;
152    for _ in 1..n {
153        result = result + (1.0 - result) * alpha;
154    }
155    result
156}
157
158/// Get a target alpha value that can get value of given alpha after mixed n times
159pub fn apart_alpha(alpha: f32, n: usize, eps: f32) -> f32 {
160    if alpha == 0.0 {
161        return 0.0;
162    }
163    let mut left = (0.0, 0.0);
164    let mut right = (1.0, 1.0);
165
166    while right.0 - left.0 > eps {
167        let mid_single = (left.0 + right.0) / 2.0;
168        let mid_merged = merge_alpha(mid_single, n);
169
170        if (mid_merged - alpha).abs() < f32::EPSILON {
171            return mid_single;
172        }
173
174        if mid_merged < alpha {
175            left = (mid_single, mid_merged);
176        } else {
177            right = (mid_single, mid_merged);
178        }
179    }
180
181    ((left.0 + right.0) / 2.0).clamp(0.0, 1.0)
182}
183
184/// Calculate hash
185pub fn calculate_hash<T: Hash>(t: &T) -> u64 {
186    let mut s = DefaultHasher::new();
187    t.hash(&mut s);
188    s.finish()
189}
190
191/// Apply the function by first transform the points to origin based on a point,
192/// then apply the function, then transform the points back.
193pub fn wrap_point_func_with_point(
194    f: impl Fn(&mut DVec3) + Copy,
195    point: DVec3,
196) -> impl Fn(&mut DVec3) + Copy {
197    move |points| {
198        *points -= point;
199        f(points);
200        *points += point;
201    }
202}
203
204#[cfg(test)]
205mod test {
206    use super::*;
207
208    #[test]
209    fn test_resize_preserve_order_with_repeated_cnt() {
210        let values = vec![0, 1, 2, 3];
211        let (v, c) = resize_preserving_order_with_repeated_cnt(&values, 8);
212        assert_eq!(v, vec![0, 0, 1, 1, 2, 2, 3, 3]);
213        assert_eq!(c, vec![2; 8]);
214    }
215
216    #[test]
217    fn tset_apart_alpha() {
218        let a = apart_alpha(1.0, 10, 1e-3);
219        println!("{a}");
220        println!("{}", merge_alpha(1.0, 10));
221    }
222}