simplify_polyline/
point.rs

1use std::ops::{Add, Mul, Sub};
2
3use crate::ExtendedNumOps;
4
5/// The basic input type for constructing and simplifying a polyline. It can have any number of components, and will
6/// work with components that implement the [ExtendedNumOps] type. Dimensionality must be determined at compile time.
7///
8/// This also implements some basic math operations between points, like:
9/// - addition
10/// - subtraction
11/// - component-wise multiplication
12/// - scalar multiplication
13///
14/// ## Example
15/// ```
16/// use simplify_polyline::*;
17///
18/// let point2d: Point<2, i32> = Point { vec: [1, 1] };
19/// let another_point2d: Point<2, i32> = Point { vec: [2, 2] };
20///
21/// assert_eq!(point2d + another_point2d, Point { vec: [3, 3] });
22/// assert_eq!(point2d - another_point2d, Point { vec: [-1, -1] });
23/// assert_eq!(point2d * another_point2d, Point { vec: [2, 2] });
24/// assert_eq!(point2d * 7, Point { vec: [7, 7] });
25/// ```
26#[derive(Clone, Copy, PartialEq, Eq, Debug)]
27pub struct Point<const D: usize, T: ExtendedNumOps> {
28    /// The components of the point.
29    pub vec: [T; D],
30}
31
32impl<const D: usize, T: ExtendedNumOps> Point<D, T> {
33    /// Computes the squared distance between two points.
34    #[inline(always)]
35    pub fn sq_dist(&self, other: &Point<D, T>) -> T {
36        match D {
37            2 => {
38                let xdist = other.vec[0] - self.vec[0];
39                let ydist = other.vec[1] - self.vec[1];
40                (xdist * xdist) + (ydist * ydist)
41            }
42            3 => {
43                let xdist = other.vec[0] - self.vec[0];
44                let ydist = other.vec[1] - self.vec[1];
45                let zdist = other.vec[2] - self.vec[2];
46                (xdist * xdist) + (ydist * ydist) + (zdist * zdist)
47            }
48            4 => {
49                let xdist = other.vec[0] - self.vec[0];
50                let ydist = other.vec[1] - self.vec[1];
51                let zdist = other.vec[2] - self.vec[2];
52                let wdist = other.vec[3] - self.vec[3];
53                (xdist * xdist) + (ydist * ydist) + (zdist * zdist) + (wdist * wdist)
54            }
55            _ => self
56                .vec
57                .iter()
58                .zip(other.vec)
59                .map(|(a, b)| b - *a)
60                .reduce(|acc, v| acc + (v * v))
61                .unwrap_or_else(|| T::zero()),
62        }
63    }
64
65    /// Computes the squared distance between this point, and the origin.
66    #[inline(always)]
67    pub fn sq_dist_origin(&self) -> T {
68        match D {
69            2 => (self.vec[0] * self.vec[0]) + (self.vec[1] * self.vec[1]),
70            3 => {
71                (self.vec[0] * self.vec[0])
72                    + (self.vec[1] * self.vec[1])
73                    + (self.vec[2] * self.vec[2])
74            }
75            4 => {
76                (self.vec[0] * self.vec[0])
77                    + (self.vec[1] * self.vec[1])
78                    + (self.vec[2] * self.vec[2])
79                    + (self.vec[3] * self.vec[3])
80            }
81            _ => self.sq_dist(&Point {
82                vec: [T::zero(); D],
83            }),
84        }
85    }
86
87    /// Computes the sum of each value of the point.
88    #[inline(always)]
89    pub fn value_sum(&self) -> T {
90        match D {
91            2 => self.vec[0] + self.vec[1],
92            3 => self.vec[0] + self.vec[1] + self.vec[2],
93            4 => self.vec[0] + self.vec[1] + self.vec[2] + self.vec[3],
94            _ => self
95                .vec
96                .into_iter()
97                .reduce(|acc, v| acc + v)
98                .unwrap_or_else(|| T::zero()),
99        }
100    }
101
102    /// Checks if the point is the origin point (all values at zero).
103    #[inline(always)]
104    pub fn is_origin(&self) -> bool {
105        let zero = T::zero();
106        match D {
107            2 => self.vec[0] == zero && self.vec[1] == zero,
108            3 => self.vec[0] == zero && self.vec[1] == zero && self.vec[2] == zero,
109            4 => {
110                self.vec[0] == zero
111                    && self.vec[1] == zero
112                    && self.vec[2] == zero
113                    && self.vec[3] == zero
114            }
115            _ => self.vec.iter().all(|v| v == &zero),
116        }
117    }
118}
119
120macro_rules! impl_ref_op {
121    (impl $imp:ident, $method:ident for $t:ty, $u:ty) => {
122        impl<'a, const D: usize, T: ExtendedNumOps> $imp<$u> for &'a $t {
123            type Output = $t;
124
125            #[inline(always)]
126            fn $method(self, other: $u) -> Self::Output {
127                $imp::$method(*self, other)
128            }
129        }
130
131        impl<'b, const D: usize, T: ExtendedNumOps> $imp<&'b $u> for $t {
132            type Output = $t;
133
134            #[inline(always)]
135            fn $method(self, other: &'b $u) -> Self::Output {
136                $imp::$method(self, *other)
137            }
138        }
139
140        impl<'a, 'b, const D: usize, T: ExtendedNumOps> $imp<&'b $u> for &'a $t {
141            type Output = $t;
142
143            #[inline(always)]
144            fn $method(self, other: &'b $u) -> Self::Output {
145                $imp::$method(*self, *other)
146            }
147        }
148    };
149}
150
151impl<const D: usize, T: ExtendedNumOps> Add<Point<D, T>> for Point<D, T> {
152    type Output = Point<D, T>;
153
154    #[inline(always)]
155    fn add(self, rhs: Point<D, T>) -> Self::Output {
156        let mut new_values = [T::zero(); D];
157        match D {
158            2 => {
159                new_values[0] = self.vec[0] + rhs.vec[0];
160                new_values[1] = self.vec[1] + rhs.vec[1];
161            }
162            3 => {
163                new_values[0] = self.vec[0] + rhs.vec[0];
164                new_values[1] = self.vec[1] + rhs.vec[1];
165                new_values[2] = self.vec[2] + rhs.vec[2];
166            }
167            4 => {
168                new_values[0] = self.vec[0] + rhs.vec[0];
169                new_values[1] = self.vec[1] + rhs.vec[1];
170                new_values[2] = self.vec[2] + rhs.vec[2];
171                new_values[3] = self.vec[3] + rhs.vec[3];
172            }
173            _ => {
174                let mut i = 0usize;
175                while i < self.vec.len() {
176                    new_values[i] = self.vec[i] + rhs.vec[i];
177                    i += 1;
178                }
179            }
180        }
181        Point { vec: new_values }
182    }
183}
184impl_ref_op!(impl Add, add for Point<D, T>, Point<D, T>);
185
186impl<const D: usize, T: ExtendedNumOps> Sub<Point<D, T>> for Point<D, T> {
187    type Output = Point<D, T>;
188
189    #[inline(always)]
190    fn sub(self, rhs: Point<D, T>) -> Self::Output {
191        match D {
192            2 => {
193                let mut new_values = [T::zero(); D];
194                new_values[0] = self.vec[0] - rhs.vec[0];
195                new_values[1] = self.vec[1] - rhs.vec[1];
196                Point { vec: new_values }
197            }
198            _ => {
199                let mut i = 0usize;
200                let mut new_values = [T::zero(); D];
201                while i < self.vec.len() {
202                    new_values[i] = self.vec[i] - rhs.vec[i];
203                    i += 1;
204                }
205                Point { vec: new_values }
206            }
207        }
208    }
209}
210impl_ref_op!(impl Sub, sub for Point<D, T>, Point<D, T>);
211
212impl<const D: usize, T: ExtendedNumOps> Mul<Point<D, T>> for Point<D, T> {
213    type Output = Point<D, T>;
214
215    #[inline(always)]
216    fn mul(self, rhs: Point<D, T>) -> Self::Output {
217        let mut new_values = [T::zero(); D];
218        match D {
219            2 => {
220                new_values[0] = self.vec[0] * rhs.vec[0];
221                new_values[1] = self.vec[1] * rhs.vec[1];
222            }
223            3 => {
224                new_values[0] = self.vec[0] * rhs.vec[0];
225                new_values[1] = self.vec[1] * rhs.vec[1];
226                new_values[2] = self.vec[2] * rhs.vec[2];
227            }
228            4 => {
229                new_values[0] = self.vec[0] * rhs.vec[0];
230                new_values[1] = self.vec[1] * rhs.vec[1];
231                new_values[2] = self.vec[2] * rhs.vec[2];
232                new_values[3] = self.vec[3] * rhs.vec[3];
233            }
234            _ => {
235                let mut i = 0usize;
236                while i < self.vec.len() {
237                    new_values[i] = self.vec[i] * rhs.vec[i];
238                    i += 1;
239                }
240            }
241        }
242        Point { vec: new_values }
243    }
244}
245impl_ref_op!(impl Mul, mul for Point<D, T>, Point<D, T>);
246
247impl<const D: usize, T: ExtendedNumOps> Mul<T> for Point<D, T> {
248    type Output = Point<D, T>;
249
250    #[inline(always)]
251    fn mul(self, rhs: T) -> Self::Output {
252        let mut new_values = [T::zero(); D];
253        match D {
254            2 => {
255                new_values[0] = self.vec[0] * rhs;
256                new_values[1] = self.vec[1] * rhs;
257            }
258            3 => {
259                new_values[0] = self.vec[0] * rhs;
260                new_values[1] = self.vec[1] * rhs;
261                new_values[2] = self.vec[2] * rhs;
262            }
263            4 => {
264                new_values[0] = self.vec[0] * rhs;
265                new_values[1] = self.vec[1] * rhs;
266                new_values[2] = self.vec[2] * rhs;
267                new_values[3] = self.vec[3] * rhs;
268            }
269            _ => {
270                let mut i = 0usize;
271                let mut new_values = [T::zero(); D];
272                while i < self.vec.len() {
273                    new_values[i] = self.vec[i] * rhs;
274                    i += 1;
275                }
276            }
277        }
278        Point { vec: new_values }
279    }
280}
281impl_ref_op!(impl Mul, mul for Point<D, T>, T);
282
283/// Creates a single [Point], where the dimension is determined from the number of values specified, and the values all
284/// must implement [ExtendedNumOps] and be of the same type.
285///
286/// ## Example
287/// ```
288/// use simplify_polyline::*;
289///
290/// // 2d point
291/// let point2d: Point<2, i32> = point!(1, 2);
292/// assert_eq!(point2d.vec.len(), 2);
293///
294/// // 8d point
295/// let point8d: Point<8, i32> = point!(1, 2, 3, 4, 5, 6, 7, 8);
296/// assert_eq!(point8d.vec.len(), 8);
297/// ```
298#[macro_export]
299macro_rules! point {
300    ($($values:expr),+) => {
301        Point { vec: [$($values),+] }
302    };
303}
304
305/// Creates a [Point] array, where the dimension is determined by the length of the tuples in the array, and the values
306/// all must implement [ExtendedNumOps] and be of the same type. Point tuples must all be the same length.
307///
308/// ## Example
309/// ```
310/// use simplify_polyline::*;
311///
312/// // 2d array
313/// let points2d: [Point<2, f64>; 3] = points![(1.0, 1.0), (2.0, 2.0), (3.0, 3.0)];
314/// assert_eq!(points2d.len(), 3);
315/// assert_eq!(points2d[0].vec.len(), 2);
316///
317/// // 4d array
318/// let points4d: [Point<4, f64>; 2] = points![(1.0, 2.0, 3.0, 4.0), (5.0, 6.0, 7.0, 8.0)];
319/// assert_eq!(points4d.len(), 2);
320/// assert_eq!(points4d[0].vec.len(), 4);
321/// ```
322#[macro_export]
323macro_rules! points {
324    ($(($($values:expr),+)),*) => {
325        [$(Point { vec: [$($values),+] }),*]
326    };
327}