1use std::fmt::Debug;
2
3use derive_more::{AsMut, AsRef, Deref, DerefMut};
4
5use crate::{
6 prelude::{Alignable, Interpolatable},
7 utils::{math::interpolate_usize, resize_preserving_order},
8};
9
10pub mod point;
12pub mod rgba;
14pub mod vpoint;
16pub mod width;
18
19pub trait Component: Debug + Default + Clone + PartialEq {}
21
22impl<T: Debug + Default + Clone + PartialEq> Component for T {}
23
24#[derive(Default, Debug, Clone, PartialEq, Deref, DerefMut, AsMut, AsRef)]
26#[as_ref(forward)]
27#[as_mut(forward)]
28pub struct ComponentVec<T: Component>(pub(crate) Vec<T>);
29
30impl<T: Component + PointWise + Interpolatable> ComponentVec<T> {
33 pub fn get_partial(&self, range: std::ops::Range<f64>) -> Self {
37 let max_idx = self.len() - 2;
38
39 let (start_index, start_residue) = interpolate_usize(0, max_idx, range.start);
40 let (end_index, end_residue) = interpolate_usize(0, max_idx, range.end);
41 if start_index == end_index {
43 let start_v = self
44 .get(start_index)
45 .unwrap()
46 .lerp(self.get(start_index + 1).unwrap(), start_residue);
47 let end_v = self
48 .get(end_index)
49 .unwrap()
50 .lerp(self.get(end_index + 1).unwrap(), end_residue);
51 vec![start_v, end_v]
52 } else {
53 let start_v = self
54 .get(start_index)
55 .unwrap()
56 .lerp(self.get(start_index + 1).unwrap(), start_residue);
57 let end_v = self
58 .get(end_index)
59 .unwrap()
60 .lerp(self.get(end_index + 1).unwrap(), end_residue);
61
62 let mut partial = Vec::with_capacity(end_index - start_index + 1 + 2);
63 partial.push(start_v);
64 partial.extend_from_slice(self.get(start_index + 1..=end_index).unwrap());
65 partial.push(end_v);
66 partial
67 }
68 .into()
69 }
70}
71
72impl<T: Component> Alignable for ComponentVec<T> {
73 fn is_aligned(&self, other: &Self) -> bool {
74 self.len() == other.len()
75 }
76 fn align_with(&mut self, other: &mut Self) {
77 if self.len() == other.len() {
78 return;
79 }
80 if self.len() < other.len() {
81 self.resize_with_last(other.len());
82 } else {
83 other.resize_with_last(self.len());
84 }
85 }
86}
87
88impl<T: Component + Interpolatable> Interpolatable for ComponentVec<T> {
89 fn lerp(&self, target: &Self, t: f64) -> Self {
90 Self(
91 self.iter()
92 .zip(target.iter())
93 .map(|(a, b)| a.lerp(b, t))
94 .collect::<Vec<_>>(),
95 )
96 }
97}
98
99impl<T: Component, I: IntoIterator<Item = impl Into<T>>> From<I> for ComponentVec<T> {
100 fn from(v: I) -> Self {
101 Self(v.into_iter().map(Into::into).collect())
102 }
103}
104
105impl<T: Component> ComponentVec<T> {
106 pub fn extend_from_vec(&mut self, vec: Vec<T>) {
108 self.0.extend(vec);
109 }
110 pub fn resize_with_default(&mut self, new_len: usize) {
112 self.0.resize(new_len, Default::default());
113 }
114 pub fn resize_with_last(&mut self, new_len: usize) {
116 let last = self.last().cloned().unwrap_or_default();
117 self.0.resize(new_len, last);
118 }
119 pub fn resize_preserving_order(&mut self, new_len: usize) {
121 self.0 = resize_preserving_order(&self.0, new_len);
122 }
123 pub fn set_all(&mut self, value: impl Into<T>) {
125 let value = value.into();
126 self.iter_mut().for_each(|x| *x = value.clone());
127 }
128}
129
130pub trait PointWise {}
132
133#[cfg(test)]
135mod test {
136 use glam::{DVec3, IVec3, dvec3, ivec3};
137
138 use crate::{
139 components::vpoint::VPointComponentVec,
140 traits::{BoundingBox, Scale},
141 };
142
143 #[test]
144 fn test_bounding_box() {
145 let points: VPointComponentVec = VPointComponentVec(
146 vec![
147 dvec3(-100.0, -100.0, 0.0),
148 dvec3(-100.0, 100.0, 0.0),
149 dvec3(100.0, 100.0, 0.0),
150 dvec3(100.0, -200.0, 0.0),
151 ]
152 .into(),
153 );
154 assert_eq!(
155 points.get_bounding_box(),
156 [
157 dvec3(-100.0, -200.0, 0.0),
158 dvec3(0.0, -50.0, 0.0),
159 dvec3(100.0, 100.0, 0.0)
160 ]
161 );
162 assert_eq!(
163 dvec3(0.0, -50.0, 0.0),
164 points.get_bounding_box_point(ivec3(0, 0, 0))
165 );
166 assert_eq!(
167 dvec3(-100.0, -200.0, 0.0),
168 points.get_bounding_box_point(ivec3(-1, -1, 0))
169 );
170 assert_eq!(
171 dvec3(-100.0, 100.0, 0.0),
172 points.get_bounding_box_point(ivec3(-1, 1, 0))
173 );
174 assert_eq!(
175 dvec3(100.0, -200.0, 0.0),
176 points.get_bounding_box_point(ivec3(1, -1, 0))
177 );
178 assert_eq!(
179 dvec3(100.0, 100.0, 0.0),
180 points.get_bounding_box_point(ivec3(1, 1, 0))
181 );
182 }
183
184 #[test]
185 fn test_transform() {
186 let square = vec![
187 dvec3(-1.0, -1.0, 0.0),
188 dvec3(2.0, -2.0, 0.0),
189 dvec3(0.5, 1.0, 0.0),
190 dvec3(-3.0, 3.0, 0.0),
191 dvec3(4.0, 4.0, 0.0),
192 ];
193 let mut scale_origin = VPointComponentVec(square.clone().into());
194 assert_eq!(
195 scale_origin.get_bounding_box_point(IVec3::ZERO),
196 dvec3(0.5, 1.0, 0.0)
197 );
198 scale_origin.scale(DVec3::splat(3.0));
199
200 let ans = VPointComponentVec(
201 vec![
202 dvec3(-4.0, -5.0, 0.0),
203 dvec3(5.0, -8.0, 0.0),
204 dvec3(0.5, 1.0, 0.0),
205 dvec3(-10.0, 7.0, 0.0),
206 dvec3(11.0, 10.0, 0.0),
207 ]
208 .into(),
209 );
210 assert_eq!(scale_origin, ans);
211 }
212}