fj_math/
point.rs

1use std::{fmt, ops};
2
3use super::{
4    coordinates::{Uv, Xyz, T},
5    Scalar, Vector,
6};
7
8/// An n-dimensional point
9///
10/// The dimensionality of the point is defined by the const generic `D`
11/// parameter.
12#[derive(Clone, Copy, Default, Eq, PartialEq, Hash, Ord, PartialOrd)]
13#[repr(C)]
14pub struct Point<const D: usize> {
15    /// The coordinates of the point
16    pub coords: Vector<D>,
17}
18
19impl<const D: usize> Point<D> {
20    /// Construct a `Point` at the origin of the coordinate system
21    pub fn origin() -> Self {
22        nalgebra::Point::<_, D>::origin().into()
23    }
24
25    /// Construct a `Point` from an array
26    pub fn from_array(array: [f64; D]) -> Self {
27        Self {
28            coords: array.map(Scalar::from_f64).into(),
29        }
30    }
31
32    /// Construct a `Point` from an nalgebra vector
33    pub fn from_na(point: nalgebra::Point<f64, D>) -> Self {
34        Self {
35            coords: point.coords.into(),
36        }
37    }
38
39    /// Convert the point into an nalgebra point
40    pub fn to_na(self) -> nalgebra::Point<f64, D> {
41        nalgebra::Point {
42            coords: self.coords.into(),
43        }
44    }
45
46    /// Convert to a 1-dimensional point
47    pub fn to_t(self) -> Point<1> {
48        Point {
49            coords: self.coords.to_t(),
50        }
51    }
52
53    /// Convert to a 3-dimensional point
54    ///
55    /// See [`Vector::to_xyz`] for details. This method follows the same rules.
56    pub fn to_xyz(self) -> Point<3> {
57        Point {
58            coords: self.coords.to_xyz(),
59        }
60    }
61
62    /// Gives the distance between two points.
63    pub fn distance_to(&self, other: &Self) -> Scalar {
64        (self.coords - other.coords).magnitude()
65    }
66}
67
68impl ops::Deref for Point<1> {
69    type Target = T;
70
71    fn deref(&self) -> &Self::Target {
72        self.coords.deref()
73    }
74}
75
76impl ops::Deref for Point<2> {
77    type Target = Uv;
78
79    fn deref(&self) -> &Self::Target {
80        self.coords.deref()
81    }
82}
83
84impl ops::Deref for Point<3> {
85    type Target = Xyz;
86
87    fn deref(&self) -> &Self::Target {
88        self.coords.deref()
89    }
90}
91
92impl ops::DerefMut for Point<1> {
93    fn deref_mut(&mut self) -> &mut Self::Target {
94        self.coords.deref_mut()
95    }
96}
97
98impl ops::DerefMut for Point<2> {
99    fn deref_mut(&mut self) -> &mut Self::Target {
100        self.coords.deref_mut()
101    }
102}
103
104impl ops::DerefMut for Point<3> {
105    fn deref_mut(&mut self) -> &mut Self::Target {
106        self.coords.deref_mut()
107    }
108}
109
110impl<const D: usize> From<[Scalar; D]> for Point<D> {
111    fn from(array: [Scalar; D]) -> Self {
112        Self {
113            coords: array.into(),
114        }
115    }
116}
117
118impl<const D: usize> From<[f64; D]> for Point<D> {
119    fn from(array: [f64; D]) -> Self {
120        Self::from_array(array)
121    }
122}
123
124impl<const D: usize> From<nalgebra::Point<f64, D>> for Point<D> {
125    fn from(point: nalgebra::Point<f64, D>) -> Self {
126        Self::from_na(point)
127    }
128}
129
130impl<const D: usize> From<Point<D>> for [f32; D] {
131    fn from(point: Point<D>) -> Self {
132        point.coords.into()
133    }
134}
135
136impl<const D: usize> From<Point<D>> for [f64; D] {
137    fn from(point: Point<D>) -> Self {
138        point.coords.into()
139    }
140}
141
142impl<const D: usize> From<Point<D>> for [Scalar; D] {
143    fn from(point: Point<D>) -> Self {
144        point.coords.into()
145    }
146}
147
148impl<const D: usize> ops::Neg for Point<D> {
149    type Output = Self;
150
151    fn neg(self) -> Self::Output {
152        self.to_na().neg().into()
153    }
154}
155
156impl<V, const D: usize> ops::Add<V> for Point<D>
157where
158    V: Into<Vector<D>>,
159{
160    type Output = Self;
161
162    fn add(self, rhs: V) -> Self::Output {
163        self.to_na().add(rhs.into().to_na()).into()
164    }
165}
166
167impl<V, const D: usize> ops::AddAssign<V> for Point<D>
168where
169    V: Into<Vector<D>>,
170{
171    fn add_assign(&mut self, rhs: V) {
172        *self = *self + rhs;
173    }
174}
175
176impl<V, const D: usize> ops::Sub<V> for Point<D>
177where
178    V: Into<Vector<D>>,
179{
180    type Output = Self;
181
182    fn sub(self, rhs: V) -> Self::Output {
183        self.to_na().sub(rhs.into().to_na()).into()
184    }
185}
186
187impl<const D: usize> ops::Sub<Self> for Point<D> {
188    type Output = Vector<D>;
189
190    fn sub(self, rhs: Self) -> Self::Output {
191        self.to_na().sub(rhs.to_na()).into()
192    }
193}
194
195impl<const D: usize> ops::Sub<Point<D>> for &Point<D> {
196    type Output = Vector<D>;
197
198    fn sub(self, rhs: Point<D>) -> Self::Output {
199        self.to_na().sub(rhs.to_na()).into()
200    }
201}
202
203impl<const D: usize> ops::Mul<f64> for Point<D> {
204    type Output = Self;
205
206    fn mul(self, rhs: f64) -> Self::Output {
207        self.to_na().mul(rhs).into()
208    }
209}
210
211impl<const D: usize> fmt::Debug for Point<D> {
212    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
213        self.coords.fmt(f)
214    }
215}
216
217impl<const D: usize> approx::AbsDiffEq for Point<D> {
218    type Epsilon = <Vector<D> as approx::AbsDiffEq>::Epsilon;
219
220    fn default_epsilon() -> Self::Epsilon {
221        Scalar::default_epsilon()
222    }
223
224    fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
225        self.coords.abs_diff_eq(&other.coords, epsilon)
226    }
227}