ranim_core/components/
mod.rs

1use std::fmt::Debug;
2
3use derive_more::{AsMut, AsRef, Deref, DerefMut};
4
5use crate::{
6    prelude::{Alignable, Interpolatable},
7    utils::{math::interpolate_usize, resize_preserving_order},
8};
9
10/// Point
11pub mod point;
12/// Rgba
13pub mod rgba;
14/// Vpoint
15pub mod vpoint;
16/// Width
17pub mod width;
18
19/// An component
20pub trait Component: Debug + Default + Clone + PartialEq {}
21
22impl<T: Debug + Default + Clone + PartialEq> Component for T {}
23
24/// A component vec
25#[derive(Default, Debug, Clone, PartialEq, Deref, DerefMut, AsMut, AsRef)]
26#[as_ref(forward)]
27#[as_mut(forward)]
28pub struct ComponentVec<T: Component>(pub(crate) Vec<T>);
29
30// MARK: Trait impls
31
32impl<T: Component + PointWise + Interpolatable> ComponentVec<T> {
33    /// Get partial of data
34    ///
35    /// This will interpolate between point wise data
36    pub fn get_partial(&self, range: std::ops::Range<f64>) -> Self {
37        let max_idx = self.len() - 2;
38
39        let (start_index, start_residue) = interpolate_usize(0, max_idx, range.start);
40        let (end_index, end_residue) = interpolate_usize(0, max_idx, range.end);
41        // trace!("max_idx: {max_idx}, range: {:?}, start: {} {}, end: {} {}", range, start_index, start_residue, end_index, end_residue);
42        if start_index == end_index {
43            let start_v = self
44                .get(start_index)
45                .unwrap()
46                .lerp(self.get(start_index + 1).unwrap(), start_residue);
47            let end_v = self
48                .get(end_index)
49                .unwrap()
50                .lerp(self.get(end_index + 1).unwrap(), end_residue);
51            vec![start_v, end_v]
52        } else {
53            let start_v = self
54                .get(start_index)
55                .unwrap()
56                .lerp(self.get(start_index + 1).unwrap(), start_residue);
57            let end_v = self
58                .get(end_index)
59                .unwrap()
60                .lerp(self.get(end_index + 1).unwrap(), end_residue);
61
62            let mut partial = Vec::with_capacity(end_index - start_index + 1 + 2);
63            partial.push(start_v);
64            partial.extend_from_slice(self.get(start_index + 1..=end_index).unwrap());
65            partial.push(end_v);
66            partial
67        }
68        .into()
69    }
70}
71
72impl<T: Component> Alignable for ComponentVec<T> {
73    fn is_aligned(&self, other: &Self) -> bool {
74        self.len() == other.len()
75    }
76    fn align_with(&mut self, other: &mut Self) {
77        if self.len() == other.len() {
78            return;
79        }
80        if self.len() < other.len() {
81            self.resize_with_last(other.len());
82        } else {
83            other.resize_with_last(self.len());
84        }
85    }
86}
87
88impl<T: Component + Interpolatable> Interpolatable for ComponentVec<T> {
89    fn lerp(&self, target: &Self, t: f64) -> Self {
90        Self(
91            self.iter()
92                .zip(target.iter())
93                .map(|(a, b)| a.lerp(b, t))
94                .collect::<Vec<_>>(),
95        )
96    }
97}
98
99impl<T: Component, I: IntoIterator<Item = impl Into<T>>> From<I> for ComponentVec<T> {
100    fn from(v: I) -> Self {
101        Self(v.into_iter().map(Into::into).collect())
102    }
103}
104
105impl<T: Component> ComponentVec<T> {
106    /// Extend from a vec
107    pub fn extend_from_vec(&mut self, vec: Vec<T>) {
108        self.0.extend(vec);
109    }
110    /// Resize with default value
111    pub fn resize_with_default(&mut self, new_len: usize) {
112        self.0.resize(new_len, Default::default());
113    }
114    /// Resize with last element
115    pub fn resize_with_last(&mut self, new_len: usize) {
116        let last = self.last().cloned().unwrap_or_default();
117        self.0.resize(new_len, last);
118    }
119    /// Resize preserved order
120    pub fn resize_preserving_order(&mut self, new_len: usize) {
121        self.0 = resize_preserving_order(&self.0, new_len);
122    }
123    /// Set all element to a value
124    pub fn set_all(&mut self, value: impl Into<T>) {
125        let value = value.into();
126        self.iter_mut().for_each(|x| *x = value.clone());
127    }
128}
129
130/// A marker trait for components that has each element as a point data.
131pub trait PointWise {}
132
133// MARK: Test
134#[cfg(test)]
135mod test {
136    use glam::{DVec3, IVec3, dvec3, ivec3};
137
138    use crate::{
139        components::vpoint::VPointComponentVec,
140        traits::{BoundingBox, Scale},
141    };
142
143    #[test]
144    fn test_bounding_box() {
145        let points: VPointComponentVec = VPointComponentVec(
146            vec![
147                dvec3(-100.0, -100.0, 0.0),
148                dvec3(-100.0, 100.0, 0.0),
149                dvec3(100.0, 100.0, 0.0),
150                dvec3(100.0, -200.0, 0.0),
151            ]
152            .into(),
153        );
154        assert_eq!(
155            points.get_bounding_box(),
156            [
157                dvec3(-100.0, -200.0, 0.0),
158                dvec3(0.0, -50.0, 0.0),
159                dvec3(100.0, 100.0, 0.0)
160            ]
161        );
162        assert_eq!(
163            dvec3(0.0, -50.0, 0.0),
164            points.get_bounding_box_point(ivec3(0, 0, 0))
165        );
166        assert_eq!(
167            dvec3(-100.0, -200.0, 0.0),
168            points.get_bounding_box_point(ivec3(-1, -1, 0))
169        );
170        assert_eq!(
171            dvec3(-100.0, 100.0, 0.0),
172            points.get_bounding_box_point(ivec3(-1, 1, 0))
173        );
174        assert_eq!(
175            dvec3(100.0, -200.0, 0.0),
176            points.get_bounding_box_point(ivec3(1, -1, 0))
177        );
178        assert_eq!(
179            dvec3(100.0, 100.0, 0.0),
180            points.get_bounding_box_point(ivec3(1, 1, 0))
181        );
182    }
183
184    #[test]
185    fn test_transform() {
186        let square = vec![
187            dvec3(-1.0, -1.0, 0.0),
188            dvec3(2.0, -2.0, 0.0),
189            dvec3(0.5, 1.0, 0.0),
190            dvec3(-3.0, 3.0, 0.0),
191            dvec3(4.0, 4.0, 0.0),
192        ];
193        let mut scale_origin = VPointComponentVec(square.clone().into());
194        assert_eq!(
195            scale_origin.get_bounding_box_point(IVec3::ZERO),
196            dvec3(0.5, 1.0, 0.0)
197        );
198        scale_origin.scale(DVec3::splat(3.0));
199
200        let ans = VPointComponentVec(
201            vec![
202                dvec3(-4.0, -5.0, 0.0),
203                dvec3(5.0, -8.0, 0.0),
204                dvec3(0.5, 1.0, 0.0),
205                dvec3(-10.0, 7.0, 0.0),
206                dvec3(11.0, 10.0, 0.0),
207            ]
208            .into(),
209        );
210        assert_eq!(scale_origin, ans);
211    }
212}