stroke/
point_generic.rs

1use core::iter::{IntoIterator, Sum};
2use core::slice;
3
4use super::*;
5//use num_traits::{Float, FromPrimitive};
6use super::Point;
7
8/// Point with dimensions of constant generic size N and of generic type T
9/// (Implemented as Newtype Pattern on an array
10/// see book or https://www.worthe-it.co.za/blog/2020-10-31-newtype-pattern-in-rust.html)
11/// This type only interacts with the library through
12/// the point trait, so you are free to use your own
13/// Point/Coord/Vec structures instead by implementing the (small) trait
14#[derive(Debug, Copy, Clone)]
15pub struct PointN<T, const N: usize>([T; N]);
16
17impl<T, const N: usize> PointN<T, N> {
18    pub fn new(array: [T; N]) -> Self {
19        PointN(array)
20    }
21}
22
23/// Initialize with the Default value for the underlying type
24impl<T: Default + Copy, const N: usize> Default for PointN<T, N> {
25    fn default() -> Self {
26        PointN([T::default(); N])
27    }
28}
29
30impl<T, const N: usize> PartialEq for PointN<T, N>
31where
32    T: PartialOrd,
33{
34    fn eq(&self, other: &Self) -> bool {
35        for i in 0..N {
36            if self.0[i] != other.0[i] {
37                return false;
38            }
39        }
40        true
41    }
42}
43
44impl<T, const N: usize> Add for PointN<T, N>
45where
46    T: Add<Output = T> + Clone + Copy,
47{
48    type Output = Self;
49
50    fn add(self, other: PointN<T, N>) -> PointN<T, N> {
51        let mut res = self;
52        for i in 0..N {
53            res.0[i] = self.0[i] + other.0[i];
54        }
55        res
56    }
57}
58
59/// This is not required by the Point trait or library but
60/// convenient if you want to use the type externally
61impl<T, const N: usize> Add<T> for PointN<T, N>
62where
63    T: Add<Output = T> + Clone + Copy,
64{
65    type Output = Self;
66
67    fn add(self, _rhs: T) -> PointN<T, N> {
68        let mut res = self;
69        for i in 0..N {
70            res.0[i] = self.0[i] + _rhs;
71        }
72        res
73    }
74}
75
76impl<T, const N: usize> Sub for PointN<T, N>
77where
78    T: Sub<Output = T> + Clone + Copy,
79{
80    type Output = Self;
81
82    fn sub(self, other: PointN<T, N>) -> PointN<T, N> {
83        let mut res = self;
84        for i in 0..N {
85            res.0[i] = self.0[i] - other.0[i];
86        }
87        res
88    }
89}
90
91/// This is not required by the Point trait or library but
92/// convenient if you want to use the type externally
93impl<T, const N: usize> Sub<T> for PointN<T, N>
94where
95    T: Sub<Output = T> + Clone + Copy,
96{
97    type Output = Self;
98
99    fn sub(self, _rhs: T) -> PointN<T, N> {
100        let mut res = self;
101        for i in 0..N {
102            res.0[i] = self.0[i] - _rhs;
103        }
104        res
105    }
106}
107
108impl<T, const N: usize, U> Mul<U> for PointN<T, N>
109where
110    // The mulitplication is done by mulitpling T * U => T, this
111    // trait bound for T will specify this requirement as the mul operator is
112    // translated to using the first operand as self and the second as rhs.
113    T: Mul<U, Output = T> + Clone + Copy, //+ SizedFloat,
114    U: Clone + Copy,
115{
116    type Output = PointN<T, N>;
117
118    fn mul(self, _rhs: U) -> PointN<T, N> {
119        let mut res = self;
120        for i in 0..res.0.len() {
121            res.0[i] = res.0[i] * _rhs;
122        }
123        res
124    }
125}
126
127impl<T, const N: usize> IntoIterator for PointN<T, N> {
128    type Item = T;
129    type IntoIter = core::array::IntoIter<Self::Item, N>;
130
131    fn into_iter(self) -> Self::IntoIter {
132        IntoIterator::into_iter(self.0)
133    }
134}
135
136impl<'a, T, const N: usize> IntoIterator for &'a mut PointN<T, N> {
137    type Item = &'a mut T;
138    type IntoIter = slice::IterMut<'a, T>;
139
140    fn into_iter(self) -> slice::IterMut<'a, T> {
141        self.0.iter_mut()
142    }
143}
144
145impl<T, const N: usize> Point for PointN<T, N>
146where
147    T: Float
148        + Copy
149        + Default
150        + Add<T, Output = T>
151        + Add<NativeFloat, Output = T>
152        + Sub<T, Output = T>
153        + Sub<NativeFloat, Output = T>
154        + Mul<T, Output = T>
155        + Mul<NativeFloat, Output = T>
156        + Sum<NativeFloat>
157        + From<NativeFloat>
158        + Into<NativeFloat>,
159{
160    type Scalar = NativeFloat;
161    const DIM: usize = { N };
162
163    fn axis(&self, index: usize) -> Self::Scalar {
164        assert!(index <= N);
165        self.0[index].into()
166    }
167
168    fn squared_length(&self) -> Self::Scalar {
169        let mut sqr_dist = 0.0;
170        for i in 0..N {
171            sqr_dist += (self.0[i] * self.0[i]).into();
172        }
173        sqr_dist
174    }
175}