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