summaryrefslogtreecommitdiff
path: root/src/geometry/point.rs
blob: c34d00fb3f709026e907208d7f4041677421a6ce (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
use crate::geometry::vec::*;

use std::ops::*;
use num_traits::{NumOps, NumAssignOps};
use num_traits::pow::Pow;
use num_traits::real::Real;

macro_rules! impl_point {
    ($PointN:ident { $($field:ident),+ }, $VecN:ident) => {
        #[derive(Debug, Default, Clone, Copy, Hash, PartialEq, Eq)]
        pub struct $PointN<T> {
            $(pub $field: T),+
        }

        impl<T> $PointN<T> {
            pub fn new($($field: T),+) -> $PointN<T> {
                $PointN { $($field),+ }
            }
        }

        impl<T: NumOps + Pow<u8, Output=T> + Copy> $PointN<T> {
            pub fn distance_squared(self, other: $PointN<T>) -> T {
                (self - other).magnitude_squared()
            }
        }


        impl<T: Real + Pow<u8, Output=T>> $PointN<T> {
            pub fn distance(self, other: $PointN<T>) -> T {
                (self - other).magnitude()
            }
        }

        impl<T: NumOps> Add<$VecN<T>> for $PointN<T> {
            type Output = Self;

            fn add(self, other: $VecN<T>) -> Self {
                $PointN {
                    $($field: self.$field + other.$field),+
                }
            }
        }

        impl<T: NumAssignOps> AddAssign<$VecN<T>> for $PointN<T> {
            fn add_assign(&mut self, other: $VecN<T>) {
                $(self.$field += other.$field);+
            }
        }

        impl<T: NumOps> Sub for $PointN<T> {
            type Output = $VecN<T>;

            fn sub(self, other: Self) -> $VecN<T> {
                $VecN {
                    $($field: self.$field - other.$field),+
                }
            }
        }
    }
}

impl_point!(Point2d { x, y }, Vec2d);
impl_point!(Point3d { x, y, z }, Vec3d);

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn distance_in_x_dimension_example() {
        let a = Point2d::new(1., 1.);
        let b = Point2d::new(3., 1.);
        assert_eq!(a.distance(b), 2.);
        assert_eq!(a.distance_squared(b), 4.);
    }

    #[test]
    fn distance_in_y_dimension_example() {
        let a = Point2d::new(1., 1.);
        let b = Point2d::new(1., 3.);
        assert_eq!(b.distance(a), 2.);
        assert_eq!(b.distance_squared(a), 4.);
    }
}