irox_stats/
points.rs

1// SPDX-License-Identifier: MIT
2// Copyright 2024 IROX Contributors
3//
4
5use crate::rects::Rect2D;
6use core::cmp::Ordering;
7///
8/// Geometric Cartesian Coordinate Spaces
9use core::ops::Add;
10use irox_bits::{FromBEBytes, ToBEBytes};
11
12/// Geometric point in Cartesian 2D Space.  X and Y values.
13pub trait Point2D {
14    type Output: Copy + Add;
15    fn get_x(&self) -> Self::Output;
16    fn get_y(&self) -> Self::Output;
17
18    #[must_use]
19    fn new(x: Self::Output, y: Self::Output) -> Self;
20
21    #[must_use]
22    fn new_f64(x: f64, y: f64) -> Double2D {
23        Double2D { x, y }
24    }
25    #[must_use]
26    fn new_f32(x: f32, y: f32) -> Float2D {
27        Float2D { x, y }
28    }
29}
30
31pub trait EncodablePoint2D<const N: usize>: Point2D {
32    fn encode(&self) -> [u8; N];
33    fn decode(value: [u8; N]) -> Self;
34}
35
36/// Geometric point in Cartesian 2D Space.  X and Y values. Backed by two [`f64`]'s
37#[derive(Default, Debug, Copy, Clone, PartialEq)]
38pub struct Double2D {
39    pub x: f64,
40    pub y: f64,
41}
42impl Double2D {
43    #[must_use]
44    pub const fn new(x: f64, y: f64) -> Self {
45        Double2D { x, y }
46    }
47    #[must_use]
48    pub fn new_f64(x: f64, y: f64) -> Self {
49        Double2D { x, y }
50    }
51    #[must_use]
52    pub fn get_x(&self) -> f64 {
53        self.x
54    }
55    #[must_use]
56    pub fn get_y(&self) -> f64 {
57        self.y
58    }
59
60    #[must_use]
61    pub fn translate(&self, vec: &Vec2D) -> Double2D {
62        Self {
63            x: self.x + vec.x,
64            y: self.y + vec.y,
65        }
66    }
67
68    pub fn translate_mut(&mut self, vec: &Vec2D) {
69        self.x += vec.x;
70        self.y += vec.y;
71    }
72}
73impl From<[f64; 2]> for Double2D {
74    fn from(val: [f64; 2]) -> Double2D {
75        let [x, y] = val;
76        Double2D { x, y }
77    }
78}
79impl Eq for Double2D {}
80impl PartialOrd for Double2D {
81    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
82        Some(self.cmp(other))
83    }
84}
85impl Ord for Double2D {
86    fn cmp(&self, other: &Self) -> Ordering {
87        let x = self.x.total_cmp(&other.x);
88        if x != Ordering::Equal {
89            return x;
90        }
91        self.y.total_cmp(&other.y)
92    }
93}
94impl core::ops::Sub for Double2D {
95    type Output = Vec2D;
96
97    fn sub(self, rhs: Self) -> Self::Output {
98        let x = self.x - rhs.x;
99        let y = self.y - rhs.y;
100        Vec2D { x, y }
101    }
102}
103
104impl Point2D for Double2D {
105    type Output = f64;
106
107    fn get_x(&self) -> Self::Output {
108        self.x
109    }
110
111    fn get_y(&self) -> Self::Output {
112        self.y
113    }
114
115    fn new(x: Self::Output, y: Self::Output) -> Self {
116        Double2D { x, y }
117    }
118}
119impl EncodablePoint2D<16> for Double2D {
120    fn encode(&self) -> [u8; 16] {
121        [self.x, self.y].to_be_bytes()
122    }
123
124    fn decode(val: [u8; 16]) -> Self {
125        <[f64; 2]>::from_be_bytes(val).into()
126    }
127}
128
129/// Geometric point in Cartesian 2D Space.  X and Y values. Backed by two [`f32`]'s
130#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd)]
131pub struct Float2D {
132    pub x: f32,
133    pub y: f32,
134}
135impl From<[f32; 2]> for Float2D {
136    fn from(val: [f32; 2]) -> Float2D {
137        let [x, y] = val;
138        Float2D { x, y }
139    }
140}
141impl Point2D for Float2D {
142    type Output = f32;
143
144    fn get_x(&self) -> Self::Output {
145        self.x
146    }
147
148    fn get_y(&self) -> Self::Output {
149        self.y
150    }
151
152    fn new(x: Self::Output, y: Self::Output) -> Self {
153        Float2D { x, y }
154    }
155}
156impl EncodablePoint2D<8> for Float2D {
157    fn encode(&self) -> [u8; 8] {
158        [self.x, self.y].to_be_bytes()
159    }
160
161    fn decode(val: [u8; 8]) -> Self {
162        <[f32; 2]>::from_be_bytes(val).into()
163    }
164}
165
166/// Geometric point in Cartesian 2D Space.  X and Y values. Backed by two [`u64`]'s
167#[derive(Default, Debug, Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
168pub struct Quad2D {
169    pub x: u64,
170    pub y: u64,
171}
172impl From<[u64; 2]> for Quad2D {
173    fn from(val: [u64; 2]) -> Quad2D {
174        let [x, y] = val;
175        Quad2D { x, y }
176    }
177}
178impl Point2D for Quad2D {
179    type Output = u64;
180
181    fn get_x(&self) -> Self::Output {
182        self.x
183    }
184
185    fn get_y(&self) -> Self::Output {
186        self.y
187    }
188
189    fn new(x: Self::Output, y: Self::Output) -> Self {
190        Quad2D { x, y }
191    }
192}
193impl EncodablePoint2D<16> for Quad2D {
194    fn encode(&self) -> [u8; 16] {
195        [self.x, self.y].to_be_bytes()
196    }
197
198    fn decode(val: [u8; 16]) -> Self {
199        <[u64; 2]>::from_be_bytes(val).into()
200    }
201}
202
203#[derive(Debug, Copy, Clone, PartialEq)]
204pub struct Vec2D {
205    pub x: f64,
206    pub y: f64,
207}
208impl Default for Vec2D {
209    fn default() -> Self {
210        Vec2D { x: 1.0, y: 1.0 }
211    }
212}
213impl Eq for Vec2D {}
214impl PartialOrd for Vec2D {
215    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
216        Some(self.cmp(other))
217    }
218}
219impl Ord for Vec2D {
220    fn cmp(&self, other: &Self) -> Ordering {
221        let x = self.x.total_cmp(&other.x);
222        if x != Ordering::Equal {
223            return x;
224        }
225        self.y.total_cmp(&other.y)
226    }
227}
228impl Vec2D {
229    #[must_use]
230    pub fn new(x: f64, y: f64) -> Self {
231        Vec2D { x, y }
232    }
233    #[must_use]
234    pub fn get_x(&self) -> f64 {
235        self.x
236    }
237    #[must_use]
238    pub fn get_y(&self) -> f64 {
239        self.y
240    }
241
242    #[must_use]
243    pub fn with_origin(&self, origin: Double2D) -> Rect2D {
244        Rect2D {
245            origin,
246            far_point: origin.translate(self),
247        }
248    }
249}
250#[cfg(feature = "emath")]
251impl From<emath::Vec2> for Vec2D {
252    fn from(pos: emath::Vec2) -> Self {
253        Self {
254            x: pos.x as f64,
255            y: pos.y as f64,
256        }
257    }
258}
259#[cfg(feature = "emath")]
260impl From<emath::Pos2> for Double2D {
261    fn from(pos: emath::Pos2) -> Self {
262        Self {
263            x: pos.x as f64,
264            y: pos.y as f64,
265        }
266    }
267}
268#[cfg(feature = "emath")]
269impl From<Double2D> for emath::Pos2 {
270    fn from(value: Double2D) -> Self {
271        Self {
272            x: value.x as f32,
273            y: value.y as f32,
274        }
275    }
276}