ranim_core/traits/
mod.rs

1/// Transform related traits
2pub mod transform {
3    mod rotate;
4    mod scale;
5    mod shift;
6
7    pub use rotate::*;
8    pub use scale::*;
9    pub use shift::*;
10}
11pub use transform::*;
12
13pub use crate::anchor::{Aabb, AabbPoint, Locate};
14
15use std::ops::Range;
16
17use color::{AlphaColor, ColorSpace, OpaqueColor, Srgb};
18use glam::{
19    DAffine2, DAffine3, DMat4, DQuat, DVec2, DVec3, Mat4, USizeVec3, Vec3, Vec3Swizzles, dvec3,
20};
21use num::complex::Complex64;
22
23use crate::{components::width::Width, utils::resize_preserving_order_with_repeated_indices};
24
25// MARK: With
26/// A trait for mutating a value in place.
27///
28/// This trait is automatically implemented for `T`.
29///
30/// # Example
31/// ```ignore
32/// use ranim::prelude::*;
33///
34/// let mut a = 1;
35/// a = a.with(|x| *x = 2);
36/// assert_eq!(a, 2);
37/// ```
38pub trait With {
39    /// Mutating a value in place
40    fn with(mut self, f: impl Fn(&mut Self)) -> Self
41    where
42        Self: Sized,
43    {
44        f(&mut self);
45        self
46    }
47}
48
49impl<T> With for T {}
50
51/// A trait for discarding a value.
52///
53/// It is useful when you want a short closure:
54/// ```ignore
55/// let x = Square::new(1.0).with(|x| {
56///     x.set_color(manim::BLUE_C);
57/// });
58/// let x = Square::new(1.0).with(|x|
59///     x.set_color(manim::BLUE_C).discard()
60/// );
61/// ```
62pub trait Discard {
63    /// Simply returns `()`
64    fn discard(&self) {}
65}
66
67impl<T> Discard for T {}
68
69// MARK: Interpolatable
70/// A trait for interpolating to values
71///
72/// It uses the reference of two values and produce an owned interpolated value.
73pub trait Interpolatable {
74    /// Lerping between values
75    fn lerp(&self, target: &Self, t: f64) -> Self;
76}
77
78impl Interpolatable for usize {
79    fn lerp(&self, target: &Self, t: f64) -> Self {
80        (*self as f32).lerp(&(*target as f32), t) as usize
81    }
82}
83
84impl Interpolatable for f32 {
85    fn lerp(&self, target: &Self, t: f64) -> Self {
86        self + (target - self) * t as f32
87    }
88}
89
90impl Interpolatable for f64 {
91    fn lerp(&self, target: &Self, t: f64) -> Self {
92        self + (target - self) * t
93    }
94}
95
96impl Interpolatable for DVec3 {
97    fn lerp(&self, target: &Self, t: f64) -> Self {
98        self + (target - self) * t
99    }
100}
101
102impl Interpolatable for Vec3 {
103    fn lerp(&self, target: &Self, t: f64) -> Self {
104        self + (target - self) * t as f32
105    }
106}
107
108impl Interpolatable for DVec2 {
109    fn lerp(&self, target: &Self, t: f64) -> Self {
110        self + (target - self) * t
111    }
112}
113
114impl Interpolatable for DQuat {
115    fn lerp(&self, target: &Self, t: f64) -> Self {
116        self.slerp(*target, t)
117    }
118}
119
120impl<CS: ColorSpace> Interpolatable for AlphaColor<CS> {
121    fn lerp(&self, target: &Self, t: f64) -> Self {
122        // TODO: figure out to use `lerp_rect` or `lerp`
123        AlphaColor::lerp_rect(*self, *target, t as f32)
124    }
125}
126
127impl<CS: ColorSpace> Interpolatable for OpaqueColor<CS> {
128    fn lerp(&self, target: &Self, t: f64) -> Self {
129        // TODO: figure out to use `lerp_rect` or `lerp`
130        OpaqueColor::lerp_rect(*self, *target, t as f32)
131    }
132}
133
134impl Interpolatable for DMat4 {
135    fn lerp(&self, target: &Self, t: f64) -> Self {
136        let mut result = DMat4::ZERO;
137        for i in 0..4 {
138            for j in 0..4 {
139                result.col_mut(i)[j] = self.col(i)[j].lerp(&target.col(i)[j], t);
140            }
141        }
142        result
143    }
144}
145
146impl Interpolatable for Mat4 {
147    fn lerp(&self, other: &Self, t: f64) -> Self {
148        let t = t as f32;
149        let mut result = Mat4::ZERO;
150        for i in 0..4 {
151            for j in 0..4 {
152                result.col_mut(i)[j] = self.col(i)[j] + (other.col(i)[j] - self.col(i)[j]) * t;
153            }
154        }
155        result
156    }
157}
158
159impl<T: Interpolatable> Interpolatable for Vec<T> {
160    fn lerp(&self, target: &Self, t: f64) -> Self {
161        self.iter().zip(target).map(|(a, b)| a.lerp(b, t)).collect()
162    }
163}
164
165impl<T: Interpolatable, const N: usize> Interpolatable for [T; N] {
166    fn lerp(&self, target: &Self, t: f64) -> Self {
167        core::array::from_fn(|i| self[i].lerp(&target[i], t))
168    }
169}
170
171macro_rules! impl_interpolatable_tuple {
172    ($(($T:ident, $s:ident)),*) => {
173        impl<$($T: Interpolatable),*> Interpolatable for ($($T,)*) {
174            #[allow(non_snake_case)]
175            fn lerp(&self, target: &Self, t: f64) -> Self {
176                let ($($s,)*) = self;
177                let ($($T,)*) = target;
178                ($($s.lerp($T, t),)*)
179            }
180        }
181    }
182}
183variadics_please::all_tuples!(impl_interpolatable_tuple, 1, 12, T, S);
184
185impl<T: Opacity + Alignable + Clone> Alignable for Vec<T> {
186    fn is_aligned(&self, other: &Self) -> bool {
187        self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.is_aligned(b))
188    }
189    fn align_with(&mut self, other: &mut Self) {
190        let len = self.len().max(other.len());
191
192        let transparent_repeated = |items: &mut Vec<T>, repeat_idxs: Vec<usize>| {
193            for idx in repeat_idxs {
194                items[idx].set_opacity(0.0);
195            }
196        };
197        if self.len() != len {
198            let (mut items, idxs) = resize_preserving_order_with_repeated_indices(self, len);
199            transparent_repeated(&mut items, idxs);
200            *self = items;
201        }
202        if other.len() != len {
203            let (mut items, idxs) = resize_preserving_order_with_repeated_indices(other, len);
204            transparent_repeated(&mut items, idxs);
205            *other = items;
206        }
207        self.iter_mut()
208            .zip(other)
209            .for_each(|(a, b)| a.align_with(b));
210    }
211}
212
213// MARK: Alignable
214/// A trait for aligning two items
215///
216/// Alignment is actually the meaning of preparation for interpolation.
217///
218/// For example, if we want to interpolate two VItems, we need to
219/// align all their inner components like `ComponentVec<VPoint>` to the same length.
220pub trait Alignable: Clone {
221    /// Checking if two items are aligned
222    fn is_aligned(&self, other: &Self) -> bool;
223    /// Aligning two items
224    fn align_with(&mut self, other: &mut Self);
225}
226
227impl Alignable for DVec3 {
228    fn align_with(&mut self, _other: &mut Self) {}
229    fn is_aligned(&self, _other: &Self) -> bool {
230        true
231    }
232}
233
234// MARK: Opacity
235/// A trait for items with opacity
236pub trait Opacity {
237    /// Setting opacity of an item
238    fn set_opacity(&mut self, opacity: f32) -> &mut Self;
239}
240
241impl<T: Opacity, I> Opacity for I
242where
243    for<'a> &'a mut I: IntoIterator<Item = &'a mut T>,
244{
245    fn set_opacity(&mut self, opacity: f32) -> &mut Self {
246        self.into_iter().for_each(|x: &mut T| {
247            x.set_opacity(opacity);
248        });
249        self
250    }
251}
252
253// MARK: Partial
254/// A trait for items that can be displayed partially
255pub trait Partial {
256    /// Getting a partial item
257    fn get_partial(&self, range: Range<f64>) -> Self;
258    /// Getting a partial item closed
259    fn get_partial_closed(&self, range: Range<f64>) -> Self;
260}
261
262// MARK: Empty
263/// A trait for items that can be empty
264pub trait Empty {
265    /// Getting an empty item
266    fn empty() -> Self;
267}
268
269// MARK: FillColor
270/// A trait for items that have fill color
271pub trait FillColor {
272    /// Getting fill color of an item
273    fn fill_color(&self) -> AlphaColor<Srgb>;
274    /// Setting fill opacity of an item
275    fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self;
276    /// Setting fill color(rgba) of an item
277    fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self;
278}
279
280impl<T: FillColor> FillColor for [T] {
281    fn fill_color(&self) -> color::AlphaColor<color::Srgb> {
282        self[0].fill_color()
283    }
284    fn set_fill_color(&mut self, color: color::AlphaColor<color::Srgb>) -> &mut Self {
285        self.iter_mut()
286            .for_each(|x| x.set_fill_color(color).discard());
287        self
288    }
289    fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
290        self.iter_mut()
291            .for_each(|x| x.set_fill_opacity(opacity).discard());
292        self
293    }
294}
295
296// MARK: StrokeColor
297/// A trait for items that have stroke color
298pub trait StrokeColor {
299    /// Getting stroke color of an item
300    fn stroke_color(&self) -> AlphaColor<Srgb>;
301    /// Setting stroke opacity of an item
302    fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self;
303    /// Setting stroke color(rgba) of an item
304    fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self;
305}
306
307impl<T: StrokeColor> StrokeColor for [T] {
308    fn stroke_color(&self) -> AlphaColor<Srgb> {
309        self[0].stroke_color()
310    }
311    fn set_stroke_color(&mut self, color: color::AlphaColor<color::Srgb>) -> &mut Self {
312        self.iter_mut().for_each(|x| {
313            x.set_stroke_color(color);
314        });
315        self
316    }
317    fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
318        self.iter_mut().for_each(|x| {
319            x.set_stroke_opacity(opacity);
320        });
321        self
322    }
323}
324
325// MARK: StrokeWidth
326/// A trait for items have stroke width
327pub trait StrokeWidth {
328    // TODO: Make this better
329    /// Get the stroke width
330    fn stroke_width(&self) -> f32;
331    /// Applying stroke width function to an item
332    fn apply_stroke_func(&mut self, f: impl for<'a> Fn(&'a mut [Width])) -> &mut Self;
333    /// Setting stroke width of an item
334    fn set_stroke_width(&mut self, width: f32) -> &mut Self {
335        self.apply_stroke_func(|widths| widths.fill(width.into()))
336    }
337}
338
339impl<T: StrokeWidth> StrokeWidth for [T] {
340    fn stroke_width(&self) -> f32 {
341        self[0].stroke_width()
342    }
343    fn apply_stroke_func(
344        &mut self,
345        f: impl for<'a> Fn(&'a mut [crate::components::width::Width]),
346    ) -> &mut Self {
347        self.iter_mut().for_each(|x| {
348            x.apply_stroke_func(&f);
349        });
350        self
351    }
352}
353
354// MARK: Color
355/// A trait for items that have both fill color and stroke color
356///
357/// This trait is auto implemented for items that implement [`FillColor`] and [`StrokeColor`].
358pub trait Color: FillColor + StrokeColor {
359    /// Setting color(rgba) of an item
360    fn set_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
361        self.set_fill_color(color);
362        self.set_stroke_color(color);
363        self
364    }
365}
366
367impl<T: FillColor + StrokeColor + ?Sized> Color for T {}
368
369// MARK: PointsFunc
370/// A trait for items that can apply points function.
371pub trait PointsFunc {
372    /// Applying points function to an item
373    fn apply_points_func(&mut self, f: impl for<'a> Fn(&'a mut [DVec3])) -> &mut Self;
374
375    /// Applying affine transform in xy plane to an item
376    fn apply_affine2(&mut self, affine: DAffine2) -> &mut Self {
377        self.apply_point_func(|p| {
378            let transformed = affine.transform_point2(p.xy());
379            p.x = transformed.x;
380            p.y = transformed.y;
381        });
382        self
383    }
384
385    /// Applying affine transform to an item
386    fn apply_affine3(&mut self, affine: DAffine3) -> &mut Self {
387        self.apply_point_func(|p| *p = affine.transform_point3(*p));
388        self
389    }
390
391    /// Applying point function to an item
392    fn apply_point_func(&mut self, f: impl Fn(&mut DVec3)) -> &mut Self {
393        self.apply_points_func(|points| {
394            points.iter_mut().for_each(&f);
395        });
396        self
397    }
398    /// Applying point function to an item
399    fn apply_point_map(&mut self, f: impl Fn(DVec3) -> DVec3) -> &mut Self {
400        self.apply_points_func(|points| {
401            points.iter_mut().for_each(|p| *p = f(*p));
402        });
403        self
404    }
405
406    /// Applying complex function to an item.
407    ///
408    /// The point's x and y coordinates will be used as real and imaginary parts of a complex number.
409    fn apply_complex_func(&mut self, f: impl Fn(&mut Complex64)) -> &mut Self {
410        self.apply_point_func(|p| {
411            let mut c = Complex64::new(p.x, p.y);
412            f(&mut c);
413            p.x = c.re;
414            p.y = c.im;
415        });
416        self
417    }
418    /// Applying complex function to an item.
419    ///
420    /// The point's x and y coordinates will be used as real and imaginary parts of a complex number.
421    fn apply_complex_map(&mut self, f: impl Fn(Complex64) -> Complex64) -> &mut Self {
422        self.apply_complex_func(|p| {
423            *p = f(*p);
424        });
425        self
426    }
427}
428
429impl PointsFunc for DVec3 {
430    fn apply_points_func(&mut self, f: impl for<'a> Fn(&'a mut [DVec3])) -> &mut Self {
431        f(std::slice::from_mut(self));
432        self
433    }
434}
435
436impl<T: PointsFunc> PointsFunc for [T] {
437    fn apply_points_func(&mut self, f: impl for<'a> Fn(&'a mut [DVec3])) -> &mut Self {
438        self.iter_mut()
439            .for_each(|x| x.apply_points_func(&f).discard());
440        self
441    }
442}
443
444// MARK: Align
445/// Align a slice of items
446pub trait AlignSlice<T: transform::ShiftTransformExt>: AsMut<[T]> {
447    /// Align items' anchors in a given axis, based on the first item.
448    fn align_anchor<A>(&mut self, axis: DVec3, anchor: A) -> &mut Self
449    where
450        A: Locate<T> + Clone,
451    {
452        let Some(dir) = axis.try_normalize() else {
453            return self;
454        };
455        let Some(point) = self.as_mut().first().map(|x| anchor.locate(x)) else {
456            return self;
457        };
458
459        self.as_mut().iter_mut().for_each(|x| {
460            let p = anchor.locate(x);
461
462            let v = p - point;
463            let proj = dir * v.dot(dir);
464            let closest = point + proj;
465            let displacement = closest - p;
466            x.shift(displacement);
467        });
468        self
469    }
470    /// Align items' centers in a given axis, based on the first item.
471    fn align(&mut self, axis: DVec3) -> &mut Self
472    where
473        T: Aabb,
474    {
475        self.align_anchor(axis, AabbPoint::CENTER)
476    }
477}
478
479// MARK: Arrange
480/// A trait for arranging operations.
481pub trait ArrangeSlice<T: transform::ShiftTransformExt>: AsMut<[T]> {
482    /// Arrange the items by a given function.
483    ///
484    /// The `pos_func` takes index as input and output the center position.
485    fn arrange_with(&mut self, pos_func: impl Fn(usize) -> DVec3)
486    where
487        AabbPoint: Locate<T>,
488    {
489        self.as_mut().iter_mut().enumerate().for_each(|(i, x)| {
490            x.move_to(pos_func(i));
491        });
492    }
493    /// Arrange the items in a col
494    fn arrange_in_y(&mut self, gap: f64)
495    where
496        T: Aabb,
497        AabbPoint: Locate<T>,
498    {
499        let Some(mut bbox) = self.as_mut().first().map(|x| x.aabb()) else {
500            return;
501        };
502
503        self.as_mut().iter_mut().for_each(|x| {
504            x.move_next_to_padded(bbox.as_slice(), AabbPoint(DVec3::Y), gap);
505            bbox = x.aabb();
506        });
507    }
508    /// Arrange the items in a grid.
509    fn arrange_in_grid(&mut self, cell_cnt: USizeVec3, cell_size: DVec3, gap: DVec3) -> &mut Self
510    where
511        AabbPoint: Locate<T>,
512    {
513        // x -> y -> z
514        let pos_func = |idx: usize| {
515            let x = idx % cell_cnt.x;
516            let temp = idx / cell_cnt.x;
517
518            let y = temp % cell_cnt.y;
519            let z = temp / cell_cnt.y;
520            dvec3(x as f64, y as f64, z as f64) * cell_size
521                + gap * dvec3(x as f64, y as f64, z as f64)
522        };
523        self.arrange_with(pos_func);
524        self
525    }
526    /// Arrange the items in a grid with given number of columns.
527    ///
528    /// The `pos_func` takes row and column index as input and output the center position.
529    fn arrange_in_cols_with(&mut self, ncols: usize, pos_func: impl Fn(usize, usize) -> DVec3)
530    where
531        AabbPoint: Locate<T>,
532    {
533        let pos_func = |idx: usize| {
534            let row = idx / ncols;
535            let col = idx % ncols;
536            pos_func(row, col)
537        };
538        self.arrange_with(pos_func);
539    }
540    /// Arrange the items in a grid with given number of rows.
541    ///
542    /// The `pos_func` takes row and column index as input and output the center position.
543    fn arrange_in_rows_with(&mut self, nrows: usize, pos_func: impl Fn(usize, usize) -> DVec3)
544    where
545        AabbPoint: Locate<T>,
546    {
547        let ncols = self.as_mut().len().div_ceil(nrows);
548        self.arrange_in_cols_with(ncols, pos_func);
549    }
550}
551
552impl<T: transform::ShiftTransformExt, E: AsMut<[T]>> ArrangeSlice<T> for E {}