1use std::fmt::Debug;
2
3use derive_more::{Deref, DerefMut, From};
4
5use crate::{
6 prelude::{Alignable, Interpolatable},
7 utils::{math::interpolate_usize, resize_preserving_order},
8};
9
10#[derive(Debug, PartialEq, Eq, Deref, DerefMut, From)]
12pub struct PointVec<T>(Vec<T>);
13
14impl<T: Interpolatable> Interpolatable for PointVec<T> {
15 fn lerp(&self, target: &Self, t: f64) -> Self {
16 Self(self.0.lerp(&target.0, t))
17 }
18}
19
20impl<T: Clone> Clone for PointVec<T> {
21 fn clone(&self) -> Self {
22 Self(self.0.clone())
23 }
24}
25
26impl<T: Component + Interpolatable> PointVec<T> {
27 pub fn get_partial(&self, range: std::ops::Range<f64>) -> Self {
32 let max_idx = self.len() - 2;
33
34 let (start_index, start_residue) = interpolate_usize(0, max_idx, range.start);
35 let (end_index, end_residue) = interpolate_usize(0, max_idx, range.end);
36 if start_index == end_index {
38 let start_v = self
39 .get(start_index)
40 .unwrap()
41 .lerp(self.get(start_index + 1).unwrap(), start_residue);
42 let end_v = self
43 .get(end_index)
44 .unwrap()
45 .lerp(self.get(end_index + 1).unwrap(), end_residue);
46 vec![start_v, end_v]
47 } else {
48 let start_v = self
49 .get(start_index)
50 .unwrap()
51 .lerp(self.get(start_index + 1).unwrap(), start_residue);
52 let end_v = self
53 .get(end_index)
54 .unwrap()
55 .lerp(self.get(end_index + 1).unwrap(), end_residue);
56
57 let mut partial = Vec::with_capacity(end_index - start_index + 1 + 2);
58 partial.push(start_v);
59 partial.extend_from_slice(self.get(start_index + 1..=end_index).unwrap());
60 partial.push(end_v);
61 partial
62 }
63 .into()
64 }
65}
66
67pub mod point;
69pub mod rgba;
71pub mod vpoint;
73pub mod width;
75
76pub trait Component: Debug + Default + Clone + PartialEq {}
78
79impl<T: Debug + Default + Clone + PartialEq> Component for T {}
80
81pub trait VecResizeTrait {
83 fn resize_with_default(&mut self, new_len: usize);
85 fn resize_with_last(&mut self, new_len: usize);
87 fn resize_preserving_order(&mut self, new_len: usize);
89}
90
91impl<T: Component> VecResizeTrait for Vec<T> {
92 fn resize_with_default(&mut self, new_len: usize) {
94 self.resize(new_len, Default::default());
95 }
96 fn resize_with_last(&mut self, new_len: usize) {
98 let last = self.last().cloned().unwrap_or_default();
99 self.resize(new_len, last);
100 }
101 fn resize_preserving_order(&mut self, new_len: usize) {
103 *self = resize_preserving_order(self, new_len);
104 }
105}
106
107impl<T: Component> Alignable for PointVec<T> {
108 fn is_aligned(&self, other: &Self) -> bool {
109 self.len() == other.len()
110 }
111 fn align_with(&mut self, other: &mut Self) {
112 if self.len() == other.len() {
113 return;
114 }
115 if self.len() < other.len() {
116 self.resize_with_last(other.len());
117 } else {
118 other.resize_with_last(self.len());
119 }
120 }
121}
122
123#[cfg(test)]
125mod test {
126 use glam::{DVec3, dvec3};
127
128 use crate::{
129 anchor::{Aabb, AabbPoint, Locate},
130 components::vpoint::VPointVec,
131 traits::{ScaleTransform, ShiftTransformExt},
132 };
133
134 #[test]
135 fn test_bounding_box() {
136 let points: VPointVec = VPointVec(vec![
139 dvec3(-100.0, -100.0, 0.0),
140 dvec3(-100.0, 100.0, 0.0),
141 dvec3(100.0, 100.0, 0.0),
142 dvec3(100.0, 100.0, 0.0),
143 dvec3(100.0, -200.0, 0.0),
144 ]);
145 assert_eq!(
146 points.aabb(),
147 [dvec3(-100.0, -200.0, 0.0), dvec3(100.0, 100.0, 0.0)]
148 );
149 assert_eq!(
150 dvec3(0.0, -50.0, 0.0),
151 AabbPoint(dvec3(0.0, 0.0, 0.0)).locate(&points)
152 );
153 assert_eq!(
154 dvec3(-100.0, -200.0, 0.0),
155 AabbPoint(dvec3(-1.0, -1.0, 0.0)).locate(&points)
156 );
157 assert_eq!(
158 dvec3(-100.0, 100.0, 0.0),
159 AabbPoint(dvec3(-1.0, 1.0, 0.0)).locate(&points)
160 );
161 assert_eq!(
162 dvec3(100.0, -200.0, 0.0),
163 AabbPoint(dvec3(1.0, -1.0, 0.0)).locate(&points)
164 );
165 assert_eq!(
166 dvec3(100.0, 100.0, 0.0),
167 AabbPoint(dvec3(1.0, 1.0, 0.0)).locate(&points)
168 );
169 }
170
171 #[test]
172 fn test_transform() {
173 let square = vec![
174 dvec3(-1.0, -1.0, 0.0),
175 dvec3(2.0, -2.0, 0.0),
176 dvec3(0.5, 1.0, 0.0),
177 dvec3(-3.0, 3.0, 0.0),
178 dvec3(4.0, 4.0, 0.0),
179 ];
180 let mut scale_origin = VPointVec(square.clone());
181 assert_eq!(
183 AabbPoint(DVec3::ZERO).locate(&scale_origin),
184 dvec3(1.5, 1.375, 0.0)
185 );
186 scale_origin.with_origin(AabbPoint::CENTER, |x| {
187 x.scale(DVec3::splat(3.0));
188 });
189
190 let ans = VPointVec(vec![
191 dvec3(-6.0, -5.75, 0.0),
192 dvec3(3.0, -8.75, 0.0),
193 dvec3(-1.5, 0.25, 0.0),
194 dvec3(-12.0, 6.25, 0.0),
195 dvec3(9.0, 9.25, 0.0),
196 ]);
197 assert_eq!(scale_origin, ans);
198 }
199}