1use core::{
2 array,
3 fmt::{Debug, Formatter},
4 marker::PhantomData as Pd,
5 ops::{Add, AddAssign, Index, IndexMut, Sub, SubAssign},
6};
7
8use super::{Affine, ApproxEq, Linear, Vector, space::Real, vary::ZDiv};
9
10#[repr(transparent)]
11pub struct Point<Repr, Space = ()>(pub Repr, Pd<Space>);
12
13pub type Point2<Basis = ()> = Point<[f32; 2], Real<2, Basis>>;
15pub type Point3<Basis = ()> = Point<[f32; 3], Real<3, Basis>>;
17
18pub type Point2u<Basis = ()> = Point<[u32; 2], Real<2, Basis>>;
20
21pub const fn pt2<Sc, B>(x: Sc, y: Sc) -> Point<[Sc; 2], Real<2, B>> {
23 Point([x, y], Pd)
24}
25pub const fn pt3<Sc, B>(x: Sc, y: Sc, z: Sc) -> Point<[Sc; 3], Real<3, B>> {
27 Point([x, y, z], Pd)
28}
29
30impl<R, Sp> Point<R, Sp> {
31 #[inline]
32 pub const fn new(repr: R) -> Self {
33 Self(repr, Pd)
34 }
35
36 #[inline]
39 pub fn to<S>(self) -> Point<R, S> {
40 Point(self.0, Pd)
41 }
42
43 #[inline]
46 pub fn to_vec(self) -> Vector<R, Sp> {
47 Vector::new(self.0)
48 }
49}
50
51impl<Sc: Copy, Sp, const N: usize> Point<[Sc; N], Sp> {
52 #[inline]
63 #[must_use]
64 pub fn map<T>(self, f: impl FnMut(Sc) -> T) -> Point<[T; N], Sp> {
65 self.0.map(f).into()
66 }
67
68 #[inline]
80 #[must_use]
81 pub fn zip_map<T: Copy, U>(
82 self,
83 other: Point<[T; N], Sp>,
84 mut f: impl FnMut(Sc, T) -> U,
85 ) -> Point<[U; N], Sp> {
86 array::from_fn(|i| f(self.0[i], other.0[i])).into()
87 }
88}
89
90impl<const N: usize, B> Point<[f32; N], Real<N, B>> {
91 #[inline]
93 pub const fn origin() -> Self {
94 Self::new([0.0; N])
95 }
96
97 #[cfg(feature = "fp")]
108 #[inline]
109 pub fn distance(&self, other: &Self) -> f32 {
110 self.sub(other).len()
111 }
112
113 #[inline]
127 pub fn distance_sqr(&self, other: &Self) -> f32 {
128 self.sub(other).len_sqr()
129 }
130
131 #[must_use]
152 pub fn clamp(&self, min: &Self, max: &Self) -> Self {
153 array::from_fn(|i| self.0[i].clamp(min.0[i], max.0[i])).into()
154 }
155}
156
157impl<R, B, Sc> Point<R, Real<2, B>>
158where
159 R: Index<usize, Output = Sc>,
160 Sc: Copy,
161{
162 #[inline]
164 pub fn x(&self) -> Sc {
165 self.0[0]
166 }
167 #[inline]
169 pub fn y(&self) -> Sc {
170 self.0[1]
171 }
172}
173
174impl Point2 {
175 pub fn to_pt3(self) -> Point3 {
177 pt3(self.x(), self.y(), 0.0)
178 }
179}
180
181impl<R, Sc, B> Point<R, Real<3, B>>
182where
183 R: Index<usize, Output = Sc>,
184 Sc: Copy,
185{
186 #[inline]
188 pub fn x(&self) -> Sc {
189 self.0[0]
190 }
191 #[inline]
193 pub fn y(&self) -> Sc {
194 self.0[1]
195 }
196 #[inline]
198 pub fn z(&self) -> Sc {
199 self.0[2]
200 }
201}
202
203impl<ScSelf, ScDiff, Sp, const N: usize> Affine for Point<[ScSelf; N], Sp>
208where
209 ScSelf: Affine<Diff = ScDiff> + Copy,
210 ScDiff: Linear<Scalar = ScDiff> + Copy,
211{
212 type Space = Sp;
213 type Diff = Vector<[ScDiff; N], Sp>;
214 const DIM: usize = N;
215
216 #[inline]
217 fn add(&self, other: &Self::Diff) -> Self {
218 Self(array::from_fn(|i| self.0[i].add(&other.0[i])), Pd)
220 }
221 #[inline]
222 fn sub(&self, other: &Self) -> Self::Diff {
223 Vector::new(array::from_fn(|i| self.0[i].sub(&other.0[i])))
224 }
225}
226
227impl<Sc, Sp, const N: usize> ZDiv for Point<[Sc; N], Sp>
228where
229 Sc: ZDiv + Copy,
230{
231 fn z_div(self, z: f32) -> Self {
232 self.map(|c| c.z_div(z))
233 }
234}
235
236impl<Sc: ApproxEq, Sp, const N: usize> ApproxEq<Self, Sc>
237 for Point<[Sc; N], Sp>
238{
239 fn approx_eq_eps(&self, other: &Self, eps: &Sc) -> bool {
240 self.0.approx_eq_eps(&other.0, eps)
241 }
242 fn relative_epsilon() -> Sc {
243 Sc::relative_epsilon()
244 }
245}
246
247impl<R: Copy, S> Copy for Point<R, S> {}
255
256impl<R: Clone, S> Clone for Point<R, S> {
257 fn clone(&self) -> Self {
258 Self(self.0.clone(), Pd)
259 }
260}
261
262impl<R: Default, S> Default for Point<R, S> {
263 fn default() -> Self {
264 Self(R::default(), Pd)
265 }
266}
267
268impl<R: Debug, Sp: Debug + Default> Debug for Point<R, Sp> {
269 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
270 write!(f, "Point<{:?}>", Sp::default())?;
271 Debug::fmt(&self.0, f)
272 }
273}
274
275impl<R: Eq, S> Eq for Point<R, S> {}
276
277impl<R: PartialEq, S> PartialEq for Point<R, S> {
278 fn eq(&self, other: &Self) -> bool {
279 self.0 == other.0
280 }
281}
282
283impl<R, Sp> From<R> for Point<R, Sp> {
284 #[inline]
285 fn from(repr: R) -> Self {
286 Self(repr, Pd)
287 }
288}
289impl<R: Index<usize>, Sp> Index<usize> for Point<R, Sp> {
305 type Output = R::Output;
306
307 fn index(&self, i: usize) -> &Self::Output {
308 self.0.index(i)
309 }
310}
311
312impl<R: IndexMut<usize>, Sp> IndexMut<usize> for Point<R, Sp> {
313 fn index_mut(&mut self, i: usize) -> &mut R::Output {
314 self.0.index_mut(i)
315 }
316}
317
318impl<R, Sp> Add<<Self as Affine>::Diff> for Point<R, Sp>
319where
320 Self: Affine,
321{
322 type Output = Self;
323
324 fn add(self, other: <Self as Affine>::Diff) -> Self {
325 Affine::add(&self, &other)
326 }
327}
328
329impl<R, Sp> AddAssign<<Self as Affine>::Diff> for Point<R, Sp>
330where
331 Self: Affine,
332{
333 fn add_assign(&mut self, other: <Self as Affine>::Diff) {
334 *self = Affine::add(self, &other);
335 }
336}
337
338impl<R, Sp> Sub<<Self as Affine>::Diff> for Point<R, Sp>
339where
340 Self: Affine,
341{
342 type Output = Self;
343
344 fn sub(self, other: <Self as Affine>::Diff) -> Self {
345 Affine::add(&self, &other.neg())
346 }
347}
348
349impl<R, Sp> SubAssign<<Self as Affine>::Diff> for Point<R, Sp>
350where
351 Self: Affine,
352{
353 fn sub_assign(&mut self, other: <Self as Affine>::Diff) {
354 *self = Affine::add(self, &other.neg());
355 }
356}
357
358impl<R, Sp> Sub for Point<R, Sp>
359where
360 Self: Affine,
361{
362 type Output = <Self as Affine>::Diff;
363
364 fn sub(self, other: Self) -> Self::Output {
365 Affine::sub(&self, &other)
366 }
367}
368
369#[cfg(test)]
370#[allow(non_upper_case_globals)]
371mod tests {
372 use super::*;
373 use crate::math::{Lerp, vec2, vec3};
374
375 mod f32 {
376 use super::*;
377
378 const pt2: fn(f32, f32) -> Point2 = super::pt2;
379 const pt3: fn(f32, f32, f32) -> Point3 = super::pt3;
380 #[test]
381 fn vector_addition() {
382 assert_eq!(pt2(1.0, 2.0) + vec2(-2.0, 3.0), pt2(-1.0, 5.0));
383 assert_eq!(
384 pt3(1.0, 2.0, 3.0) + vec3(-2.0, 3.0, 1.0),
385 pt3(-1.0, 5.0, 4.0)
386 )
387 }
388 #[test]
389 fn vector_subtraction() {
390 assert_eq!(pt2(1.0, 2.0) - vec2(-2.0, 3.0), pt2(3.0, -1.0));
391 assert_eq!(
392 pt3(1.0, 2.0, 3.0) - vec3(-2.0, 3.0, 1.0),
393 pt3(3.0, -1.0, 2.0)
394 )
395 }
396 #[test]
397 fn point_subtraction() {
398 assert_eq!(pt2(1.0, 2.0) - pt2(-2.0, 3.0), vec2(3.0, -1.0));
399 assert_eq!(
400 pt3(1.0, 2.0, 3.0) - pt3(-2.0, 3.0, 1.0),
401 vec3(3.0, -1.0, 2.0)
402 )
403 }
404 #[test]
405 fn point_point_distance_sqr() {
406 assert_eq!(pt2(1.0, -1.0).distance_sqr(&pt2(-2.0, 3.0)), 25.0);
407 assert_eq!(
408 pt3(1.0, -3.0, 2.0).distance_sqr(&pt3(-2.0, 3.0, 4.0)),
409 49.0
410 );
411 }
412 #[test]
413 #[cfg(feature = "fp")]
414 fn point_point_distance() {
415 assert_eq!(pt2(1.0, -1.0).distance(&pt2(-2.0, 3.0)), 5.0);
416 assert_eq!(pt3(1.0, -3.0, 2.0).distance(&pt3(-2.0, 3.0, 4.0)), 7.0);
417 }
418 #[test]
419 fn point2_clamp() {
420 let (min, max) = (&pt2(-2.0, -1.0), &pt2(3.0, 2.0));
421 assert_eq!(pt2(1.0, -1.0).clamp(min, max), pt2(1.0, -1.0));
422 assert_eq!(pt2(3.0, -2.0).clamp(min, max), pt2(3.0, -1.0));
423 assert_eq!(pt2(-3.0, 4.0).clamp(min, max), pt2(-2.0, 2.0));
424 }
425 #[test]
426 fn point3_clamp() {
427 let (min, max) = (&pt3(-2.0, -1.0, 0.0), &pt3(3.0, 2.0, 1.0));
428 assert_eq!(
429 pt3(1.0, -1.0, 0.0).clamp(min, max),
430 pt3(1.0, -1.0, 0.0)
431 );
432 assert_eq!(
433 pt3(3.0, -2.0, -1.0).clamp(min, max),
434 pt3(3.0, -1.0, 0.0)
435 );
436 assert_eq!(
437 pt3(-3.0, 4.0, 2.0).clamp(min, max),
438 pt3(-2.0, 2.0, 1.0)
439 );
440 }
441 #[test]
442 fn point2_indexing() {
443 let mut p = pt2(2.0, -1.0);
444 assert_eq!(p[0], p.x());
445 assert_eq!(p[1], p.y());
446
447 p[1] -= 1.0;
448 assert_eq!(p[1], -2.0);
449 }
450 #[test]
451 fn point3_indexing() {
452 let mut p = pt3(2.0, -1.0, 3.0);
453 assert_eq!(p[0], p.x());
454 assert_eq!(p[1], p.y());
455 assert_eq!(p[2], p.z());
456
457 p[2] += 1.0;
458 assert_eq!(p[2], 4.0);
459 }
460 #[test]
461 #[should_panic]
462 fn point2_index_oob() {
463 _ = pt2(1.0, 2.0)[2];
464 }
465 #[test]
466 fn point2_lerp() {
467 assert_eq!(
468 pt2(2.0, -1.0).lerp(&pt2(-2.0, 3.0), 0.25),
469 pt2(1.0, 0.0)
470 );
471 }
472 }
473
474 mod u32 {
475 use super::*;
476
477 const pt2: fn(u32, u32) -> Point2u = super::super::pt2;
478
479 #[test]
480 fn vector_addition() {
481 assert_eq!(pt2(1_u32, 2) + vec2(1_i32, -2), pt2(2_u32, 0));
482 }
483
484 #[test]
485 fn vector_subtraction() {
486 assert_eq!(pt2(3_u32, 2) - vec2(3_i32, -1), pt2(0_u32, 3));
487 }
488
489 #[test]
490 fn point_subtraction() {
491 assert_eq!(pt2(3_u32, 2) - pt2(3_u32, 3), vec2(0, -1));
492 }
493
494 #[test]
495 fn indexing() {
496 let mut p = pt2(1u32, 2);
497 assert_eq!(p[1], 2);
498 p[0] = 3;
499 assert_eq!(p.0, [3, 2]);
500 }
501
502 #[test]
503 fn from_array() {
504 assert_eq!(Point2u::from([1, 2]), pt2(1, 2));
505 }
506 }
507}