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
use crate::polygon_features;

/// Returns true if the given way is an area according to [Overpass turbo](https://wiki.openstreetmap.org/wiki/Overpass_turbo/Polygon_Features)
///
/// ```
/// use osm_is_area;
///
/// let tags = vec![
///  (r"waterway", r"riverbank")
/// ];
/// let refs = vec![1, 3, 2, 1];
///
/// let is_area = osm_is_area::way(&tags, &refs);
///
/// assert_eq!(true, is_area);
/// ```
///
pub fn way<X>(tags: &[(&str, &str)], refs: &[X]) -> bool where X: PartialEq {
    let features = &polygon_features::get_polygon_features();

    if refs.len() < 3 {
        return false;
    }

    if tags.len() == 0 {
        return false;
    }

    let mut refs_iter = refs.into_iter();
    let first = refs_iter.next();
    let last = refs_iter.last();

    // A way is considered an area if
    // 1. It forms a closed loop
    if first == last {
        // 2. It is not tagged `area=no`
        let opt = tags
            .into_iter()
            .find(|tag| tag.0 == "area" && tag.1 == "no");

        match opt {
            Some(_) => {
                return false;
            }
            None => {
                // 3. At least one of the following conditions is true
                let mut is_area = false;
                tags.into_iter().for_each(|tag| {
                    let key = tag.0;
                    let value = tag.1;

                    let mut iter = features
                        .into_iter()
                        .filter(|condition| condition.key == key);

                    let maybe_condition = iter.next();
                    if maybe_condition.is_some() {
                        let condition = maybe_condition.unwrap();
                        if condition.polygon == "all" && value != "no" {
                            is_area = true
                        }
                        if condition.polygon == "whitelist" {
                            let whitelist = &condition.values;
                            whitelist.into_iter().for_each(|val| {
                                if &value == val {
                                    is_area = true
                                }
                            });
                        }
                        if condition.polygon == "blacklist" {
                            is_area = true;
                            if key == "natural" && value == "coastline" {
                                is_area = true;
                            } else {
                                let blacklist = &condition.values;
                                blacklist.into_iter().for_each(|val| {
                                    if &value == val {
                                        is_area = false
                                    }
                                });
                            }
                        }
                    }
                });
                return is_area;
            }
        }
    }

    return false;
}