logo
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
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
use crate::search::*;
use serde::Serialize;

/// Strategies to verify the correctness of coordinates
#[derive(Debug, PartialEq, Clone, Serialize)]
#[serde(rename_all = "SCREAMING_SNAKE_CASE")]
pub enum ValidationMethod {
    /// accept geo points with invalid latitude or longitude
    IgnoreMalformed,

    /// try to infer correct latitude or longitude
    Coerce,

    /// strict mode
    Strict,
}

/// Different representations of geo bounding box
#[derive(Debug, PartialEq, Clone, Serialize)]
#[serde(untagged)]
pub enum GeoBoundingBox {
    /// MainDiagonal vertices of geo bounding box
    MainDiagonal {
        /// The coordinates of the upper left vertex
        top_left: GeoPoint,
        /// The coordinates of the lower right vertex
        bottom_right: GeoPoint,
    },

    /// SubDiagonal vertices of geo bounding box
    SubDiagonal {
        /// The coordinates of the upper right vertex
        top_right: GeoPoint,
        /// The coordinates of the lower left vertex
        bottom_left: GeoPoint,
    },

    /// Well-Known Text (WKT).
    WellKnownText {
        /// e.g. `BBOX (-74.1, -71.12, 40.73, 40.01)`
        wkt: String,
    },

    /// The vertices of the bounding box can either be set by `top_left` and `bottom_right` or by
    /// `top_right` and `bottom_left` parameters. More over the names `topLeft`, `bottomRight`, `topRight`
    /// and `bottomLeft` are supported. Instead of setting the values pairwise, one can use the simple
    /// names `top`, `left`, `bottom` and `right` to set the values separately.
    Vertices {
        /// Set top separately
        top: f32,
        /// Set left separately
        left: f32,
        /// Set bottom separately
        bottom: f32,
        /// Set right separately
        right: f32,
    },
}

/// Strategies to compute the distance
#[derive(Debug, PartialEq, Clone, Serialize)]
#[serde(rename_all = "snake_case")]
pub enum DistanceType {
    /// Accurate (default)
    Arc,
    /// Faster, but inaccurate on long distances and close to the poles
    Plane,
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::util::*;

    #[test]
    fn serialization() {
        assert_serialize(
            GeoBoundingBox::MainDiagonal {
                top_left: GeoPoint::Coordinates {
                    longitude: -74.1,
                    latitude: 40.73,
                },
                bottom_right: GeoPoint::Coordinates {
                    longitude: -71.12,
                    latitude: 40.01,
                },
            },
            json!({
                "top_left": [-74.1, 40.73],
                "bottom_right": [-71.12, 40.01]
            }),
        );

        assert_serialize(
            GeoBoundingBox::SubDiagonal {
                top_right: GeoPoint::Geohash("dr5r9ydj2y73".into()),
                bottom_left: GeoPoint::Geohash("drj7teegpus6".into()),
            },
            json!({
                "top_right": "dr5r9ydj2y73",
            "bottom_left": "drj7teegpus6"
            }),
        );

        assert_serialize(
            GeoBoundingBox::WellKnownText {
                wkt: "BBOX (-74.1, -71.12, 40.73, 40.01)".into(),
            },
            json!({
                "wkt": "BBOX (-74.1, -71.12, 40.73, 40.01)"
            }),
        );

        assert_serialize(
            GeoBoundingBox::Vertices {
                top: 40.73,
                left: -74.1,
                bottom: 40.01,
                right: -71.12,
            },
            json!({
                "top": 40.73,
                "left": -74.1,
                "bottom": 40.01,
                "right": -71.12
            }),
        );

        assert_serialize(
            [DistanceType::Arc, DistanceType::Plane],
            json!(["arc", "plane"]),
        );
    }
}