1use egui::{Painter, Pos2, Response};
4use std::any::Any;
5
6use crate::projection::MapProjection;
7
8#[cfg(feature = "geojson")]
10pub mod geojson;
11
12#[cfg(feature = "drawing-layer")]
14pub mod drawing;
15
16#[cfg(feature = "text-layer")]
18pub mod text;
19
20#[cfg(feature = "svg-layer")]
22pub mod svg;
23
24#[cfg(feature = "area-layer")]
26pub mod area;
27
28#[cfg(feature = "tile-layer")]
30pub mod tile;
31
32pub(crate) mod serde_color32 {
34 use egui::Color32;
35 use serde::{self, Deserialize, Deserializer, Serializer};
36
37 pub fn serialize<S>(color: &Color32, serializer: S) -> Result<S::Ok, S::Error>
39 where
40 S: Serializer,
41 {
42 serializer.serialize_str(&color.to_hex())
43 }
44
45 pub fn deserialize<'de, D>(deserializer: D) -> Result<Color32, D::Error>
47 where
48 D: Deserializer<'de>,
49 {
50 let s = <String as Deserialize>::deserialize(deserializer)?;
51 Color32::from_hex(&s).map_err(|err| serde::de::Error::custom(format!("{err:?}")))
52 }
53}
54
55pub(crate) mod serde_stroke {
57 use crate::layers::serde_color32;
58 use egui::{Color32, Stroke};
59 use serde::{self, Deserialize, Deserializer, Serialize, Serializer};
60
61 #[derive(Serialize, Deserialize)]
62 struct StrokeHelper {
63 width: f32,
64 #[serde(with = "serde_color32")]
65 color: Color32,
66 }
67
68 pub fn serialize<S>(stroke: &Stroke, serializer: S) -> Result<S::Ok, S::Error>
69 where
70 S: Serializer,
71 {
72 let helper = StrokeHelper {
73 width: stroke.width,
74 color: stroke.color,
75 };
76 helper.serialize(serializer)
77 }
78
79 pub fn deserialize<'de, D>(deserializer: D) -> Result<Stroke, D::Error>
80 where
81 D: Deserializer<'de>,
82 {
83 let helper = StrokeHelper::deserialize(deserializer)?;
84 Ok(Stroke {
85 width: helper.width,
86 color: helper.color,
87 })
88 }
89}
90
91pub trait Layer: Any {
93 fn handle_input(&mut self, response: &Response, projection: &MapProjection) -> bool;
96
97 fn draw(&self, painter: &Painter, projection: &MapProjection);
99
100 fn as_any(&self) -> &dyn Any;
102
103 fn as_any_mut(&mut self) -> &mut dyn Any;
105
106 fn opacity(&self) -> f32 {
108 1.0
109 }
110
111 fn set_opacity(&mut self, _opacity: f32) {}
113}
114
115pub fn default_opacity() -> f32 {
117 1.0
118}
119
120pub(crate) fn dist_sq_to_segment(p: Pos2, a: Pos2, b: Pos2) -> f32 {
122 let ab = b - a;
123 let ap = p - a;
124 let l2 = ab.length_sq();
125
126 if l2 == 0.0 {
127 return ap.length_sq();
129 }
130
131 let t = (ap.dot(ab) / l2).clamp(0.0, 1.0);
134
135 let closest_point = a + t * ab;
137
138 p.distance_sq(closest_point)
139}
140
141pub(crate) fn projection_factor(p: Pos2, a: Pos2, b: Pos2) -> f32 {
144 let ab = b - a;
145 let ap = p - a;
146 let l2 = ab.length_sq();
147
148 if l2 == 0.0 {
149 return 0.0;
150 }
151
152 (ap.dot(ab) / l2).clamp(0.0, 1.0)
154}
155
156pub(crate) fn segments_intersect(p1: Pos2, q1: Pos2, p2: Pos2, q2: Pos2) -> bool {
158 fn orientation(p: Pos2, q: Pos2, r: Pos2) -> i8 {
159 let val = (q.y - p.y) * (r.x - q.x) - (q.x - p.x) * (r.y - q.y);
160 if val.abs() < 1e-6 {
161 0 } else if val > 0.0 {
163 1 } else {
165 -1 }
167 }
168
169 let o1 = orientation(p1, q1, p2);
170 let o2 = orientation(p1, q1, q2);
171 let o3 = orientation(p2, q2, p1);
172 let o4 = orientation(p2, q2, q1);
173
174 if o1 != o2 && o3 != o4 {
176 return true;
177 }
178
179 false
182}
183
184#[cfg(test)]
185mod tests {
186 use super::*;
187 use egui::pos2;
188
189 const EPSILON: f32 = 1e-6;
190
191 #[test]
192 fn test_dist_sq_to_segment() {
193 let a = pos2(0.0, 0.0);
194 let b = pos2(10.0, 0.0);
195
196 let p1 = pos2(5.0, 0.0);
198 assert!((dist_sq_to_segment(p1, a, b) - 0.0).abs() < EPSILON);
199
200 let p2 = pos2(5.0, 5.0);
202 assert!((dist_sq_to_segment(p2, a, b) - 25.0).abs() < EPSILON); let p3 = pos2(-5.0, 5.0);
206 assert!((dist_sq_to_segment(p3, a, b) - 50.0).abs() < EPSILON); let p4 = pos2(15.0, 5.0);
210 assert!((dist_sq_to_segment(p4, a, b) - 50.0).abs() < EPSILON); let c = pos2(5.0, 5.0);
214 let p5 = pos2(10.0, 10.0);
215 assert!((dist_sq_to_segment(p5, c, c) - 50.0).abs() < EPSILON); }
217
218 #[test]
219 fn test_layer_opacity_defaults() {
220 struct MockLayer;
221 impl Layer for MockLayer {
222 fn handle_input(&mut self, _: &Response, _: &MapProjection) -> bool {
223 false
224 }
225 fn draw(&self, _: &Painter, _: &MapProjection) {}
226 fn as_any(&self) -> &dyn Any {
227 self
228 }
229 fn as_any_mut(&mut self) -> &mut dyn Any {
230 self
231 }
232 }
233
234 let mut layer = MockLayer;
235 assert_eq!(layer.opacity(), 1.0);
236 layer.set_opacity(0.5);
237 assert_eq!(layer.opacity(), 1.0);
239 }
240
241 #[test]
242 fn test_projection_factor() {
243 let a = pos2(0.0, 0.0);
244 let b = pos2(10.0, 0.0);
245
246 assert!((projection_factor(a, a, b) - 0.0).abs() < EPSILON);
248
249 assert!((projection_factor(b, a, b) - 1.0).abs() < EPSILON);
251
252 let p1 = pos2(5.0, 0.0);
254 assert!((projection_factor(p1, a, b) - 0.5).abs() < EPSILON);
255
256 let p2 = pos2(5.0, 5.0);
258 assert!((projection_factor(p2, a, b) - 0.5).abs() < EPSILON);
259
260 let p3 = pos2(-5.0, 5.0);
262 assert!((projection_factor(p3, a, b) - 0.0).abs() < EPSILON);
263
264 let p4 = pos2(15.0, 5.0);
266 assert!((projection_factor(p4, a, b) - 1.0).abs() < EPSILON);
267
268 let c = pos2(5.0, 5.0);
270 let p5 = pos2(10.0, 10.0);
271 assert!((projection_factor(p5, c, c) - 0.0).abs() < EPSILON);
272 }
273
274 #[test]
275 fn test_segments_intersect() {
276 let p1 = pos2(0.0, 0.0);
278 let q1 = pos2(10.0, 10.0);
279 let p2 = pos2(0.0, 10.0);
280 let q2 = pos2(10.0, 0.0);
281 assert!(segments_intersect(p1, q1, p2, q2), "General intersection");
282
283 let p1 = pos2(0.0, 0.0);
285 let q1 = pos2(10.0, 0.0);
286 let p2 = pos2(0.0, 5.0);
287 let q2 = pos2(10.0, 5.0);
288 assert!(
289 !segments_intersect(p1, q1, p2, q2),
290 "Parallel, no intersection"
291 );
292
293 let p1 = pos2(0.0, 0.0);
295 let q1 = pos2(1.0, 1.0);
296 let p2 = pos2(2.0, 2.0);
297 let q2 = pos2(3.0, 0.0);
298 assert!(
299 !segments_intersect(p1, q1, p2, q2),
300 "Not parallel, no intersection"
301 );
302
303 let p1 = pos2(0.0, 5.0);
305 let q1 = pos2(10.0, 5.0);
306 let p2 = pos2(5.0, 0.0);
307 let q2 = pos2(5.0, 5.0);
308 assert!(segments_intersect(p1, q1, p2, q2), "T-junction");
309
310 let p1 = pos2(0.0, 0.0);
312 let q1 = pos2(5.0, 5.0);
313 let p2 = pos2(5.0, 5.0);
314 let q2 = pos2(10.0, 0.0);
315 assert!(segments_intersect(p1, q1, p2, q2), "Meeting at an endpoint");
316
317 let p1 = pos2(0.0, 0.0);
319 let q1 = pos2(10.0, 0.0);
320 let p2 = pos2(5.0, 0.0);
321 let q2 = pos2(15.0, 0.0);
322 assert!(
323 !segments_intersect(p1, q1, p2, q2),
324 "Collinear, overlapping"
325 );
326
327 let p1 = pos2(0.0, 0.0);
329 let q1 = pos2(10.0, 0.0);
330 let p2 = pos2(11.0, 0.0);
331 let q2 = pos2(20.0, 0.0);
332 assert!(
333 !segments_intersect(p1, q1, p2, q2),
334 "Collinear, non-overlapping"
335 );
336
337 let p1 = pos2(0.0, 0.0);
339 let q1 = pos2(10.0, 0.0);
340 let p2 = pos2(2.0, 0.0);
341 let q2 = pos2(8.0, 0.0);
342 assert!(!segments_intersect(p1, q1, p2, q2), "Collinear, contained");
343
344 let p1 = pos2(0.0, 0.0);
346 let q1 = pos2(10.0, 0.0);
347 let p2 = pos2(5.0, 0.0);
348 let q2 = pos2(5.0, 0.0);
349 assert!(!segments_intersect(p1, q1, p2, q2), "Point on segment");
350 }
351}