ranim_core/
traits.rs

1use std::{cmp::Ordering, ops::Range};
2
3use color::{AlphaColor, ColorSpace, Srgb};
4use glam::{DAffine2, DMat3, DMat4, DVec3, IVec3, Vec3Swizzles, dvec3, ivec3};
5use itertools::Itertools;
6use tracing::warn;
7
8use crate::components::width::Width;
9
10// MARK: Interpolatable
11/// A trait for interpolating to values
12///
13/// It uses the reference of two values and produce an owned interpolated value.
14pub trait Interpolatable {
15    /// Lerping between values
16    fn lerp(&self, target: &Self, t: f64) -> Self;
17}
18
19impl Interpolatable for f32 {
20    fn lerp(&self, target: &Self, t: f64) -> Self {
21        self + (target - self) * t as f32
22    }
23}
24
25impl Interpolatable for f64 {
26    fn lerp(&self, target: &Self, t: f64) -> Self {
27        self + (target - self) * t
28    }
29}
30
31impl Interpolatable for DVec3 {
32    fn lerp(&self, target: &Self, t: f64) -> Self {
33        self + (target - self) * t
34    }
35}
36
37impl<CS: ColorSpace> Interpolatable for AlphaColor<CS> {
38    fn lerp(&self, other: &Self, t: f64) -> Self {
39        // TODO: figure out to use `lerp_rect` or `lerp`
40        AlphaColor::lerp_rect(*self, *other, t as f32)
41    }
42}
43
44impl Interpolatable for DMat4 {
45    fn lerp(&self, other: &Self, t: f64) -> Self {
46        let mut result = DMat4::ZERO;
47        for i in 0..4 {
48            for j in 0..4 {
49                result.col_mut(i)[j] = self.col(i)[j].lerp(&other.col(i)[j], t);
50            }
51        }
52        result
53    }
54}
55
56// MARK: With
57/// A trait for mutating a value in place.
58///
59/// This trait is automatically implemented for `T`.
60///
61/// # Example
62/// ```
63/// use ranim::prelude::*;
64///
65/// let mut a = 1;
66/// a = a.with(|x| *x = 2);
67/// assert_eq!(a, 2);
68/// ```
69pub trait With {
70    /// Mutating a value inplace
71    fn with(mut self, f: impl Fn(&mut Self)) -> Self
72    where
73        Self: Sized,
74    {
75        f(&mut self);
76        self
77    }
78}
79
80impl<T> With for T {}
81
82// MARK: Alignable
83/// A trait for aligning two items
84///
85/// Alignment is actually the meaning of preparation for interpolation.
86///
87/// For example, if we want to interpolate two VItems, we need to
88/// align all their inner components like `ComponentVec<VPoint>` to the same length.
89pub trait Alignable: Clone {
90    /// Checking if two items are aligned
91    fn is_aligned(&self, other: &Self) -> bool;
92    /// Aligning two items
93    fn align_with(&mut self, other: &mut Self);
94}
95
96impl Alignable for DVec3 {
97    fn align_with(&mut self, _other: &mut Self) {}
98    fn is_aligned(&self, _other: &Self) -> bool {
99        true
100    }
101}
102
103// MARK: Opacity
104/// A trait for items with opacity
105pub trait Opacity {
106    /// Setting opacity of an item
107    fn set_opacity(&mut self, opacity: f32) -> &mut Self;
108}
109
110impl<T: Opacity, I> Opacity for I
111where
112    for<'a> &'a mut I: IntoIterator<Item = &'a mut T>,
113{
114    fn set_opacity(&mut self, opacity: f32) -> &mut Self {
115        self.into_iter().for_each(|x: &mut T| {
116            x.set_opacity(opacity);
117        });
118        self
119    }
120}
121
122// MARK: Partial
123/// A trait for items that can be displayed partially
124pub trait Partial {
125    /// Getting a partial item
126    fn get_partial(&self, range: Range<f64>) -> Self;
127    /// Getting a partial item closed
128    fn get_partial_closed(&self, range: Range<f64>) -> Self;
129}
130
131// MARK: Empty
132/// A trait for items that can be empty
133pub trait Empty {
134    /// Getting an empty item
135    fn empty() -> Self;
136}
137
138// MARK: FillColor
139/// A trait for items that have fill color
140pub trait FillColor {
141    /// Getting fill color of an item
142    fn fill_color(&self) -> AlphaColor<Srgb>;
143    /// Setting fill opacity of an item
144    fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self;
145    /// Setting fill color(rgba) of an item
146    fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self;
147}
148
149impl<T: FillColor> FillColor for [T] {
150    fn fill_color(&self) -> color::AlphaColor<color::Srgb> {
151        self[0].fill_color()
152    }
153    fn set_fill_color(&mut self, color: color::AlphaColor<color::Srgb>) -> &mut Self {
154        self.iter_mut().for_each(|x| {
155            x.set_fill_color(color);
156        });
157        self
158    }
159    fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
160        self.iter_mut().for_each(|x| {
161            x.set_fill_opacity(opacity);
162        });
163        self
164    }
165}
166
167// MARK: StrokeColor
168/// A trait for items that have stroke color
169pub trait StrokeColor {
170    /// Getting stroke color of an item
171    fn stroke_color(&self) -> AlphaColor<Srgb>;
172    /// Setting stroke opacity of an item
173    fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self;
174    /// Setting stroke color(rgba) of an item
175    fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self;
176}
177
178impl<T: StrokeColor> StrokeColor for [T] {
179    fn stroke_color(&self) -> AlphaColor<Srgb> {
180        self[0].stroke_color()
181    }
182    fn set_stroke_color(&mut self, color: color::AlphaColor<color::Srgb>) -> &mut Self {
183        self.iter_mut().for_each(|x| {
184            x.set_stroke_color(color);
185        });
186        self
187    }
188    fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
189        self.iter_mut().for_each(|x| {
190            x.set_stroke_opacity(opacity);
191        });
192        self
193    }
194}
195
196// MARK: StrokeWidth
197/// A trait for items have stroke width
198pub trait StrokeWidth {
199    // TODO: Make this better
200    /// Get the stroke width
201    fn stroke_width(&self) -> f32;
202    /// Applying stroke width function to an item
203    fn apply_stroke_func(&mut self, f: impl for<'a> Fn(&'a mut [Width])) -> &mut Self;
204    /// Setting stroke width of an item
205    fn set_stroke_width(&mut self, width: f32) -> &mut Self {
206        self.apply_stroke_func(|widths| widths.fill(width.into()))
207    }
208}
209
210impl<T: StrokeWidth> StrokeWidth for [T] {
211    fn stroke_width(&self) -> f32 {
212        self[0].stroke_width()
213    }
214    fn apply_stroke_func(
215        &mut self,
216        f: impl for<'a> Fn(&'a mut [crate::components::width::Width]),
217    ) -> &mut Self {
218        self.iter_mut().for_each(|x| {
219            x.apply_stroke_func(&f);
220        });
221        self
222    }
223}
224
225// MARK: Color
226/// A trait for items that have both fill color and stroke color
227///
228/// This trait is auto implemented for items that implement [`FillColor`] and [`StrokeColor`].
229pub trait Color: FillColor + StrokeColor {
230    /// Setting color(rgba) of an item
231    fn set_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
232        self.set_fill_color(color);
233        self.set_stroke_color(color);
234        self
235    }
236}
237
238impl<T: FillColor + StrokeColor + ?Sized> Color for T {}
239
240// MARK: BoundingBox
241/// A trait for items that have a bounding box
242pub trait BoundingBox {
243    /// Get the bounding box of the mobject in [min, mid, max] order.
244    fn get_bounding_box(&self) -> [DVec3; 3];
245    /// Get the bounding box point of the mobject at an edge Anchor.
246    ///
247    /// See [`Anchor`].
248    fn get_bounding_box_point(&self, edge: IVec3) -> DVec3 {
249        let bb = self.get_bounding_box();
250        let signum = (edge.signum() + IVec3::ONE).as_uvec3();
251
252        dvec3(
253            bb[signum.x as usize].x,
254            bb[signum.y as usize].y,
255            bb[signum.z as usize].z,
256        )
257    }
258    /// Get the bounding box corners of the mobject.
259    ///
260    /// The order is the cartesian product of [-1, 1] on x, y, z axis.
261    /// Which is `(-1, -1, -1)`, `(-1, -1, 1)`, `(-1, 1, -1)`, `(-1, 1, 1)`, ...
262    fn get_bounding_box_corners(&self) -> [DVec3; 8] {
263        [-1, 1]
264            .into_iter()
265            .cartesian_product([-1, 1])
266            .cartesian_product([-1, 1])
267            .map(|((x, y), z)| self.get_bounding_box_point(ivec3(x, y, z)))
268            .collect::<Vec<_>>()
269            .try_into()
270            .unwrap()
271    }
272}
273
274impl BoundingBox for DVec3 {
275    fn get_bounding_box(&self) -> [DVec3; 3] {
276        [*self, *self, *self]
277    }
278}
279
280impl<T: BoundingBox> BoundingBox for [T] {
281    fn get_bounding_box(&self) -> [DVec3; 3] {
282        let [min, max] = self
283            .iter()
284            .map(|x| x.get_bounding_box())
285            .map(|[min, _, max]| [min, max])
286            .reduce(|[acc_min, acc_max], [min, max]| [acc_min.min(min), acc_max.max(max)])
287            .unwrap_or([DVec3::ZERO, DVec3::ZERO]);
288        if min == max {
289            warn!("Empty bounding box, is the slice empty?")
290        }
291        [min, (min + max) / 2.0, max]
292    }
293}
294
295// MARK: PointsFunc
296/// A trait for items that can apply points function.
297pub trait PointsFunc {
298    /// Applying points function to an item
299    fn apply_points_func(&mut self, f: impl for<'a> Fn(&'a mut [DVec3])) -> &mut Self;
300    /// Applying affine transform to an item
301    fn apply_affine(&mut self, affine: DAffine2) -> &mut Self {
302        self.apply_points_func(|points| {
303            points.iter_mut().for_each(|p| {
304                let transformed = affine.transform_point2(p.xy());
305                p.x = transformed.x;
306                p.y = transformed.y;
307            });
308        });
309        self
310    }
311}
312
313// MARK: Shift
314/// A trait for shifting operations.
315pub trait Shift: BoundingBox {
316    /// Shift the item by a given vector.
317    fn shift(&mut self, shift: DVec3) -> &mut Self;
318    /// Put anchor at a given point.
319    ///
320    /// See [`Anchor`] for more details.
321    fn put_anchor_on(&mut self, anchor: Anchor, point: DVec3) -> &mut Self {
322        self.shift(point - anchor.get_pos(self));
323        self
324    }
325    /// Put center at a given point.
326    fn put_center_on(&mut self, point: DVec3) -> &mut Self {
327        self.put_anchor_on(Anchor::CENTER, point)
328    }
329}
330
331impl<T: Shift> Shift for [T] {
332    fn shift(&mut self, shift: DVec3) -> &mut Self {
333        self.iter_mut().for_each(|x| {
334            x.shift(shift);
335        });
336        self
337    }
338}
339
340// MARK: Rotate
341/// A trait for rotating operations
342pub trait Rotate {
343    /// Rotate the item by a given angle about a given axis at anchor.
344    ///
345    /// See [`Anchor`]
346    fn rotate_by_anchor(&mut self, angle: f64, axis: DVec3, anchor: Anchor) -> &mut Self;
347    /// Rotate the mobject by a given angle about a given axis at center.
348    ///
349    /// This is equivalent to [`Rotate::rotate_by_anchor`] with [`Anchor::CENTER`].
350    fn rotate(&mut self, angle: f64, axis: DVec3) -> &mut Self {
351        self.rotate_by_anchor(angle, axis, Anchor::CENTER)
352    }
353}
354
355impl<T: Rotate + BoundingBox> Rotate for [T] {
356    fn rotate_by_anchor(&mut self, angle: f64, axis: DVec3, anchor: Anchor) -> &mut Self {
357        let anchor = Anchor::Point(anchor.get_pos(self));
358        self.iter_mut().for_each(|x| {
359            x.rotate_by_anchor(angle, axis, anchor);
360        });
361        self
362    }
363}
364
365// MARK: Anchor
366/// The anchor of the transformation.
367///
368/// - [`DVec3`] implements [`Into`] [`Anchor::Point`]
369/// - [`IVec3`] implements [`Into`] [`Anchor::Edge`]
370#[derive(Debug, Clone, Copy)]
371pub enum Anchor {
372    /// A point anchor, which is an absolute coordinate
373    Point(DVec3),
374    /// An edge anchor, use -1, 0, 1 to specify the edge on each axis, (0, 0, 0) is the center point.
375    /// ```text
376    ///      +Y
377    ///      |
378    ///      |
379    ///      +----- +X
380    ///    /
381    /// +Z
382    /// ```
383    Edge(IVec3),
384}
385
386impl Anchor {
387    /// The origin point: `Anchor::Point(DVec3::ZERO)`
388    pub const ORIGIN: Self = Self::Point(DVec3::ZERO);
389    /// The center edge: `Anchor::Edge(IVec3::ZERO)`
390    pub const CENTER: Self = Self::Edge(IVec3::ZERO);
391
392    /// Construct a [`Anchor::Point`]
393    pub fn point(x: f64, y: f64, z: f64) -> Self {
394        Self::Point(dvec3(x, y, z))
395    }
396    /// Construct a [`Anchor::Edge`]
397    pub fn edge(x: i32, y: i32, z: i32) -> Self {
398        Self::Edge(ivec3(x, y, z).clamp(IVec3::NEG_ONE, IVec3::ONE))
399    }
400
401    /// Get the position of the anchor based on a [`BoundingBox`]
402    pub fn get_pos<T: BoundingBox + ?Sized>(self, bbox: &T) -> DVec3 {
403        match self {
404            Self::Point(x) => x,
405            Self::Edge(x) => bbox.get_bounding_box_point(x),
406        }
407    }
408}
409
410/// Apply the function by first transform the points to origin based on a point,
411/// then apply the function, then transform the points back.
412pub fn wrap_point_func_with_point(
413    f: impl Fn(&mut DVec3) + Copy,
414    point: DVec3,
415) -> impl Fn(&mut DVec3) + Copy {
416    move |points| {
417        *points -= point;
418        f(points);
419        *points += point;
420    }
421}
422
423// MARK: ScaleHint
424/// A hint for scaling the mobject.
425#[derive(Debug, Clone, Copy)]
426pub enum ScaleHint {
427    /// Scale the mobject's X axe
428    X(f64),
429    /// Scale the mobject's Y axe
430    Y(f64),
431    /// Scale the mobject's Z axe
432    Z(f64),
433    /// Scale the mobject's X axe, while other axes are scaled accordingly.
434    PorportionalX(f64),
435    /// Scale the mobject's Y axe, while other axes are scaled accordingly.
436    PorportionalY(f64),
437    /// Scale the mobject's Z axe, while other axes are scaled accordingly.
438    PorportionalZ(f64),
439}
440
441// MARK: Scale
442/// A trait for scaling operations
443pub trait Scale: BoundingBox {
444    /// Scale the item by a given scale at anchor.
445    ///
446    /// See [`Anchor`]
447    fn scale_by_anchor(&mut self, scale: DVec3, anchor: Anchor) -> &mut Self;
448    /// Scale the item by a given scale at center.
449    ///
450    /// This is equivalent to [`Scale::scale_by_anchor`] with [`Anchor::CENTER`].
451    fn scale(&mut self, scale: DVec3) -> &mut Self {
452        self.scale_by_anchor(scale, Anchor::CENTER)
453    }
454    /// Calculate the scale ratio for a given hint.
455    ///
456    /// See [`ScaleHint`] for more details.
457    fn calc_scale_ratio(&self, hint: ScaleHint) -> DVec3 {
458        let bb = self.get_bounding_box();
459        match hint {
460            ScaleHint::X(v) => dvec3(v / (bb[2].x - bb[0].x), 1.0, 1.0),
461            ScaleHint::Y(v) => dvec3(1.0, v / (bb[2].y - bb[0].y), 1.0),
462            ScaleHint::Z(v) => dvec3(1.0, 1.0, v / (bb[2].z - bb[0].z)),
463            ScaleHint::PorportionalX(v) => DVec3::splat(v / (bb[2].x - bb[0].x)),
464            ScaleHint::PorportionalY(v) => DVec3::splat(v / (bb[2].y - bb[0].y)),
465            ScaleHint::PorportionalZ(v) => DVec3::splat(v / (bb[2].z - bb[0].z)),
466        }
467    }
468    /// Scale the item to a given hint.
469    ///
470    /// See [`ScaleHint`] for more details.
471    fn scale_to(&mut self, hint: ScaleHint) -> &mut Self {
472        self.scale(self.calc_scale_ratio(hint));
473        self
474    }
475    /// Scale the item to the minimum scale ratio of each axis from the given hints.
476    ///
477    /// See [`ScaleHint`] for more details.
478    fn scale_to_min(&mut self, hints: &[ScaleHint]) -> &mut Self {
479        let scale = hints
480            .iter()
481            .map(|hint| self.calc_scale_ratio(*hint))
482            .reduce(|a, b| a.min(b))
483            .unwrap_or(DVec3::ONE);
484        self.scale(scale);
485        self
486    }
487    /// Scale the item to the maximum scale ratio of each axis from the given hints.
488    ///
489    /// See [`ScaleHint`] for more details.
490    fn scale_to_max(&mut self, hints: &[ScaleHint]) -> &mut Self {
491        let scale = hints
492            .iter()
493            .map(|hint| self.calc_scale_ratio(*hint))
494            .reduce(|a, b| a.max(b))
495            .unwrap_or(DVec3::ONE);
496        self.scale(scale);
497        self
498    }
499}
500
501impl<T: Scale> Scale for [T] {
502    fn scale_by_anchor(&mut self, scale: DVec3, anchor: Anchor) -> &mut Self {
503        let anchor = match anchor {
504            Anchor::Point(p) => p,
505            Anchor::Edge(e) => self.get_bounding_box_point(e),
506        };
507        self.iter_mut().for_each(|x| {
508            x.scale_by_anchor(scale, Anchor::Point(anchor));
509        });
510        self
511    }
512}
513
514impl Shift for DVec3 {
515    fn shift(&mut self, shift: DVec3) -> &mut Self {
516        *self += shift;
517        self
518    }
519}
520
521impl Rotate for DVec3 {
522    fn rotate_by_anchor(&mut self, angle: f64, axis: DVec3, anchor: Anchor) -> &mut Self {
523        let rotation = DMat3::from_axis_angle(axis, angle);
524        let p = match anchor {
525            Anchor::Point(point) => point,
526            Anchor::Edge(edge) => self.get_bounding_box_point(edge),
527        };
528        wrap_point_func_with_point(|p| *p = rotation * *p, p)(self);
529        if self.x.abs() < 1e-10 {
530            self.x = 0.0;
531        }
532        if self.y.abs() < 1e-10 {
533            self.y = 0.0;
534        }
535        if self.z.abs() < 1e-10 {
536            self.z = 0.0;
537        }
538        self
539    }
540}
541
542impl Scale for DVec3 {
543    fn scale_by_anchor(&mut self, scale: DVec3, anchor: Anchor) -> &mut Self {
544        let p = match anchor {
545            Anchor::Point(point) => point,
546            Anchor::Edge(edge) => self.get_bounding_box_point(edge),
547        };
548        wrap_point_func_with_point(|p| *p *= scale, p)(self);
549        self
550    }
551}
552
553// MARK: Arrange
554/// A trait for arranging operations.
555pub trait Arrange: Shift {
556    /// Arrange the items by a given function.
557    ///
558    /// The `pos_func` takes index as input and output the center position.
559    fn arrange(&mut self, pos_func: impl Fn(usize) -> DVec3);
560    /// Arrange the items in a grid with given number of columns.
561    ///
562    /// The `pos_func` takes row and column index as input and output the center position.
563    fn arrange_cols(&mut self, ncols: usize, pos_func: impl Fn(usize, usize) -> DVec3);
564    /// Arrange the items in a grid with given number of rows.
565    ///
566    /// The `pos_func` takes row and column index as input and output the center position.
567    fn arrange_rows(&mut self, nrows: usize, pos_func: impl Fn(usize, usize) -> DVec3);
568}
569
570impl<T: Shift> Arrange for [T] {
571    fn arrange(&mut self, pos_func: impl Fn(usize) -> DVec3) {
572        self.iter_mut().enumerate().for_each(|(i, item)| {
573            item.put_center_on(pos_func(i));
574        });
575    }
576    fn arrange_cols(&mut self, ncols: usize, pos_func: impl Fn(usize, usize) -> DVec3) {
577        let pos_func = |idx: usize| {
578            let row = idx / ncols;
579            let col = idx % ncols;
580            pos_func(row, col)
581        };
582        self.arrange(pos_func);
583    }
584    fn arrange_rows(&mut self, nrows: usize, pos_func: impl Fn(usize, usize) -> DVec3) {
585        let ncols = self.len().div_ceil(nrows);
586        self.arrange_cols(ncols, pos_func);
587    }
588}
589
590// MARK: ScaleStrokeExt
591/// A trait for scaling operations with stroke width.
592pub trait ScaleStrokeExt: Scale + StrokeWidth {
593    /// Scale the item by a given scale at anchor with stroke width.
594    fn scale_with_stroke_by_anchor(&mut self, scale: DVec3, anchor: Anchor) -> &mut Self {
595        self.scale_by_anchor(scale, anchor);
596
597        let scales = [scale.x, scale.y, scale.z];
598        let idx = scales
599            .iter()
600            .map(|x: &f64| if *x > 1.0 { *x } else { 1.0 / *x })
601            .position_max_by(|a, b| a.partial_cmp(b).unwrap_or(Ordering::Equal))
602            .unwrap_or(0);
603        let scale = scales[idx];
604        self.apply_stroke_func(|widths| widths.iter_mut().for_each(|w| w.0 *= scale as f32));
605        self
606    }
607    /// Scale the item by a given scale with stroke width.
608    fn scale_with_stroke(&mut self, scale: DVec3) -> &mut Self {
609        self.scale_with_stroke_by_anchor(scale, Anchor::CENTER)
610    }
611    /// Scale the item to a given hint.
612    ///
613    /// See [`ScaleHint`] for more details.
614    fn scale_to_with_stroke(&mut self, hint: ScaleHint) -> &mut Self {
615        let scale = self.calc_scale_ratio(hint);
616        self.scale_with_stroke(scale)
617    }
618}
619
620impl<T: Scale + StrokeWidth + ?Sized> ScaleStrokeExt for T {}