98 lines
2.4 KiB
Rust
Raw Normal View History

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)]
2023-03-19 18:54:49 -04:00
pub struct Coordinate(pub DMM, pub DMM);
2023-03-19 18:59:25 -04:00
impl Coordinate {
2023-03-19 19:20:17 -04:00
pub fn parse(i: &str) -> IResult<&str, Self> {
2023-03-19 18:59:25 -04:00
map_opt(
tuple((DMM::parse, optional_separator(','), DMM::parse)),
|(ns, _, ew)| {
// Ensure this is a north/south then east/west direction
if ns.direction.is_lat() && ew.direction.is_lon() {
Some(Coordinate(ns, ew))
} else {
None
}
},
)(i)
}
}
2023-03-19 19:20:17 -04:00
impl FromStr for Coordinate {
type Err = ();
fn from_str(i: &str) -> Result<Self, Self::Err> {
Self::parse(i).map_err(|_| ()).map(|(_, ret)| ret)
}
}
#[derive(PartialEq, Debug)]
2023-03-19 18:54:49 -04:00
pub struct DMM {
pub degrees: i16,
pub minutes: f64,
pub direction: Direction,
}
2023-03-19 18:59:25 -04:00
impl DMM {
pub fn parse(i: &str) -> IResult<&str, DMM> {
map(
tuple((
// Degrees
complete::i16,
optional_separator('°'),
// Minutes
double,
optional_separator('\''),
// Direction
parse_direction,
)),
|(degrees, (), minutes, (), direction)| DMM {
degrees,
minutes,
direction,
},
)(i)
}
}
2023-03-19 18:54:49 -04:00
impl FromStr for DMM {
type Err = ();
/// Recognizes DMS in the formats:
///
/// * `40° 31' 21" N, 105° 5' 39" W`
/// * `40 31 21 N, 105 5 39 W`
///
/// ```rust
2023-03-19 18:54:49 -04:00
/// use spatial_coordinate_systems::dmm::DMM;
/// use spatial_coordinate_systems::Direction;
/// use std::str::FromStr;
///
2023-03-19 18:54:49 -04:00
/// assert_eq!(DMM::from_str("40 31.3 N").unwrap(), DMM {
/// degrees: 40,
/// minutes: 31.3_f64,
/// direction: Direction::North,
/// });
2023-03-19 18:54:49 -04:00
/// assert_eq!(DMM::from_str("40°31' N").unwrap(), DMM {
/// degrees: 40,
/// minutes: 31_f64,
/// direction: Direction::North,
/// });
/// ```
fn from_str(i: &str) -> Result<Self, Self::Err> {
2023-03-19 18:59:25 -04:00
DMM::parse(i).map_err(|_| ()).map(|(_, ret)| ret)
}
}