1use crate::geometry::{Centroid, Geometry};
6use crate::rectangle::Rectangle;
7use crate::{Vector, Vector2D};
8use core::ops::Add;
9use core::ops::Sub;
10use core::ops::{AddAssign, SubAssign};
11use irox_tools::FloatIsh;
12
13pub trait Point2D<T: FloatIsh>: Default + Copy + Clone + PartialEq + PartialOrd {
14 fn x(&self) -> T;
15 fn y(&self) -> T;
16 fn z(&self) -> Option<T>;
17 fn m(&self) -> Option<T>;
18
19 fn new_point(x: T, y: T) -> Point<T> {
20 Point {
21 x,
22 y,
23 z: None,
24 m: None,
25 }
26 }
27
28 fn as_pointz(&self, or_else_z: T) -> PointZ<T>;
29 fn as_pointm(&self, or_else_m: T) -> PointM<T>;
30 fn as_pointzm(&self, or_else_z: T, or_else_m: T) -> PointZM<T>;
31}
32
33#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
34pub struct Point<T: FloatIsh> {
35 pub x: T,
36 pub y: T,
37 pub z: Option<T>,
38 pub m: Option<T>,
39}
40impl<T: FloatIsh> Point<T> {
41 pub fn to_vector(&self) -> Vector<T> {
42 Vector {
43 vx: self.x,
44 vy: self.y,
45 }
46 }
47}
48impl<T: FloatIsh> Point2D<T> for Point<T> {
49 fn x(&self) -> T {
50 self.x
51 }
52
53 fn y(&self) -> T {
54 self.y
55 }
56
57 fn z(&self) -> Option<T> {
58 self.z
59 }
60
61 fn m(&self) -> Option<T> {
62 self.m
63 }
64
65 fn as_pointz(&self, default_z: T) -> PointZ<T> {
66 PointZ {
67 x: self.x,
68 y: self.y,
69 z: self.z.unwrap_or(default_z),
70 m: self.m,
71 }
72 }
73
74 fn as_pointm(&self, or_else_m: T) -> PointM<T> {
75 PointM {
76 x: self.x,
77 y: self.y,
78 z: self.z,
79 m: self.m.unwrap_or(or_else_m),
80 }
81 }
82
83 fn as_pointzm(&self, or_else_z: T, or_else_m: T) -> PointZM<T> {
84 PointZM {
85 x: self.x,
86 y: self.y,
87 z: self.z.unwrap_or(or_else_z),
88 m: self.m.unwrap_or(or_else_m),
89 }
90 }
91}
92
93#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
94pub struct PointZ<T: FloatIsh> {
95 pub x: T,
96 pub y: T,
97 pub z: T,
98 pub m: Option<T>,
99}
100
101#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
102pub struct PointM<T: FloatIsh> {
103 pub x: T,
104 pub y: T,
105 pub z: Option<T>,
106 pub m: T,
107}
108
109#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Default)]
110pub struct PointZM<T: FloatIsh> {
111 pub x: T,
112 pub y: T,
113 pub z: T,
114 pub m: T,
115}
116
117impl<T: FloatIsh> Add<Vector<T>> for Point<T> {
118 type Output = Self;
119
120 fn add(self, rhs: Vector<T>) -> Self::Output {
121 Self {
122 x: self.x + rhs.vx,
123 y: self.y + rhs.vy,
124 z: self.z,
125 m: self.m,
126 }
127 }
128}
129
130impl<T: FloatIsh> Sub for Point<T> {
131 type Output = Vector<T>;
132
133 fn sub(self, rhs: Self) -> Self::Output {
134 self.to_vector() - rhs.to_vector()
135 }
136}
137impl<T: FloatIsh> SubAssign<Vector<T>> for Point<T> {
138 fn sub_assign(&mut self, rhs: Vector<T>) {
139 self.x -= rhs.vx;
140 self.y -= rhs.vy;
141 }
142}
143impl<T: FloatIsh> AddAssign<Vector<T>> for Point<T> {
144 fn add_assign(&mut self, rhs: Vector<T>) {
145 self.x += rhs.vx;
146 self.y += rhs.vy;
147 }
148}
149
150impl<T: FloatIsh> Centroid<T> for Point<T> {
151 fn centroid(&self) -> Point<T> {
152 *self
153 }
154}
155
156impl<T: FloatIsh> Geometry<T> for Point<T> {
157 fn contains(&self, point: &Point<T>) -> bool {
158 self == point
159 }
160
161 fn distance_to(&self, point: &Point<T>) -> T {
162 let d = *self - *point;
163 d.magnitude()
164 }
165
166 fn intersects(&self, point: &Point<T>) -> bool {
167 self.contains(point)
168 }
169
170 fn bounding_rectangle(&self) -> Rectangle<T> {
171 Rectangle {
172 min: *self,
173 size: Vector::default(),
174 }
175 }
176}