1use matrix3x2f::Matrix3x2f;
4use point2f::Point2f;
5
6#[cfg(all(windows, feature = "d2d"))]
7use winapi::um::d2d1::D2D1_ELLIPSE;
8
9#[derive(Copy, Clone, Debug, Default, PartialEq)]
11#[cfg_attr(feature = "serde_derive", derive(Serialize, Deserialize))]
12#[repr(C)]
13pub struct Ellipse {
14 pub center: Point2f,
16 pub radius_x: f32,
18 pub radius_y: f32,
20}
21
22impl Ellipse {
23 #[inline]
25 pub fn new(center: impl Into<Point2f>, rx: f32, ry: f32) -> Ellipse {
26 Ellipse {
27 center: center.into(),
28 radius_x: rx,
29 radius_y: ry,
30 }
31 }
32
33 #[inline]
35 pub fn contains_point(&self, point: impl Into<Point2f>) -> bool {
36 let point = point.into();
37 let px = point.x - self.center.x;
38 let px2 = px * px;
39 let py = point.y - self.center.y;
40 let py2 = py * py;
41 let rx2 = self.radius_x * self.radius_x;
42 let ry2 = self.radius_y * self.radius_y;
43
44 px2 / rx2 + py2 / ry2 <= 1.0
45 }
46
47 #[inline]
52 pub fn contains_point_transformed(
53 &self,
54 transform: &Matrix3x2f,
55 point: impl Into<Point2f>,
56 ) -> bool {
57 if let Some(inverse) = transform.try_inverse() {
58 let point = point.into();
59 let point = point * inverse;
60 self.contains_point(point)
61 } else {
62 false
63 }
64 }
65}
66
67impl<P> From<(P, f32, f32)> for Ellipse
68where
69 P: Into<Point2f>,
70{
71 #[inline]
72 fn from(data: (P, f32, f32)) -> Ellipse {
73 Ellipse::new(data.0, data.1, data.2)
74 }
75}
76
77#[cfg(all(windows, feature = "d2d"))]
78impl From<Ellipse> for D2D1_ELLIPSE {
79 #[inline]
80 fn from(e: Ellipse) -> D2D1_ELLIPSE {
81 D2D1_ELLIPSE {
82 point: e.center.into(),
83 radiusX: e.radius_x,
84 radiusY: e.radius_y,
85 }
86 }
87}
88
89#[cfg(all(windows, feature = "d2d"))]
90impl From<D2D1_ELLIPSE> for Ellipse {
91 #[inline]
92 fn from(e: D2D1_ELLIPSE) -> Ellipse {
93 Ellipse {
94 center: e.point.into(),
95 radius_x: e.radiusX,
96 radius_y: e.radiusY,
97 }
98 }
99}
100
101#[cfg(all(test, windows, feature = "d2d"))]
102#[test]
103fn ellipse_d2d_bin_compat() {
104 use std::mem::size_of_val;
105
106 fn ptr_eq<T>(a: &T, b: &T) -> bool {
107 (a as *const T) == (b as *const T)
108 }
109
110 let ellipse = Ellipse::new((0.0, 0.0), 1.0, 0.5);
111 let d2d = unsafe { &*((&ellipse) as *const _ as *const D2D1_ELLIPSE) };
112
113 assert!(ptr_eq(&ellipse.center.x, &d2d.point.x));
114 assert!(ptr_eq(&ellipse.center.y, &d2d.point.y));
115 assert!(ptr_eq(&ellipse.radius_x, &d2d.radiusX));
116 assert!(ptr_eq(&ellipse.radius_y, &d2d.radiusY));
117 assert_eq!(size_of_val(&ellipse), size_of_val(d2d));
118}