1use crate::layers::{Layer, dist_sq_to_segment, projection_factor, serde_stroke};
33use crate::projection::{GeoPos, MapProjection};
34use egui::{Color32, Painter, Pos2, Response, Stroke};
35use serde::{Deserialize, Serialize};
36use std::any::Any;
37
38#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
40pub struct Polyline(pub Vec<GeoPos>);
41
42#[derive(Clone, Copy, Debug, Default, PartialEq, Eq, Serialize, Deserialize)]
44pub enum DrawMode {
45 #[default]
47 Disabled,
48 Draw,
50 Erase,
52}
53
54#[derive(Clone, Serialize, Deserialize)]
56#[serde(default)]
57pub struct DrawingLayer {
58 polylines: Vec<Polyline>,
59
60 #[serde(with = "serde_stroke")]
62 pub stroke: Stroke,
63
64 #[serde(skip)]
66 pub draw_mode: DrawMode,
67}
68
69impl DrawingLayer {
70 #[cfg(feature = "geojson")]
72 #[cfg(feature = "geojson")]
74 pub fn to_geojson_str(&self, layer_id: &str) -> Result<String, serde_json::Error> {
75 let features: Vec<geojson::Feature> = self
76 .polylines
77 .clone()
78 .into_iter()
79 .map(|p| {
80 let mut feature = geojson::Feature::from(p);
81 if let Some(properties) = &mut feature.properties {
82 properties.insert(
83 "stroke_width".to_string(),
84 serde_json::Value::from(self.stroke.width),
85 );
86 properties.insert(
87 "stroke_color".to_string(),
88 serde_json::Value::String(self.stroke.color.to_hex()),
89 );
90 properties.insert(
91 "layer_id".to_string(),
92 serde_json::Value::String(layer_id.to_string()),
93 );
94 }
95 feature
96 })
97 .collect();
98
99 let mut foreign_members = serde_json::Map::new();
100 foreign_members.insert(
101 "stroke_width".to_string(),
102 serde_json::Value::from(self.stroke.width),
103 );
104 foreign_members.insert(
105 "stroke_color".to_string(),
106 serde_json::Value::String(self.stroke.color.to_hex()),
107 );
108 foreign_members.insert(
109 "layer_id".to_string(),
110 serde_json::Value::String(layer_id.to_string()),
111 );
112
113 let feature_collection = geojson::FeatureCollection {
114 bbox: None,
115 features,
116 foreign_members: Some(foreign_members),
117 };
118 serde_json::to_string(&feature_collection)
119 }
120
121 #[cfg(feature = "geojson")]
126 pub fn from_geojson_str(
127 &mut self,
128 s: &str,
129 layer_id: Option<&str>,
130 ) -> Result<(), serde_json::Error> {
131 let feature_collection: geojson::FeatureCollection = serde_json::from_str(s)?;
132 let new_polylines: Vec<Polyline> = feature_collection
133 .features
134 .iter()
135 .filter_map(|f| {
136 if let Some(target_id) = layer_id {
138 if let Some(properties) = &f.properties {
139 if let Some(val) = properties.get("layer_id") {
140 if let Some(id) = val.as_str() {
141 if id != target_id {
142 return None;
143 }
144 } else {
145 return None;
147 }
148 } else {
149 return None;
151 }
152 } else {
153 return None;
155 }
156 }
157
158 let polyline = Polyline::try_from(f.clone()).ok();
159 if polyline.is_some() {
160 if let Some(properties) = &f.properties {
161 if let Some(value) = properties.get("stroke_width") {
162 if let Some(width) = value.as_f64() {
163 self.stroke.width = width as f32;
164 }
165 }
166 if let Some(value) = properties.get("stroke_color") {
167 if let Some(s) = value.as_str() {
168 if let Ok(color) = Color32::from_hex(s) {
169 self.stroke.color = color;
170 }
171 }
172 }
173 }
174 }
175 polyline
176 })
177 .collect();
178 self.polylines.extend(new_polylines);
179
180 if let Some(foreign_members) = feature_collection.foreign_members {
181 if let Some(value) = foreign_members.get("stroke_width") {
192 if let Some(width) = value.as_f64() {
193 self.stroke.width = width as f32;
194 }
195 }
196 if let Some(value) = foreign_members.get("stroke_color") {
197 if let Some(s) = value.as_str() {
198 if let Ok(color) = Color32::from_hex(s) {
199 self.stroke.color = color;
200 }
201 }
202 }
203 }
204
205 Ok(())
206 }
207
208 pub fn new(stroke: Stroke) -> Self {
210 Self {
211 polylines: Vec::new(),
212 stroke,
213 draw_mode: DrawMode::default(),
214 }
215 }
216}
217
218impl Default for DrawingLayer {
219 fn default() -> Self {
220 Self {
221 polylines: Vec::new(),
222 stroke: Stroke::new(2.0, Color32::RED),
223 draw_mode: DrawMode::default(),
224 }
225 }
226}
227
228impl DrawingLayer {
229 fn handle_draw_input(&mut self, response: &Response, projection: &MapProjection) -> bool {
230 if response.hovered() {
231 response.ctx.set_cursor_icon(egui::CursorIcon::Crosshair);
232 }
233
234 if response.clicked() {
235 if let Some(pointer_pos) = response.interact_pointer_pos() {
236 let geo_pos = projection.unproject(pointer_pos);
237 if let Some(last_line) = self.polylines.last_mut()
238 && response.ctx.input(|i| i.modifiers.shift)
239 {
240 last_line.0.push(geo_pos);
241 } else {
242 let geo_pos2 = projection.unproject(pointer_pos + egui::vec2(1.0, 0.0));
244 self.polylines.push(Polyline(vec![geo_pos, geo_pos2]));
245 }
246 }
247 }
248
249 if response.drag_started() {
250 self.polylines.push(Polyline(Vec::new()));
251 }
252
253 if response.dragged() {
254 if let Some(pointer_pos) = response.interact_pointer_pos() {
255 if let Some(last_line) = self.polylines.last_mut() {
256 let geo_pos = projection.unproject(pointer_pos);
257 last_line.0.push(geo_pos);
258 }
259 }
260 }
261
262 response.hovered()
265 }
266
267 fn handle_erase_input(&mut self, response: &Response, projection: &MapProjection) -> bool {
268 if response.hovered() {
269 response.ctx.set_cursor_icon(egui::CursorIcon::NotAllowed);
270 }
271
272 if response.dragged() || response.clicked() {
273 if let Some(pointer_pos) = response.interact_pointer_pos() {
274 self.erase_at(pointer_pos, projection);
275 }
276 }
277 response.hovered()
278 }
279
280 fn erase_at(&mut self, pointer_pos: Pos2, projection: &MapProjection) {
281 let erase_radius_screen = self.stroke.width;
282 let erase_radius_sq = erase_radius_screen * erase_radius_screen;
283
284 let old_polylines = std::mem::take(&mut self.polylines);
285 self.polylines = old_polylines
286 .into_iter()
287 .flat_map(|polyline| {
288 split_polyline_by_erase_circle(
289 &polyline.0,
290 pointer_pos,
291 erase_radius_sq,
292 projection,
293 )
294 .into_iter()
295 .map(Polyline)
296 })
297 .collect();
298 }
299}
300
301impl Layer for DrawingLayer {
302 fn as_any(&self) -> &dyn Any {
303 self
304 }
305
306 fn as_any_mut(&mut self) -> &mut dyn Any {
307 self
308 }
309
310 fn handle_input(&mut self, response: &Response, projection: &MapProjection) -> bool {
311 match self.draw_mode {
312 DrawMode::Disabled => false,
313 DrawMode::Draw => self.handle_draw_input(response, projection),
314 DrawMode::Erase => self.handle_erase_input(response, projection),
315 }
316 }
317
318 fn draw(&self, painter: &Painter, projection: &MapProjection) {
319 for polyline in &self.polylines {
320 if polyline.0.len() > 1 {
321 let screen_points: Vec<egui::Pos2> =
322 polyline.0.iter().map(|p| projection.project(*p)).collect();
323 painter.add(egui::Shape::line(screen_points, self.stroke));
324 }
325 }
326 }
327}
328
329fn split_polyline_by_erase_circle(
331 polyline: &[GeoPos],
332 pointer_pos: Pos2,
333 erase_radius_sq: f32,
334 projection: &MapProjection,
335) -> Vec<Vec<GeoPos>> {
336 if polyline.len() < 2 {
337 return vec![];
338 }
339
340 let screen_points: Vec<Pos2> = polyline.iter().map(|p| projection.project(*p)).collect();
341
342 let mut new_polylines = Vec::new();
343 let mut current_line = Vec::new();
344 let mut in_visible_part = true;
345
346 if dist_sq_to_segment(pointer_pos, screen_points[0], screen_points[1]) < erase_radius_sq {
348 in_visible_part = false;
349 } else {
350 current_line.push(polyline[0]);
351 }
352
353 for i in 0..(polyline.len() - 1) {
354 let p2_geo = polyline[i + 1];
355 let p1_screen = screen_points[i];
356 let p2_screen = screen_points[i + 1];
357
358 let segment_is_erased =
359 dist_sq_to_segment(pointer_pos, p1_screen, p2_screen) < erase_radius_sq;
360
361 if in_visible_part {
362 if segment_is_erased {
363 let t = projection_factor(pointer_pos, p1_screen, p2_screen);
365 let split_point_screen = p1_screen.lerp(p2_screen, t);
366 let split_point_geo = projection.unproject(split_point_screen);
367 current_line.push(split_point_geo);
368
369 if current_line.len() > 1 {
370 new_polylines.push(std::mem::take(&mut current_line));
371 }
372 in_visible_part = false;
373 } else {
374 current_line.push(p2_geo);
376 }
377 } else {
378 if !segment_is_erased {
380 let t = projection_factor(pointer_pos, p1_screen, p2_screen);
382 let split_point_screen = p1_screen.lerp(p2_screen, t);
383 let split_point_geo = projection.unproject(split_point_screen);
384
385 current_line.push(split_point_geo);
387 current_line.push(p2_geo);
388 in_visible_part = true;
389 }
390 }
392 }
393
394 if current_line.len() > 1 {
395 new_polylines.push(current_line);
396 }
397
398 new_polylines
399}
400
401#[cfg(test)]
402mod tests {
403 use super::*;
404
405 #[test]
406 fn drawing_layer_new() {
407 let layer = DrawingLayer::default();
408 assert_eq!(layer.draw_mode, DrawMode::Disabled);
409 assert!(layer.polylines.is_empty());
410 }
411
412 #[test]
413 fn drawing_layer_as_any() {
414 let layer = DrawingLayer::default();
415 assert!(layer.as_any().is::<DrawingLayer>());
416 }
417
418 #[test]
419 fn drawing_layer_as_any_mut() {
420 let mut layer = DrawingLayer::default();
421 assert!(layer.as_any_mut().is::<DrawingLayer>());
422 }
423
424 #[test]
425 fn drawing_layer_serde() {
426 let mut layer = DrawingLayer::default();
427 layer.draw_mode = DrawMode::Draw; layer.polylines.push(Polyline(vec![
429 GeoPos { lon: 1.0, lat: 2.0 },
430 GeoPos { lon: 3.0, lat: 4.0 },
431 ]));
432 layer.stroke = Stroke::new(5.0, Color32::BLUE); let json = serde_json::to_string(&layer).unwrap();
435
436 assert!(json.contains(r##""polylines":[[{"lon":1.0,"lat":2.0},{"lon":3.0,"lat":4.0}]],"stroke":{"width":5.0,"color":"#0000ffff"}"##));
438 assert!(!json.contains("draw_mode"));
439
440 let deserialized: DrawingLayer = serde_json::from_str(&json).unwrap();
441
442 assert_eq!(deserialized.polylines, layer.polylines);
444
445 assert_eq!(deserialized.stroke.width, 5.0);
447 assert_eq!(deserialized.stroke.color, Color32::BLUE);
448
449 assert_eq!(deserialized.draw_mode, DrawMode::Disabled);
451 }
452
453 #[cfg(feature = "geojson")]
454 mod geojson_tests {
455 use super::*;
456
457 #[test]
458 fn drawing_layer_geojson() {
459 let mut layer = DrawingLayer::default();
460 layer.polylines.push(Polyline(vec![
461 (10.0, 20.0).into(),
462 (30.0, 40.0).into(),
463 (50.0, 60.0).into(),
464 ]));
465 layer.stroke = Stroke::new(5.0, Color32::BLUE);
466
467 let geojson_str = layer.to_geojson_str("my_layer").unwrap();
468
469 let mut new_layer = DrawingLayer::default();
471 new_layer
472 .from_geojson_str(&geojson_str, Some("my_layer"))
473 .unwrap();
474
475 assert_eq!(new_layer.polylines.len(), 1);
476 assert_eq!(layer.polylines[0], new_layer.polylines[0]);
477 assert_eq!(layer.stroke, new_layer.stroke);
478
479 let mut other_layer = DrawingLayer::default();
481 other_layer
482 .from_geojson_str(&geojson_str, Some("other_layer"))
483 .unwrap();
484 assert_eq!(other_layer.polylines.len(), 0);
485
486 let mut all_layer = DrawingLayer::default();
488 all_layer.from_geojson_str(&geojson_str, None).unwrap();
489 assert_eq!(all_layer.polylines.len(), 1);
490 }
491 }
492}