ranim_items/
vitem.rs

1// pub mod arrow;
2/// Geometry items
3pub mod geometry;
4/// Svg item
5pub mod svg;
6/// Typst items
7pub mod typst;
8// pub mod line;
9
10use color::{AlphaColor, Srgb, palette::css};
11use derive_more::{Deref, DerefMut};
12use glam::{DVec3, Vec4, vec4};
13use ranim_core::primitives::vitem::VItemPrimitive;
14use ranim_core::traits::Anchor;
15use ranim_core::utils::resize_preserving_order_with_repeated_indices;
16use ranim_core::{Extract, color, glam};
17
18use ranim_core::{
19    components::{ComponentVec, rgba::Rgba, vpoint::VPointComponentVec, width::Width},
20    prelude::{Alignable, Empty, FillColor, Interpolatable, Opacity, Partial, StrokeWidth},
21    traits::{BoundingBox, PointsFunc, Rotate, Scale, Shift, StrokeColor},
22};
23
24/// A vectorized item.
25///
26/// It is built from four components:
27/// - [`VItem::vpoints`]: the vpoints of the item, see [`VPointComponentVec`].
28/// - [`VItem::stroke_widths`]: the stroke widths of the item, see [`Width`].
29/// - [`VItem::stroke_rgbas`]: the stroke colors of the item, see [`Rgba`].
30/// - [`VItem::fill_rgbas`]: the fill colors of the item, see [`Rgba`].
31///
32/// You can construct a [`VItem`] from a list of VPoints, see [`VPointComponentVec`]:
33///
34/// ```rust
35/// let vitem = VItem::from_vpoints(vec![
36///     dvec3(0.0, 0.0, 0.0),
37///     dvec3(1.0, 0.0, 0.0),
38///     dvec3(0.5, 1.0, 0.0),
39/// ]);
40/// ```
41///
42///
43#[derive(Debug, Clone, PartialEq)]
44pub struct VItem {
45    /// vpoints data
46    pub vpoints: VPointComponentVec,
47    /// stroke widths
48    pub stroke_widths: ComponentVec<Width>,
49    /// stroke rgbas
50    pub stroke_rgbas: ComponentVec<Rgba>,
51    /// fill rgbas
52    pub fill_rgbas: ComponentVec<Rgba>,
53}
54
55impl PointsFunc for VItem {
56    fn apply_points_func(&mut self, f: impl Fn(&mut [DVec3])) -> &mut Self {
57        self.vpoints.apply_points_func(f);
58        self
59    }
60}
61
62impl BoundingBox for VItem {
63    fn get_bounding_box(&self) -> [DVec3; 3] {
64        self.vpoints.get_bounding_box()
65    }
66}
67
68impl Shift for VItem {
69    fn shift(&mut self, shift: DVec3) -> &mut Self {
70        self.vpoints.shift(shift);
71        self
72    }
73}
74
75impl Rotate for VItem {
76    fn rotate_by_anchor(&mut self, angle: f64, axis: DVec3, anchor: Anchor) -> &mut Self {
77        self.vpoints.rotate_by_anchor(angle, axis, anchor);
78        self
79    }
80}
81
82impl Scale for VItem {
83    fn scale_by_anchor(&mut self, scale: DVec3, anchor: Anchor) -> &mut Self {
84        self.vpoints.scale_by_anchor(scale, anchor);
85        self
86    }
87}
88
89/// Default stroke width
90pub const DEFAULT_STROKE_WIDTH: f32 = 0.02;
91
92impl VItem {
93    /// Close the VItem
94    pub fn close(&mut self) -> &mut Self {
95        if self.vpoints.last() != self.vpoints.first() && !self.vpoints.is_empty() {
96            let start = self.vpoints[0];
97            let end = self.vpoints[self.vpoints.len() - 1];
98            self.extend_vpoints(&[(start + end) / 2.0, start]);
99        }
100        self
101    }
102    /// Shrink to center
103    pub fn shrink(&mut self) -> &mut Self {
104        let bb = self.get_bounding_box();
105        self.vpoints.0 = vec![bb[1]; self.vpoints.len()].into();
106        self
107    }
108    /// Set the vpoints of the VItem
109    pub fn set_points(&mut self, vpoints: Vec<DVec3>) {
110        self.vpoints.0 = vpoints.into();
111    }
112    /// Get anchor points
113    pub fn get_anchor(&self, idx: usize) -> Option<&DVec3> {
114        self.vpoints.get(idx * 2)
115    }
116    /// Construct a [`VItem`] form vpoints
117    pub fn from_vpoints(vpoints: Vec<DVec3>) -> Self {
118        let stroke_widths = vec![DEFAULT_STROKE_WIDTH; vpoints.len().div_ceil(2)];
119        let stroke_rgbas = vec![vec4(1.0, 1.0, 1.0, 1.0); vpoints.len().div_ceil(2)];
120        let fill_rgbas = vec![vec4(0.0, 0.0, 0.0, 0.0); vpoints.len().div_ceil(2)];
121        Self {
122            vpoints: VPointComponentVec(vpoints.into()),
123            stroke_rgbas: stroke_rgbas.into(),
124            stroke_widths: stroke_widths.into(),
125            fill_rgbas: fill_rgbas.into(),
126        }
127    }
128    /// Extend vpoints of the VItem
129    pub fn extend_vpoints(&mut self, vpoints: &[DVec3]) {
130        self.vpoints.extend_from_vec(vpoints.to_vec());
131
132        let len = self.vpoints.len();
133        self.fill_rgbas.resize_with_last(len.div_ceil(2));
134        self.stroke_rgbas.resize_with_last(len.div_ceil(2));
135        self.stroke_widths.resize_with_last(len.div_ceil(2));
136    }
137
138    pub(crate) fn get_render_points(&self) -> Vec<Vec4> {
139        self.vpoints
140            .iter()
141            .zip(self.vpoints.get_closepath_flags().iter())
142            .map(|(p, f)| {
143                vec4(
144                    p.x as f32,
145                    p.y as f32,
146                    p.z as f32,
147                    if *f { 1.0 } else { 0.0 },
148                )
149            })
150            .collect()
151    }
152    /// Put start and end on
153    pub fn put_start_and_end_on(&mut self, start: DVec3, end: DVec3) -> &mut Self {
154        self.vpoints.put_start_and_end_on(start, end);
155        self
156    }
157}
158
159/// See [`VItemPrimitive`].
160impl Extract for VItem {
161    type Target = VItemPrimitive;
162    fn extract(&self) -> Vec<Self::Target> {
163        vec![VItemPrimitive {
164            points2d: self.get_render_points(),
165            fill_rgbas: self.fill_rgbas.iter().cloned().collect(),
166            stroke_rgbas: self.stroke_rgbas.iter().cloned().collect(),
167            stroke_widths: self.stroke_widths.iter().cloned().collect(),
168        }]
169    }
170}
171
172// MARK: Anim traits impl
173impl Alignable for VItem {
174    fn is_aligned(&self, other: &Self) -> bool {
175        self.vpoints.is_aligned(&other.vpoints)
176            && self.stroke_widths.is_aligned(&other.stroke_widths)
177            && self.stroke_rgbas.is_aligned(&other.stroke_rgbas)
178            && self.fill_rgbas.is_aligned(&other.fill_rgbas)
179    }
180    fn align_with(&mut self, other: &mut Self) {
181        self.vpoints.align_with(&mut other.vpoints);
182        let len = self.vpoints.len().div_ceil(2);
183        self.stroke_rgbas.resize_preserving_order(len);
184        other.stroke_rgbas.resize_preserving_order(len);
185        self.stroke_widths.resize_preserving_order(len);
186        other.stroke_widths.resize_preserving_order(len);
187        self.fill_rgbas.resize_preserving_order(len);
188        other.fill_rgbas.resize_preserving_order(len);
189    }
190}
191
192impl Interpolatable for VItem {
193    fn lerp(&self, target: &Self, t: f64) -> Self {
194        let vpoints = self.vpoints.lerp(&target.vpoints, t);
195        let stroke_rgbas = self.stroke_rgbas.lerp(&target.stroke_rgbas, t);
196        let stroke_widths = self.stroke_widths.lerp(&target.stroke_widths, t);
197        let fill_rgbas = self.fill_rgbas.lerp(&target.fill_rgbas, t);
198        Self {
199            vpoints,
200            stroke_widths,
201            stroke_rgbas,
202            fill_rgbas,
203        }
204    }
205}
206
207impl Opacity for VItem {
208    fn set_opacity(&mut self, opacity: f32) -> &mut Self {
209        self.stroke_rgbas.set_opacity(opacity);
210        self.fill_rgbas.set_opacity(opacity);
211        self
212    }
213}
214
215impl Partial for VItem {
216    fn get_partial(&self, range: std::ops::Range<f64>) -> Self {
217        let vpoints = self.vpoints.get_partial(range.clone());
218        let stroke_rgbas = self.stroke_rgbas.get_partial(range.clone());
219        let stroke_widths = self.stroke_widths.get_partial(range.clone());
220        let fill_rgbas = self.fill_rgbas.get_partial(range.clone());
221        Self {
222            vpoints,
223            stroke_widths,
224            stroke_rgbas,
225            fill_rgbas,
226        }
227    }
228    fn get_partial_closed(&self, range: std::ops::Range<f64>) -> Self {
229        let mut partial = self.get_partial(range);
230        partial.close();
231        partial
232    }
233}
234
235impl Empty for VItem {
236    fn empty() -> Self {
237        Self {
238            vpoints: VPointComponentVec(vec![DVec3::ZERO; 3].into()),
239            stroke_widths: vec![0.0, 0.0].into(),
240            stroke_rgbas: vec![Vec4::ZERO; 2].into(),
241            fill_rgbas: vec![Vec4::ZERO; 2].into(),
242        }
243    }
244}
245
246impl FillColor for VItem {
247    fn fill_color(&self) -> AlphaColor<Srgb> {
248        self.fill_rgbas
249            .first()
250            .map(|&rgba| rgba.into())
251            .unwrap_or(css::WHITE)
252    }
253    fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
254        self.fill_rgbas.set_all(color);
255        self
256    }
257    fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
258        self.fill_rgbas.set_opacity(opacity);
259        self
260    }
261}
262
263impl StrokeColor for VItem {
264    fn stroke_color(&self) -> AlphaColor<Srgb> {
265        self.stroke_rgbas
266            .first()
267            .map(|&rgba| rgba.into())
268            .unwrap_or(css::WHITE)
269    }
270    fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
271        self.stroke_rgbas.set_all(color);
272        self
273    }
274    fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
275        self.stroke_rgbas.set_opacity(opacity);
276        self
277    }
278}
279
280impl StrokeWidth for VItem {
281    fn stroke_width(&self) -> f32 {
282        self.stroke_widths[0].0
283    }
284    fn apply_stroke_func(&mut self, f: impl for<'a> Fn(&'a mut [Width])) -> &mut Self {
285        f(self.stroke_widths.as_mut());
286        self
287    }
288}
289
290/// A Group of type `T`.
291///
292/// Just like a [`Vec`]
293#[derive(Debug, Default, Clone, PartialEq, Deref, DerefMut)]
294pub struct Group<T: Opacity>(pub Vec<T>);
295
296impl<T: Opacity> IntoIterator for Group<T> {
297    type IntoIter = std::vec::IntoIter<T>;
298    type Item = T;
299    fn into_iter(self) -> Self::IntoIter {
300        self.0.into_iter()
301    }
302}
303
304impl<'a, T: Opacity> IntoIterator for &'a Group<T> {
305    type IntoIter = std::slice::Iter<'a, T>;
306    type Item = &'a T;
307    fn into_iter(self) -> Self::IntoIter {
308        self.0.iter()
309    }
310}
311
312impl<'a, T: Opacity> IntoIterator for &'a mut Group<T> {
313    type IntoIter = std::slice::IterMut<'a, T>;
314    type Item = &'a mut T;
315    fn into_iter(self) -> Self::IntoIter {
316        self.0.iter_mut()
317    }
318}
319
320impl<T: Opacity> FromIterator<T> for Group<T> {
321    fn from_iter<I: IntoIterator<Item = T>>(iter: I) -> Self {
322        Self(Vec::from_iter(iter))
323    }
324}
325
326impl<T: Interpolatable + Opacity> Interpolatable for Group<T> {
327    fn lerp(&self, target: &Self, t: f64) -> Self {
328        self.into_iter()
329            .zip(target)
330            .map(|(a, b)| a.lerp(b, t))
331            .collect()
332    }
333}
334
335impl<T: Opacity + Alignable + Clone> Alignable for Group<T> {
336    fn is_aligned(&self, other: &Self) -> bool {
337        self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.is_aligned(b))
338    }
339    fn align_with(&mut self, other: &mut Self) {
340        let len = self.len().max(other.len());
341
342        let transparent_repeated = |items: &mut Vec<T>, repeat_idxs: Vec<usize>| {
343            for idx in repeat_idxs {
344                items[idx].set_opacity(0.0);
345            }
346        };
347        if self.len() != len {
348            let (mut items, idxs) = resize_preserving_order_with_repeated_indices(&self.0, len);
349            transparent_repeated(&mut items, idxs);
350            self.0 = items;
351        }
352        if other.len() != len {
353            let (mut items, idxs) = resize_preserving_order_with_repeated_indices(&other.0, len);
354            transparent_repeated(&mut items, idxs);
355            other.0 = items;
356        }
357        self.iter_mut()
358            .zip(other)
359            .for_each(|(a, b)| a.align_with(b));
360    }
361}
362
363impl<E: Extract + Opacity> Extract for Group<E> {
364    type Target = E::Target;
365    fn extract(&self) -> Vec<Self::Target> {
366        self.iter().flat_map(|x| x.extract()).collect()
367    }
368}