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
use geom::{Distance, PolyLine, Polygon, Pt2D, Ring};

use crate::{Color, EventCtx, GfxCtx};

// TODO This is horrifically slow / memory inefficient. Reference implementation somewhere?

/// Draw freehand polygons
pub struct Lasso {
    points: Vec<Pt2D>,
    polygon: Option<Polygon>,
    threshold: Distance,
}

impl Lasso {
    /// How far do points need to be spaced apart to add?
    pub fn new(threshold: Distance) -> Self {
        Self {
            points: Vec::new(),
            polygon: None,
            threshold,
        }
    }

    /// When this returns a polygon, the interaction is finished
    pub fn event(&mut self, ctx: &mut EventCtx) -> Option<Polygon> {
        if self.points.is_empty() {
            if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
                if ctx.input.left_mouse_button_pressed() {
                    self.points.push(pt);
                }
            }
            return None;
        }

        if ctx.input.left_mouse_button_released() {
            return self.polygon.take();
        }

        if ctx.redo_mouseover() {
            if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
                if self.points.last().as_ref().unwrap().dist_to(pt) > self.threshold {
                    self.points.push(pt);

                    // TODO It's better if the user doesn't close the polygon themselves. When they
                    // try to, usually the result is the smaller polygon chunk
                    let mut copy = self.points.clone();
                    copy.push(copy[0]);
                    self.polygon = Ring::new(copy).ok().map(|ring| ring.into_polygon());
                }
            }
        }
        None
    }

    pub fn draw(&self, g: &mut GfxCtx) {
        if let Ok(pl) = PolyLine::new(self.points.clone()) {
            g.draw_polygon(
                Color::RED.alpha(0.8),
                pl.make_polygons(Distance::meters(5.0) / g.canvas.cam_zoom),
            );
        }
        if let Some(ref polygon) = self.polygon {
            g.draw_polygon(Color::RED.alpha(0.5), polygon.clone());
        }
    }
}

/// Draw freehand PolyLine
pub struct PolyLineLasso {
    pl: Option<PolyLine>,
}

impl PolyLineLasso {
    pub fn new() -> Self {
        Self { pl: None }
    }

    /// When this returns a polyline, the interaction is finished
    pub fn event(&mut self, ctx: &mut EventCtx) -> Option<PolyLine> {
        if self.pl.is_none() {
            if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
                if ctx.input.left_mouse_button_pressed() {
                    self.pl = Some(PolyLine::must_new(vec![pt, pt.offset(0.1, 0.1)]));
                }
            }
            return None;
        }

        if ctx.input.left_mouse_button_released() {
            return self.pl.take();
        }

        if ctx.redo_mouseover() {
            if let Some(pt) = ctx.canvas.get_cursor_in_map_space() {
                let pl = self.pl.take().unwrap();
                self.pl = Some(pl.optionally_push(pt));
            }
        }
        None
    }

    pub fn draw(&self, g: &mut GfxCtx) {
        if let Some(ref pl) = self.pl {
            g.draw_polygon(
                Color::RED.alpha(0.8),
                pl.make_polygons(Distance::meters(5.0) / g.canvas.cam_zoom),
            );
        }
    }
}