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