1pub mod geometry;
13pub mod svg;
15pub mod text;
17pub mod typst;
19
20use color::{AlphaColor, Srgb, palette::css};
21use glam::{DVec3, Vec4, vec4};
22use ranim_core::anchor::Aabb;
23use ranim_core::core_item::CoreItem;
24use ranim_core::core_item::vitem::Basis2d;
25use ranim_core::{Extract, color, glam};
26
27use ranim_core::{
28 components::{PointVec, VecResizeTrait, rgba::Rgba, vpoint::VPointVec, width::Width},
29 prelude::{Alignable, Empty, FillColor, Opacity, Partial, StrokeWidth},
30 traits::{PointsFunc, RotateTransform, ScaleTransform, ShiftTransform, StrokeColor},
31};
32
33#[derive(Debug, Clone, PartialEq, ranim_macros::Interpolatable)]
51pub struct VItem {
52 pub basis: Basis2d,
56 pub vpoints: VPointVec,
58 pub stroke_widths: PointVec<Width>,
60 pub stroke_rgbas: PointVec<Rgba>,
62 pub fill_rgbas: PointVec<Rgba>,
64}
65
66impl PointsFunc for VItem {
67 fn apply_points_func(&mut self, f: impl Fn(&mut [DVec3])) -> &mut Self {
68 self.vpoints.apply_points_func(f);
69 self
70 }
71}
72
73impl Aabb for VItem {
74 fn aabb(&self) -> [DVec3; 2] {
75 self.vpoints.aabb()
76 }
77}
78
79impl ShiftTransform for VItem {
80 fn shift(&mut self, shift: DVec3) -> &mut Self {
81 self.vpoints.shift(shift);
82 self
83 }
84}
85
86impl RotateTransform for VItem {
87 fn rotate_on_axis(&mut self, axis: DVec3, angle: f64) -> &mut Self {
88 self.vpoints.rotate_on_axis(axis, angle);
89 self.basis.rotate_on_axis(axis, angle);
90 self
91 }
92}
93
94impl ScaleTransform for VItem {
95 fn scale(&mut self, scale: DVec3) -> &mut Self {
96 self.vpoints.scale(scale);
97 self
98 }
99}
100
101pub use ranim_core::core_item::vitem::DEFAULT_STROKE_WIDTH;
110
111impl VItem {
112 pub fn close(&mut self) -> &mut Self {
114 if self.vpoints.last() != self.vpoints.first() && !self.vpoints.is_empty() {
115 let start = self.vpoints[0];
116 let end = self.vpoints[self.vpoints.len() - 1];
117 self.extend_vpoints(&[(start + end) / 2.0, start]);
118 }
119 self
120 }
121 pub fn shrink(&mut self) -> &mut Self {
123 let bb = self.aabb();
124 self.vpoints.0 = vec![bb[1]; self.vpoints.len()];
125 self
126 }
127 pub fn set_points(&mut self, vpoints: Vec<DVec3>) {
129 self.vpoints.0 = vpoints;
130 }
131 pub fn get_anchor(&self, idx: usize) -> Option<&DVec3> {
133 self.vpoints.get(idx * 2)
134 }
135 pub fn with_basis(mut self, basis: Basis2d) -> Self {
137 self.basis = basis;
138 self
139 }
140 pub fn set_proj(&mut self, basis: Basis2d) {
142 self.basis = basis;
143 }
144 pub fn from_vpoints(vpoints: Vec<DVec3>) -> Self {
146 let stroke_widths = vec![DEFAULT_STROKE_WIDTH.into(); vpoints.len().div_ceil(2)];
147 let stroke_rgbas = vec![vec4(1.0, 1.0, 1.0, 1.0).into(); vpoints.len().div_ceil(2)];
148 let fill_rgbas = vec![vec4(0.0, 0.0, 0.0, 0.0).into(); vpoints.len().div_ceil(2)];
149 Self {
150 basis: Basis2d::default(),
151 vpoints: VPointVec(vpoints),
152 stroke_rgbas: stroke_rgbas.into(),
153 stroke_widths: stroke_widths.into(),
154 fill_rgbas: fill_rgbas.into(),
155 }
156 }
157 pub fn extend_vpoints(&mut self, vpoints: &[DVec3]) {
159 self.vpoints.extend(vpoints.to_vec());
160
161 let len = self.vpoints.len();
162 self.fill_rgbas.resize_with_last(len.div_ceil(2));
163 self.stroke_rgbas.resize_with_last(len.div_ceil(2));
164 self.stroke_widths.resize_with_last(len.div_ceil(2));
165 }
166
167 pub(crate) fn get_render_points(&self) -> Vec<Vec4> {
168 self.vpoints
169 .iter()
170 .zip(self.vpoints.get_closepath_flags())
171 .map(|(p, f)| p.as_vec3().extend(f.into()))
172 .collect()
173 }
174 pub fn put_start_and_end_on(&mut self, start: DVec3, end: DVec3) -> &mut Self {
176 self.vpoints.put_start_and_end_on(start, end);
177 self
178 }
179}
180
181impl From<VItem> for ranim_core::core_item::vitem::VItem {
182 fn from(value: VItem) -> Self {
183 Self {
184 origin: value.vpoints.first().unwrap().as_vec3(),
185 basis: value.basis,
186 points: value.get_render_points(),
187 fill_rgbas: value.fill_rgbas.iter().cloned().collect(),
188 stroke_rgbas: value.stroke_rgbas.iter().cloned().collect(),
189 stroke_widths: value.stroke_widths.iter().cloned().collect(),
190 }
191 }
192}
193
194impl Extract for VItem {
195 type Target = CoreItem;
196 fn extract_into(&self, buf: &mut Vec<Self::Target>) {
197 ranim_core::core_item::vitem::VItem::from(self.clone()).extract_into(buf);
198 }
199}
200
201impl Alignable for VItem {
203 fn is_aligned(&self, other: &Self) -> bool {
204 self.vpoints.is_aligned(&other.vpoints)
205 && self.stroke_widths.is_aligned(&other.stroke_widths)
206 && self.stroke_rgbas.is_aligned(&other.stroke_rgbas)
207 && self.fill_rgbas.is_aligned(&other.fill_rgbas)
208 }
209 fn align_with(&mut self, other: &mut Self) {
210 self.vpoints.align_with(&mut other.vpoints);
211 let len = self.vpoints.len().div_ceil(2);
212 self.stroke_rgbas.resize_preserving_order(len);
213 other.stroke_rgbas.resize_preserving_order(len);
214 self.stroke_widths.resize_preserving_order(len);
215 other.stroke_widths.resize_preserving_order(len);
216 self.fill_rgbas.resize_preserving_order(len);
217 other.fill_rgbas.resize_preserving_order(len);
218 }
219}
220
221impl Opacity for VItem {
222 fn set_opacity(&mut self, opacity: f32) -> &mut Self {
223 self.stroke_rgbas.set_opacity(opacity);
224 self.fill_rgbas.set_opacity(opacity);
225 self
226 }
227}
228
229impl Partial for VItem {
230 fn get_partial(&self, range: std::ops::Range<f64>) -> Self {
231 let vpoints = self.vpoints.get_partial(range.clone());
232 let stroke_rgbas = self.stroke_rgbas.get_partial(range.clone());
233 let stroke_widths = self.stroke_widths.get_partial(range.clone());
234 let fill_rgbas = self.fill_rgbas.get_partial(range.clone());
235 Self {
236 basis: self.basis,
237 vpoints,
238 stroke_widths,
239 stroke_rgbas,
240 fill_rgbas,
241 }
242 }
243 fn get_partial_closed(&self, range: std::ops::Range<f64>) -> Self {
244 let mut partial = self.get_partial(range);
245 partial.close();
246 partial
247 }
248}
249
250impl Empty for VItem {
251 fn empty() -> Self {
252 Self {
253 basis: Basis2d::default(),
254 vpoints: VPointVec(vec![DVec3::ZERO; 3]),
255 stroke_widths: vec![0.0.into(); 2].into(),
256 stroke_rgbas: vec![Vec4::ZERO.into(); 2].into(),
257 fill_rgbas: vec![Vec4::ZERO.into(); 2].into(),
258 }
259 }
260}
261
262impl FillColor for VItem {
263 fn fill_color(&self) -> AlphaColor<Srgb> {
264 self.fill_rgbas
265 .first()
266 .map(|&rgba| rgba.into())
267 .unwrap_or(css::WHITE)
268 }
269 fn set_fill_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
270 self.fill_rgbas
271 .iter_mut()
272 .for_each(|rgba| *rgba = color.into());
273 self
274 }
275 fn set_fill_opacity(&mut self, opacity: f32) -> &mut Self {
276 self.fill_rgbas.set_opacity(opacity);
277 self
278 }
279}
280
281impl StrokeColor for VItem {
282 fn stroke_color(&self) -> AlphaColor<Srgb> {
283 self.stroke_rgbas
284 .first()
285 .map(|&rgba| rgba.into())
286 .unwrap_or(css::WHITE)
287 }
288 fn set_stroke_color(&mut self, color: AlphaColor<Srgb>) -> &mut Self {
289 self.stroke_rgbas
290 .iter_mut()
291 .for_each(|rgba| *rgba = color.into());
292 self
293 }
294 fn set_stroke_opacity(&mut self, opacity: f32) -> &mut Self {
295 self.stroke_rgbas.set_opacity(opacity);
296 self
297 }
298}
299
300impl StrokeWidth for VItem {
301 fn stroke_width(&self) -> f32 {
302 self.stroke_widths[0].0
303 }
304 fn apply_stroke_func(&mut self, f: impl for<'a> Fn(&'a mut [Width])) -> &mut Self {
305 f(self.stroke_widths.as_mut());
306 self
307 }
308}