1pub mod geometry;
4pub mod svg;
6pub mod typst;
8use 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#[derive(Debug, Clone, PartialEq)]
44pub struct VItem {
45 pub vpoints: VPointComponentVec,
47 pub stroke_widths: ComponentVec<Width>,
49 pub stroke_rgbas: ComponentVec<Rgba>,
51 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
89pub const DEFAULT_STROKE_WIDTH: f32 = 0.02;
91
92impl VItem {
93 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 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 pub fn set_points(&mut self, vpoints: Vec<DVec3>) {
110 self.vpoints.0 = vpoints.into();
111 }
112 pub fn get_anchor(&self, idx: usize) -> Option<&DVec3> {
114 self.vpoints.get(idx * 2)
115 }
116 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 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 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
159impl 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
172impl 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#[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}