opencv_core/
point.rs

1//! Point structures for OpenCV
2
3use std::fmt;
4use serde::{Serialize, Deserialize};
5
6/// 2D point with integer coordinates
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
8#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
9pub struct Point {
10    pub x: i32,
11    pub y: i32,
12}
13
14impl Point {
15    /// Create a new point
16    pub fn new(x: i32, y: i32) -> Self {
17        Self { x, y }
18    }
19
20    /// Origin point (0, 0)
21    pub fn origin() -> Self {
22        Self::new(0, 0)
23    }
24
25    /// Calculate distance to another point
26    pub fn distance_to(&self, other: &Point) -> f64 {
27        let dx = (self.x - other.x) as f64;
28        let dy = (self.y - other.y) as f64;
29        (dx * dx + dy * dy).sqrt()
30    }
31
32    /// Dot product with another point
33    pub fn dot(&self, other: &Point) -> i32 {
34        self.x * other.x + self.y * other.y
35    }
36}
37
38impl Default for Point {
39    fn default() -> Self {
40        Self::origin()
41    }
42}
43
44impl fmt::Display for Point {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        write!(f, "({}, {})", self.x, self.y)
47    }
48}
49
50impl From<(i32, i32)> for Point {
51    fn from((x, y): (i32, i32)) -> Self {
52        Self::new(x, y)
53    }
54}
55
56impl From<Point> for (i32, i32) {
57    fn from(point: Point) -> Self {
58        (point.x, point.y)
59    }
60}
61
62/// 2D point with single-precision floating-point coordinates
63#[derive(Debug, Clone, Copy, PartialEq)]
64#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
65pub struct Point2f {
66    pub x: f32,
67    pub y: f32,
68}
69
70impl Point2f {
71    /// Create a new point
72    pub fn new(x: f32, y: f32) -> Self {
73        Self { x, y }
74    }
75
76    /// Origin point (0.0, 0.0)
77    pub fn origin() -> Self {
78        Self::new(0.0, 0.0)
79    }
80
81    /// Calculate distance to another point
82    pub fn distance_to(&self, other: &Point2f) -> f32 {
83        let dx = self.x - other.x;
84        let dy = self.y - other.y;
85        (dx * dx + dy * dy).sqrt()
86    }
87
88    /// Dot product with another point
89    pub fn dot(&self, other: &Point2f) -> f32 {
90        self.x * other.x + self.y * other.y
91    }
92
93    /// Normalize the point (treating it as a vector)
94    pub fn normalize(&self) -> Point2f {
95        let len = (self.x * self.x + self.y * self.y).sqrt();
96        if len > 0.0 {
97            Point2f::new(self.x / len, self.y / len)
98        } else {
99            *self
100        }
101    }
102}
103
104impl Default for Point2f {
105    fn default() -> Self {
106        Self::origin()
107    }
108}
109
110impl fmt::Display for Point2f {
111    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
112        write!(f, "({:.2}, {:.2})", self.x, self.y)
113    }
114}
115
116impl From<(f32, f32)> for Point2f {
117    fn from((x, y): (f32, f32)) -> Self {
118        Self::new(x, y)
119    }
120}
121
122impl From<Point2f> for (f32, f32) {
123    fn from(point: Point2f) -> Self {
124        (point.x, point.y)
125    }
126}
127
128impl From<Point> for Point2f {
129    fn from(point: Point) -> Self {
130        Self::new(point.x as f32, point.y as f32)
131    }
132}
133
134/// 2D point with double-precision floating-point coordinates
135#[derive(Debug, Clone, Copy, PartialEq)]
136#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
137pub struct Point2d {
138    pub x: f64,
139    pub y: f64,
140}
141
142impl Point2d {
143    /// Create a new point
144    pub fn new(x: f64, y: f64) -> Self {
145        Self { x, y }
146    }
147
148    /// Origin point (0.0, 0.0)
149    pub fn origin() -> Self {
150        Self::new(0.0, 0.0)
151    }
152
153    /// Calculate distance to another point
154    pub fn distance_to(&self, other: &Point2d) -> f64 {
155        let dx = self.x - other.x;
156        let dy = self.y - other.y;
157        (dx * dx + dy * dy).sqrt()
158    }
159
160    /// Dot product with another point
161    pub fn dot(&self, other: &Point2d) -> f64 {
162        self.x * other.x + self.y * other.y
163    }
164
165    /// Normalize the point (treating it as a vector)
166    pub fn normalize(&self) -> Point2d {
167        let len = (self.x * self.x + self.y * self.y).sqrt();
168        if len > 0.0 {
169            Point2d::new(self.x / len, self.y / len)
170        } else {
171            *self
172        }
173    }
174}
175
176impl Default for Point2d {
177    fn default() -> Self {
178        Self::origin()
179    }
180}
181
182impl fmt::Display for Point2d {
183    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
184        write!(f, "({:.6}, {:.6})", self.x, self.y)
185    }
186}
187
188impl From<(f64, f64)> for Point2d {
189    fn from((x, y): (f64, f64)) -> Self {
190        Self::new(x, y)
191    }
192}
193
194impl From<Point2d> for (f64, f64) {
195    fn from(point: Point2d) -> Self {
196        (point.x, point.y)
197    }
198}
199
200impl From<Point2f> for Point2d {
201    fn from(point: Point2f) -> Self {
202        Self::new(point.x as f64, point.y as f64)
203    }
204}
205
206/// 3D point with single-precision floating-point coordinates
207#[derive(Debug, Clone, Copy, PartialEq)]
208#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
209pub struct Point3f {
210    pub x: f32,
211    pub y: f32,
212    pub z: f32,
213}
214
215impl Point3f {
216    /// Create a new 3D point
217    pub fn new(x: f32, y: f32, z: f32) -> Self {
218        Self { x, y, z }
219    }
220
221    /// Origin point (0.0, 0.0, 0.0)
222    pub fn origin() -> Self {
223        Self::new(0.0, 0.0, 0.0)
224    }
225
226    /// Calculate distance to another point
227    pub fn distance_to(&self, other: &Point3f) -> f32 {
228        let dx = self.x - other.x;
229        let dy = self.y - other.y;
230        let dz = self.z - other.z;
231        (dx * dx + dy * dy + dz * dz).sqrt()
232    }
233
234    /// Dot product with another point
235    pub fn dot(&self, other: &Point3f) -> f32 {
236        self.x * other.x + self.y * other.y + self.z * other.z
237    }
238
239    /// Cross product with another point
240    pub fn cross(&self, other: &Point3f) -> Point3f {
241        Point3f::new(
242            self.y * other.z - self.z * other.y,
243            self.z * other.x - self.x * other.z,
244            self.x * other.y - self.y * other.x,
245        )
246    }
247
248    /// Normalize the point (treating it as a vector)
249    pub fn normalize(&self) -> Point3f {
250        let len = (self.x * self.x + self.y * self.y + self.z * self.z).sqrt();
251        if len > 0.0 {
252            Point3f::new(self.x / len, self.y / len, self.z / len)
253        } else {
254            *self
255        }
256    }
257}
258
259impl Default for Point3f {
260    fn default() -> Self {
261        Self::origin()
262    }
263}
264
265impl fmt::Display for Point3f {
266    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
267        write!(f, "({:.2}, {:.2}, {:.2})", self.x, self.y, self.z)
268    }
269}
270
271impl From<(f32, f32, f32)> for Point3f {
272    fn from((x, y, z): (f32, f32, f32)) -> Self {
273        Self::new(x, y, z)
274    }
275}
276
277impl From<Point3f> for (f32, f32, f32) {
278    fn from(point: Point3f) -> Self {
279        (point.x, point.y, point.z)
280    }
281}
282
283/// 3D point with double-precision floating-point coordinates
284#[derive(Debug, Clone, Copy, PartialEq)]
285#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
286pub struct Point3d {
287    pub x: f64,
288    pub y: f64,
289    pub z: f64,
290}
291
292impl Point3d {
293    /// Create a new 3D point
294    pub fn new(x: f64, y: f64, z: f64) -> Self {
295        Self { x, y, z }
296    }
297
298    /// Origin point (0.0, 0.0, 0.0)
299    pub fn origin() -> Self {
300        Self::new(0.0, 0.0, 0.0)
301    }
302
303    /// Calculate distance to another point
304    pub fn distance_to(&self, other: &Point3d) -> f64 {
305        let dx = self.x - other.x;
306        let dy = self.y - other.y;
307        let dz = self.z - other.z;
308        (dx * dx + dy * dy + dz * dz).sqrt()
309    }
310
311    /// Dot product with another point
312    pub fn dot(&self, other: &Point3d) -> f64 {
313        self.x * other.x + self.y * other.y + self.z * other.z
314    }
315
316    /// Cross product with another point
317    pub fn cross(&self, other: &Point3d) -> Point3d {
318        Point3d::new(
319            self.y * other.z - self.z * other.y,
320            self.z * other.x - self.x * other.z,
321            self.x * other.y - self.y * other.x,
322        )
323    }
324
325    /// Normalize the point (treating it as a vector)
326    pub fn normalize(&self) -> Point3d {
327        let len = (self.x * self.x + self.y * self.y + self.z * self.z).sqrt();
328        if len > 0.0 {
329            Point3d::new(self.x / len, self.y / len, self.z / len)
330        } else {
331            *self
332        }
333    }
334}
335
336impl Default for Point3d {
337    fn default() -> Self {
338        Self::origin()
339    }
340}
341
342impl fmt::Display for Point3d {
343    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344        write!(f, "({:.6}, {:.6}, {:.6})", self.x, self.y, self.z)
345    }
346}
347
348impl From<(f64, f64, f64)> for Point3d {
349    fn from((x, y, z): (f64, f64, f64)) -> Self {
350        Self::new(x, y, z)
351    }
352}
353
354impl From<Point3d> for (f64, f64, f64) {
355    fn from(point: Point3d) -> Self {
356        (point.x, point.y, point.z)
357    }
358}
359
360impl From<Point3f> for Point3d {
361    fn from(point: Point3f) -> Self {
362        Self::new(point.x as f64, point.y as f64, point.z as f64)
363    }
364}
365
366#[cfg(test)]
367mod tests {
368    use super::*;
369
370    #[test]
371    fn test_point_creation() {
372        let p = Point::new(10, 20);
373        assert_eq!(p.x, 10);
374        assert_eq!(p.y, 20);
375    }
376
377    #[test]
378    fn test_point_distance() {
379        let p1 = Point::new(0, 0);
380        let p2 = Point::new(3, 4);
381        assert_eq!(p1.distance_to(&p2), 5.0);
382    }
383
384    #[test]
385    fn test_point3d_cross_product() {
386        let p1 = Point3d::new(1.0, 0.0, 0.0);
387        let p2 = Point3d::new(0.0, 1.0, 0.0);
388        let cross = p1.cross(&p2);
389        assert_eq!(cross, Point3d::new(0.0, 0.0, 1.0));
390    }
391}