math2d/
point2f.rs

1//! Mathematical point on the 2D (x, y) plane.
2
3use point2i::Point2i;
4use point2u::Point2u;
5use vector2f::Vector2f;
6
7use std::ops::{Add, Sub};
8
9#[cfg(all(windows, feature = "d2d"))]
10use winapi::um::dcommon::D2D_POINT_2F;
11
12/// Mathematical point on the 2D (x, y) plane.
13#[derive(Copy, Clone, Debug, Default, PartialEq)]
14#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
15#[repr(C)]
16pub struct Point2f {
17    /// Horizontal component
18    pub x: f32,
19    /// Vertical component
20    pub y: f32,
21}
22
23/// Mathematical origin point on the real number plane.
24pub const ORIGIN: Point2f = Point2f::ORIGIN;
25
26impl Point2f {
27    /// Mathematical origin point on the real number plane.
28    pub const ORIGIN: Point2f = Point2f { x: 0.0, y: 0.0 };
29
30    /// Construct a point from the components
31    #[inline]
32    pub fn new(x: f32, y: f32) -> Self {
33        Point2f { x, y }
34    }
35
36    /// Casts the point to an integer point. Will truncate integers; if
37    /// another behavior is desired it should be manually performed on
38    /// the values before calling this function.
39    #[inline]
40    pub fn to_i32(self) -> Point2i {
41        Point2i {
42            x: self.x as i32,
43            y: self.y as i32,
44        }
45    }
46
47    /// Casts the point to an unsigned integer point. Will truncate integers;
48    /// if another behavior is desired it should be manually performed on
49    /// the values before calling this function. Beware this function will
50    /// not produce reasonable values if the current value is negative.
51    #[inline]
52    pub fn to_u32(self) -> Point2u {
53        Point2u {
54            x: self.x as u32,
55            y: self.y as u32,
56        }
57    }
58
59    /// Rounds the values in the point to the nearest integer, rounding away
60    /// from zero in the half-way case.
61    /// 
62    /// See [f32::round][1]
63    /// 
64    /// [1]: https://doc.rust-lang.org/std/primitive.f32.html#method.round
65    #[inline]
66    pub fn rounded(self) -> Point2f {
67        Point2f {
68            x: self.x.round(),
69            y: self.y.round(),
70        }
71    }
72
73    /// Determines if the components of two points are less than `epsilon`
74    /// distance from each other. Be wary that this does not check the actual
75    /// distance, but a component-wise distance check. If you desire a more
76    /// precise distance check, consider subtracting one point from the other
77    /// and comparing the length(_sq) of the resulting vector.
78    #[inline]
79    pub fn is_approx_eq(self, other: impl Into<Point2f>, epsilon: f32) -> bool {
80        let other = other.into();
81        return (self.x - other.x).abs() <= epsilon && (self.y - other.y).abs() <= epsilon;
82    }
83}
84
85impl<V> Add<V> for Point2f
86where
87    V: Into<Vector2f>,
88{
89    type Output = Point2f;
90
91    #[inline]
92    fn add(self, rhs: V) -> Point2f {
93        let rhs = rhs.into();
94        Point2f {
95            x: self.x + rhs.x,
96            y: self.y + rhs.y,
97        }
98    }
99}
100
101impl Sub for Point2f {
102    type Output = Vector2f;
103
104    #[inline]
105    fn sub(self, rhs: Point2f) -> Vector2f {
106        Vector2f {
107            x: self.x - rhs.x,
108            y: self.y - rhs.y,
109        }
110    }
111}
112
113impl Sub<(f32, f32)> for Point2f {
114    type Output = Vector2f;
115
116    #[inline]
117    fn sub(self, rhs: (f32, f32)) -> Vector2f {
118        Vector2f {
119            x: self.x - rhs.0,
120            y: self.y - rhs.1,
121        }
122    }
123}
124
125impl Sub<Point2f> for (f32, f32) {
126    type Output = Vector2f;
127
128    #[inline]
129    fn sub(self, rhs: Point2f) -> Vector2f {
130        Vector2f {
131            x: self.0 - rhs.x,
132            y: self.1 - rhs.y,
133        }
134    }
135}
136
137impl<V> Sub<V> for Point2f
138where
139    V: Into<Vector2f>,
140{
141    type Output = Point2f;
142
143    #[inline]
144    fn sub(self, rhs: V) -> Point2f {
145        let rhs = rhs.into();
146        Point2f {
147            x: self.x - rhs.x,
148            y: self.y - rhs.y,
149        }
150    }
151}
152
153impl From<(f32, f32)> for Point2f {
154    #[inline]
155    fn from((x, y): (f32, f32)) -> Point2f {
156        Point2f { x, y }
157    }
158}
159
160impl From<[f32; 2]> for Point2f {
161    #[inline]
162    fn from(p: [f32; 2]) -> Point2f {
163        Point2f { x: p[0], y: p[0] }
164    }
165}
166
167impl From<Point2f> for [f32; 2] {
168    #[inline]
169    fn from(p: Point2f) -> [f32; 2] {
170        [p.x, p.y]
171    }
172}
173
174#[cfg(all(windows, feature = "d2d"))]
175impl From<Point2f> for D2D_POINT_2F {
176    #[inline]
177    fn from(point: Point2f) -> D2D_POINT_2F {
178        D2D_POINT_2F {
179            x: point.x,
180            y: point.y,
181        }
182    }
183}
184
185#[cfg(all(windows, feature = "d2d"))]
186impl From<D2D_POINT_2F> for Point2f {
187    #[inline]
188    fn from(point: D2D_POINT_2F) -> Point2f {
189        Point2f {
190            x: point.x,
191            y: point.y,
192        }
193    }
194}
195
196#[cfg(feature = "mint")]
197impl From<Point2f> for mint::Point2<f32> {
198    #[inline]
199    fn from(p: Point2f) -> mint::Point2<f32> {
200        mint::Point2 { x: p.x, y: p.y }
201    }
202}
203
204#[cfg(feature = "mint")]
205impl From<mint::Point2<f32>> for Point2f {
206    #[inline]
207    fn from(p: mint::Point2<f32>) -> Point2f {
208        Point2f { x: p.x, y: p.y }
209    }
210}
211
212#[cfg(all(test, windows, feature = "d2d"))]
213#[test]
214fn pt2f_d2d_bin_compat() {
215    use std::mem::size_of_val;
216
217    fn ptr_eq<T>(a: &T, b: &T) -> bool {
218        (a as *const T) == (b as *const T)
219    }
220
221    let pt = Point2f::ORIGIN;
222    let d2d = unsafe { &*((&pt) as *const _ as *const D2D_POINT_2F) };
223
224    assert!(ptr_eq(&pt.x, &d2d.x));
225    assert!(ptr_eq(&pt.y, &d2d.y));
226    assert_eq!(size_of_val(&pt), size_of_val(d2d));
227}