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