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
use crate::GeoPoint;
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 crate::{DistanceType, GeoBoundingBox, GeoPoint};

    test_serialization! {
        serializes_as_geo_bounding_box_geopoint(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]
        }));

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

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

        serializes_as_geo_bounding_box_vertices(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
        }));

        serializes_as_distance_type_arc(
            DistanceType::Arc,
            json!("arc")
        );

        serializes_as_distance_type_plane(
            DistanceType::Plane,
            json!("plane")
        );
    }
}