1use iced_core::Point;
4use std::fmt::Display;
5
6pub const PERIOD_PERCENTAGE: f32 = 0.1;
8
9pub const HOUR_RADIUS_PERCENTAGE: f32 = 0.4;
11
12pub const MINUTE_RADIUS_PERCENTAGE: f32 = 0.65;
14
15pub const SECOND_RADIUS_PERCENTAGE: f32 = 0.9;
17
18pub const HOUR_RADIUS_PERCENTAGE_NO_SECONDS: f32 = 0.5;
21
22pub const MINUTE_RADIUS_PERCENTAGE_NO_SECONDS: f32 = 0.9;
25
26#[derive(Clone, Debug)]
28pub enum Period {
29 AM,
31 PM,
33}
34
35impl Display for Period {
36 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
37 write!(
38 f,
39 "{}",
40 match self {
41 Self::AM => "AM",
42 Self::PM => "PM",
43 }
44 )
45 }
46}
47
48#[derive(Clone, Debug, PartialEq, Eq)]
50pub enum NearestRadius {
51 None,
53 Period,
55 Hour,
57 Minute,
59 Second,
61}
62
63#[must_use]
66pub fn circle_points(distance_radius: f32, center: Point, amount: u16) -> Vec<Point> {
67 let part = std::f32::consts::TAU / f32::from(amount);
68
69 let rotation =
70 |(x, y): (f32, f32), t: f32| (x * t.cos() - y * t.sin(), x * t.sin() + y * t.cos());
71
72 let points: Vec<(f32, f32)> = (0..amount).fold(Vec::new(), |mut v, i| {
73 v.push(rotation((0.0, -distance_radius), part * f32::from(i)));
74 v
75 });
76
77 let points: Vec<Point> = points
78 .iter()
79 .map(|p| Point::new(p.0 + center.x, p.1 + center.y))
80 .collect();
81
82 points
83}
84
85#[must_use]
90pub fn nearest_point(points: &[Point], cursor_position: Point) -> usize {
91 let mut distance_vec: Vec<(usize, f32)> = points
92 .iter()
93 .enumerate()
94 .map(|(i, p)| (i, p.distance(cursor_position)))
95 .collect();
96
97 distance_vec.sort_by(|a, b| a.1.partial_cmp(&b.1).expect("Should be comparable"));
98
99 distance_vec[0].0
100}
101
102#[must_use]
107pub fn nearest_radius(
108 radii: &[(f32, NearestRadius)],
109 cursor_position: Point,
110 center: Point,
111) -> NearestRadius {
112 let distance = cursor_position.distance(center);
113
114 let mut distance_vec: Vec<(f32, &NearestRadius)> = radii
115 .iter()
116 .map(|(r, n)| ((r - distance).abs(), n))
117 .collect();
118
119 distance_vec.sort_by(|a, b| a.0.partial_cmp(&b.0).expect("Should be comparable"));
120
121 distance_vec[0].1.clone()
122}
123
124#[cfg(test)]
125mod tests {
126 use iced_core::{Point, Vector};
127
128 use super::{NearestRadius, circle_points, nearest_point, nearest_radius};
129
130 #[test]
131 fn circle_points_test() {
132 let points = circle_points(10.0, Point::new(0.0, 0.0), 10);
133 let expected = vec![
134 Point { x: 0.0, y: -10.0 },
135 Point {
136 x: 5.877_852_4,
137 y: -8.09017,
138 },
139 Point {
140 x: 9.510_566,
141 y: -3.090_169_7,
142 },
143 Point {
144 x: 9.510_565,
145 y: 3.090_170_4,
146 },
147 Point {
148 x: 5.877_852,
149 y: 8.090_171,
150 },
151 Point {
152 x: -0.000_000_874_227_8,
153 y: 10.0,
154 },
155 Point {
156 x: -5.877_853_4,
157 y: 8.09017,
158 },
159 Point {
160 x: -9.510_565,
161 y: 3.090_170_9,
162 },
163 Point {
164 x: -9.510_565,
165 y: -3.090_171_3,
166 },
167 Point {
168 x: -5.877_849_6,
169 y: -8.090_173,
170 },
171 ];
172
173 assert_eq!(points, expected);
174 }
175
176 #[test]
177 fn nearest_radius_test() {
178 let radii = vec![
179 (10.0, NearestRadius::Period),
180 (20.0, NearestRadius::Hour),
181 (30.0, NearestRadius::Minute),
182 (40.0, NearestRadius::Second),
183 ];
184
185 let center = Point::new(0.0, 0.0);
186
187 let cursor_position = Point::new(5.0, 0.0);
188 let result = nearest_radius(&radii, cursor_position, center);
189 assert_eq!(result, NearestRadius::Period);
190
191 let cursor_position = Point::new(16.0, 0.0);
192 let result = nearest_radius(&radii, cursor_position, center);
193 assert_eq!(result, NearestRadius::Hour);
194
195 let cursor_position = Point::new(26.0, 0.0);
196 let result = nearest_radius(&radii, cursor_position, center);
197 assert_eq!(result, NearestRadius::Minute);
198
199 let cursor_position = Point::new(36.0, 0.0);
200 let result = nearest_radius(&radii, cursor_position, center);
201 assert_eq!(result, NearestRadius::Second);
202 }
203
204 #[test]
205 fn nearest_point_test() {
206 let points = circle_points(10.0, Point::new(0.0, 0.0), 10);
207
208 let mut index = 5;
209 let cursor_position = points[index] + Vector::new(1.0, -1.0);
210 let mut result = nearest_point(&points, cursor_position);
211 assert_eq!(index, result);
212
213 index = 0;
214 let cursor_position = points[index] + Vector::new(-1.0, 1.0);
215 result = nearest_point(&points, cursor_position);
216 assert_eq!(index, result);
217 }
218}