Skip to content

Commit

Permalink
Merge #22
Browse files Browse the repository at this point in the history
22: Implement Openstreetmap provider r=urschrei a=pjsier

Thanks for putting this library together! I took a stab at implementing an OpenStreetMap provider here since it was listed in #1 

I tried to follow the patterns from the OpenCage provider and used the builder pattern for specifying additional parameters, but I'm new to Rust so let me know if anything seems off. I'd like to use the `InputBounds` struct for the `viewport` parameter here, but wanted to check and see what the best way of restructuring that would be

Co-authored-by: pjsier <[email protected]>
  • Loading branch information
bors[bot] and pjsier authored Aug 20, 2019
2 parents db541d3 + 5eb1dc3 commit ce4c3a9
Show file tree
Hide file tree
Showing 3 changed files with 454 additions and 54 deletions.
52 changes: 52 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,10 @@ use serde::{Deserialize, Deserializer};
pub mod opencage;
pub use crate::opencage::Opencage;

// The OpenStreetMap Nominatim geocoding provider
pub mod openstreetmap;
pub use crate::openstreetmap::Openstreetmap;

/// Reverse-geocode a coordinate.
///
/// This trait represents the most simple and minimal implementation
Expand Down Expand Up @@ -84,3 +88,51 @@ where
// data. Please pay attention when using returned data to construct Points
fn forward(&self, address: &str) -> Result<Vec<Point<T>>, Error>;
}

/// Used to specify a bounding box to search within when forward-geocoding
///
/// - `minimum` refers to the **bottom-left** or **south-west** corner of the bounding box
/// - `maximum` refers to the **top-right** or **north-east** corner of the bounding box.
#[derive(Copy, Clone, Debug)]
pub struct InputBounds<T>
where
T: Float,
{
pub minimum_lonlat: Point<T>,
pub maximum_lonlat: Point<T>,
}

impl<T> InputBounds<T>
where
T: Float,
{
/// Create a new `InputBounds` struct by passing 2 `Point`s defining:
/// - minimum (bottom-left) longitude and latitude coordinates
/// - maximum (top-right) longitude and latitude coordinates
pub fn new<U>(minimum_lonlat: U, maximum_lonlat: U) -> InputBounds<T>
where
U: Into<Point<T>>,
{
InputBounds {
minimum_lonlat: minimum_lonlat.into(),
maximum_lonlat: maximum_lonlat.into(),
}
}
}

/// Convert borrowed input bounds into the correct String representation
impl<T> From<InputBounds<T>> for String
where
T: Float,
{
fn from(ip: InputBounds<T>) -> String {
// Return in lon, lat order
format!(
"{},{},{},{}",
ip.minimum_lonlat.x().to_f64().unwrap().to_string(),
ip.minimum_lonlat.y().to_f64().unwrap().to_string(),
ip.maximum_lonlat.x().to_f64().unwrap().to_string(),
ip.maximum_lonlat.y().to_f64().unwrap().to_string()
)
}
}
59 changes: 5 additions & 54 deletions src/opencage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::chrono::naive::serde::ts_seconds::deserialize as from_ts;
use crate::chrono::NaiveDateTime;
use crate::Deserialize;
use crate::UA_STRING;
use crate::InputBounds;
use crate::{Client, HeaderMap, HeaderValue, USER_AGENT};
use crate::Point;
use crate::{Forward, Reverse};
Expand Down Expand Up @@ -166,8 +167,7 @@ impl Opencage {
/// # Examples
///
///```
/// use geocoding::{Opencage, Point};
/// use geocoding::opencage::InputBounds;
/// use geocoding::{Opencage, InputBounds, Point};
///
/// let oc = Opencage::new("dcdbf0d783374909b3debee728c7cc10".to_string());
/// let address = "UCL CASA";
Expand All @@ -185,8 +185,8 @@ impl Opencage {
///
/// ```
/// // You can pass NOBOX if you don't need bounds.
/// use geocoding::{Opencage, Point};
/// use geocoding::opencage::{InputBounds, NOBOX};
/// use geocoding::{Opencage, InputBounds, Point};
/// use geocoding::opencage::{NOBOX};
/// let oc = Opencage::new("dcdbf0d783374909b3debee728c7cc10".to_string());
/// let address = "UCL CASA";
/// let res = oc.forward_full(&address, NOBOX).unwrap();
Expand All @@ -199,8 +199,7 @@ impl Opencage {
///
/// ```
/// // There are several ways to construct a Point, such as from a tuple
/// use geocoding::{Opencage, Point};
/// use geocoding::opencage::InputBounds;
/// use geocoding::{Opencage, InputBounds, Point};
/// let oc = Opencage::new("dcdbf0d783374909b3debee728c7cc10".to_string());
/// let address = "UCL CASA";
/// let bbox = InputBounds::new(
Expand Down Expand Up @@ -583,54 +582,6 @@ where
pub southwest: HashMap<String, T>,
}

/// Used to specify a bounding box to search within when forward-geocoding
///
/// - `minimum` refers to the **bottom-left** or **south-west** corner of the bounding box
/// - `maximum` refers to the **top-right** or **north-east** corner of the bounding box.
#[derive(Copy, Clone, Debug)]
pub struct InputBounds<T>
where
T: Float,
{
pub minimum_lonlat: Point<T>,
pub maximum_lonlat: Point<T>,
}

impl<T> InputBounds<T>
where
T: Float,
{
/// Create a new `InputBounds` struct by passing 2 `Point`s defining:
/// - minimum (bottom-left) longitude and latitude coordinates
/// - maximum (top-right) longitude and latitude coordinates
pub fn new<U>(minimum_lonlat: U, maximum_lonlat: U) -> InputBounds<T>
where
U: Into<Point<T>>,
{
InputBounds {
minimum_lonlat: minimum_lonlat.into(),
maximum_lonlat: maximum_lonlat.into(),
}
}
}

/// Convert borrowed input bounds into the correct String representation
impl<T> From<InputBounds<T>> for String
where
T: Float,
{
fn from(ip: InputBounds<T>) -> String {
// OpenCage expects lon, lat order here, for some reason
format!(
"{},{},{},{}",
ip.minimum_lonlat.x().to_f64().unwrap().to_string(),
ip.minimum_lonlat.y().to_f64().unwrap().to_string(),
ip.maximum_lonlat.x().to_f64().unwrap().to_string(),
ip.maximum_lonlat.y().to_f64().unwrap().to_string()
)
}
}

#[cfg(test)]
mod test {
use super::*;
Expand Down
Loading

0 comments on commit ce4c3a9

Please sign in to comment.