More work on spatial coordinate converter
This commit is contained in:
parent
f587b15372
commit
23d48b2a7b
@ -20,6 +20,10 @@ In order of dependency, the role of each of these directories in this repository
|
||||
|Asciidoctor documentation
|
||||
|Design decisions and algorithm definition documentation
|
||||
|
||||
|spatial-coordinate-systems
|
||||
|Rust Crate
|
||||
|Convert among latitude/longitude (DD), degree-minute (DM), degree-minute-second (DMS), UTM, and Pluscodes
|
||||
|
||||
|wordlist
|
||||
|Python/CSV
|
||||
|Wordlist sources and generator code
|
||||
|
30
spatial-coordinate-systems/src/dd.rs
Normal file
30
spatial-coordinate-systems/src/dd.rs
Normal file
@ -0,0 +1,30 @@
|
||||
use crate::{
|
||||
common::{optional_separator, parse_direction},
|
||||
Direction,
|
||||
};
|
||||
use nom::{
|
||||
branch::alt,
|
||||
character::complete::{self, space0, space1},
|
||||
combinator::{eof, map, map_opt, map_res, opt},
|
||||
number::complete::double,
|
||||
sequence::{pair, tuple},
|
||||
IResult,
|
||||
};
|
||||
use std::str::FromStr;
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Coordinate(pub f64, pub f64);
|
||||
|
||||
pub fn parse_coordinate(i: &str) -> IResult<&str, Coordinate> {
|
||||
map_opt(
|
||||
tuple((double, optional_separator(','), double)),
|
||||
|(ns, _, ew)| {
|
||||
// Ensure this is a north/south then east/west direction
|
||||
if (-90_f64..=90_f64).contains(&ns) && (-180_f64..=180_f64).contains(&ew) {
|
||||
Some(Coordinate(ns, ew))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
},
|
||||
)(i)
|
||||
}
|
@ -12,13 +12,23 @@ use nom::{
|
||||
};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn parse_coordinate(i: &str) -> IResult<&str, (DegreeMinute, DegreeMinute)> {
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Coordinate(pub DM, pub DM);
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct DM {
|
||||
pub degrees: i16,
|
||||
pub minutes: f64,
|
||||
pub direction: Direction,
|
||||
}
|
||||
|
||||
pub fn parse_coordinate(i: &str) -> IResult<&str, Coordinate> {
|
||||
map_opt(
|
||||
tuple((parse, optional_separator(','), parse)),
|
||||
|(ns, _, ew)| {
|
||||
// Ensure this is a north/south then east/west direction
|
||||
if ns.direction.is_lat() && ew.direction.is_lon() {
|
||||
Some((ns, ew))
|
||||
Some(Coordinate(ns, ew))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -26,7 +36,7 @@ pub fn parse_coordinate(i: &str) -> IResult<&str, (DegreeMinute, DegreeMinute)>
|
||||
)(i)
|
||||
}
|
||||
|
||||
pub fn parse(i: &str) -> IResult<&str, DegreeMinute> {
|
||||
pub fn parse(i: &str) -> IResult<&str, DM> {
|
||||
map(
|
||||
tuple((
|
||||
// Degrees
|
||||
@ -38,7 +48,7 @@ pub fn parse(i: &str) -> IResult<&str, DegreeMinute> {
|
||||
// Direction
|
||||
parse_direction,
|
||||
)),
|
||||
|(degrees, (), minutes, (), direction)| DegreeMinute {
|
||||
|(degrees, (), minutes, (), direction)| DM {
|
||||
degrees,
|
||||
minutes,
|
||||
direction,
|
||||
@ -46,14 +56,7 @@ pub fn parse(i: &str) -> IResult<&str, DegreeMinute> {
|
||||
)(i)
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct DegreeMinute {
|
||||
pub degrees: i16,
|
||||
pub minutes: f64,
|
||||
pub direction: Direction,
|
||||
}
|
||||
|
||||
impl FromStr for DegreeMinute {
|
||||
impl FromStr for DM {
|
||||
type Err = ();
|
||||
|
||||
/// Recognizes DMS in the formats:
|
||||
@ -62,43 +65,22 @@ impl FromStr for DegreeMinute {
|
||||
/// * `40 31 21 N, 105 5 39 W`
|
||||
///
|
||||
/// ```rust
|
||||
/// use spatial_coordinate_systems::dm::DegreeMinute;
|
||||
/// use spatial_coordinate_systems::dm::DM;
|
||||
/// use spatial_coordinate_systems::Direction;
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// assert_eq!(DegreeMinute::from_str("40 31.3 N").unwrap(), DegreeMinute {
|
||||
/// assert_eq!(DM::from_str("40 31.3 N").unwrap(), DM {
|
||||
/// degrees: 40,
|
||||
/// minutes: 31.3_f64,
|
||||
/// direction: Direction::North,
|
||||
/// });
|
||||
/// assert_eq!(DegreeMinute::from_str("40°31' N").unwrap(), DegreeMinute {
|
||||
/// assert_eq!(DM::from_str("40°31' N").unwrap(), DM {
|
||||
/// degrees: 40,
|
||||
/// minutes: 31_f64,
|
||||
/// direction: Direction::North,
|
||||
/// });
|
||||
/// ```
|
||||
fn from_str(i: &str) -> Result<Self, Self::Err> {
|
||||
map(
|
||||
tuple((
|
||||
space0,
|
||||
// Degrees
|
||||
complete::i16,
|
||||
optional_separator('°'),
|
||||
// Minutes
|
||||
double,
|
||||
optional_separator('\''),
|
||||
// Direction
|
||||
parse_direction,
|
||||
// Ensure no other characters can be read
|
||||
eof,
|
||||
)),
|
||||
|(_, degrees, (), minutes, (), direction, _)| DegreeMinute {
|
||||
degrees,
|
||||
minutes,
|
||||
direction,
|
||||
},
|
||||
)(i)
|
||||
.map_err(|_| ())
|
||||
.map(|(_, ret)| ret)
|
||||
parse(i).map_err(|_| ()).map(|(_, ret)| ret)
|
||||
}
|
||||
}
|
||||
|
@ -12,13 +12,16 @@ use nom::{
|
||||
};
|
||||
use std::str::FromStr;
|
||||
|
||||
pub fn parse_coordinate(i: &str) -> IResult<&str, (DegreeMinuteSecond, DegreeMinuteSecond)> {
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct Coordinate(pub DMS, pub DMS);
|
||||
|
||||
pub fn parse_coordinate(i: &str) -> IResult<&str, Coordinate> {
|
||||
map_opt(
|
||||
tuple((parse, optional_separator(','), parse)),
|
||||
|(ns, _, ew)| {
|
||||
// Ensure this is a north/south then east/west direction
|
||||
if ns.direction.is_lat() && ew.direction.is_lon() {
|
||||
Some((ns, ew))
|
||||
Some(Coordinate(ns, ew))
|
||||
} else {
|
||||
None
|
||||
}
|
||||
@ -26,7 +29,7 @@ pub fn parse_coordinate(i: &str) -> IResult<&str, (DegreeMinuteSecond, DegreeMin
|
||||
)(i)
|
||||
}
|
||||
|
||||
pub fn parse(i: &str) -> IResult<&str, DegreeMinuteSecond> {
|
||||
pub fn parse(i: &str) -> IResult<&str, DMS> {
|
||||
map(
|
||||
tuple((
|
||||
// Degrees
|
||||
@ -41,7 +44,7 @@ pub fn parse(i: &str) -> IResult<&str, DegreeMinuteSecond> {
|
||||
// Direction
|
||||
parse_direction,
|
||||
)),
|
||||
|(degrees, (), minutes, (), seconds, (), direction)| DegreeMinuteSecond {
|
||||
|(degrees, (), minutes, (), seconds, (), direction)| DMS {
|
||||
degrees,
|
||||
minutes,
|
||||
seconds,
|
||||
@ -51,14 +54,14 @@ pub fn parse(i: &str) -> IResult<&str, DegreeMinuteSecond> {
|
||||
}
|
||||
|
||||
#[derive(PartialEq, Debug)]
|
||||
pub struct DegreeMinuteSecond {
|
||||
pub struct DMS {
|
||||
pub degrees: i16,
|
||||
pub minutes: i16,
|
||||
pub seconds: f64,
|
||||
pub direction: Direction,
|
||||
}
|
||||
|
||||
impl FromStr for DegreeMinuteSecond {
|
||||
impl FromStr for DMS {
|
||||
type Err = ();
|
||||
|
||||
/// Recognizes DMS in the formats:
|
||||
@ -67,17 +70,17 @@ impl FromStr for DegreeMinuteSecond {
|
||||
/// * `40 31 21 N, 105 5 39 W`
|
||||
///
|
||||
/// ```rust
|
||||
/// use spatial_coordinate_systems::dms::DegreeMinuteSecond;
|
||||
/// use spatial_coordinate_systems::dms::DMS;
|
||||
/// use spatial_coordinate_systems::Direction;
|
||||
/// use std::str::FromStr;
|
||||
///
|
||||
/// assert_eq!(DegreeMinuteSecond::from_str("40 31 21 N").unwrap(), DegreeMinuteSecond {
|
||||
/// assert_eq!(DMS::from_str("40 31 21 N").unwrap(), DMS {
|
||||
/// degrees: 40,
|
||||
/// minutes: 31,
|
||||
/// seconds: 21_f64,
|
||||
/// direction: Direction::North,
|
||||
/// });
|
||||
/// assert_eq!(DegreeMinuteSecond::from_str("40°31' 21 \" N").unwrap(), DegreeMinuteSecond {
|
||||
/// assert_eq!(DMS::from_str("40°31' 21 \" N").unwrap(), DMS {
|
||||
/// degrees: 40,
|
||||
/// minutes: 31,
|
||||
/// seconds: 21_f64,
|
||||
@ -85,31 +88,6 @@ impl FromStr for DegreeMinuteSecond {
|
||||
/// });
|
||||
/// ```
|
||||
fn from_str(i: &str) -> Result<Self, Self::Err> {
|
||||
map(
|
||||
tuple((
|
||||
space0,
|
||||
// Degrees
|
||||
complete::i16,
|
||||
optional_separator('°'),
|
||||
// Minutes
|
||||
complete::i16,
|
||||
optional_separator('\''),
|
||||
// Seconds
|
||||
double,
|
||||
optional_separator('"'),
|
||||
// Direction
|
||||
parse_direction,
|
||||
// Ensure no other characters can be read
|
||||
eof,
|
||||
)),
|
||||
|(_, degrees, (), minutes, (), seconds, (), direction, _)| DegreeMinuteSecond {
|
||||
degrees,
|
||||
minutes,
|
||||
seconds,
|
||||
direction,
|
||||
},
|
||||
)(i)
|
||||
.map_err(|_| ())
|
||||
.map(|(_, ret)| ret)
|
||||
parse(i).map_err(|_| ()).map(|(_, ret)| ret)
|
||||
}
|
||||
}
|
||||
|
@ -2,11 +2,12 @@
|
||||
|
||||
use std::str::FromStr;
|
||||
mod common;
|
||||
pub mod dd;
|
||||
pub mod dm;
|
||||
pub mod dms;
|
||||
|
||||
use dm::DegreeMinute;
|
||||
use dms::DegreeMinuteSecond;
|
||||
use dm::DM;
|
||||
use dms::DMS;
|
||||
use nom::{
|
||||
branch::alt,
|
||||
character::complete::space0,
|
||||
@ -46,9 +47,11 @@ impl Direction {
|
||||
}
|
||||
|
||||
pub enum Coordinate {
|
||||
LatLon((f64, f64)),
|
||||
DegreeMinuteSecond((DegreeMinuteSecond, DegreeMinuteSecond)),
|
||||
DegreeMinute((DegreeMinute, DegreeMinute)),
|
||||
DD(dd::Coordinate),
|
||||
DMS(dms::Coordinate),
|
||||
DM(dm::Coordinate),
|
||||
// UTM(utm::UTMCoordinate),
|
||||
// Plus(plus::PlusCoordinate),
|
||||
}
|
||||
|
||||
pub enum CoordinateSystem {
|
||||
@ -61,7 +64,13 @@ impl FromStr for Coordinate {
|
||||
fn from_str(i: &str) -> Result<Self, Self::Err> {
|
||||
tuple((
|
||||
space0,
|
||||
alt((map(dms::parse_coordinate, Coordinate::DegreeMinuteSecond),)),
|
||||
alt((
|
||||
map(dd::parse_coordinate, Coordinate::DD),
|
||||
map(dms::parse_coordinate, Coordinate::DMS),
|
||||
map(dm::parse_coordinate, Coordinate::DM),
|
||||
// map(utm::parse_coordinate, Coordinate::UTM),
|
||||
// map(plus::parse_coordinate, Coordinate::PLUS),
|
||||
)),
|
||||
space0,
|
||||
eof,
|
||||
))(i)
|
||||
|
Loading…
Reference in New Issue
Block a user