Skip to main content

irox_geometry/
point.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2025 IROX Contributors
3//
4
5use 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}