diff --git a/spatial-coordinate-systems/src/common.rs b/spatial-coordinate-systems/src/common.rs index 20b4946..8948d0c 100644 --- a/spatial-coordinate-systems/src/common.rs +++ b/spatial-coordinate-systems/src/common.rs @@ -36,6 +36,15 @@ pub fn parse_direction(i: &str) -> IResult<&str, Direction> { ))(i) } +/// Changes degrees to a positive number and flips the direction if required +pub fn normalize_degrees_direction(degrees: i16, direction: Direction) -> (i16, Direction) { + if degrees < 0 { + (-degrees, direction.inverse()) + } else { + (degrees, direction) + } +} + pub fn parse_f64(i: &str) -> IResult<&str, f64> { map_opt( tuple(( diff --git a/spatial-coordinate-systems/src/dmm.rs b/spatial-coordinate-systems/src/dmm.rs index 3d5576b..5774c50 100644 --- a/spatial-coordinate-systems/src/dmm.rs +++ b/spatial-coordinate-systems/src/dmm.rs @@ -1,5 +1,5 @@ use crate::{ - common::{optional_separator, parse_direction, parse_f64}, + common::{normalize_degrees_direction, optional_separator, parse_direction, parse_f64}, Direction, Error, LatLon, }; use nom::{ @@ -95,16 +95,12 @@ impl DMM { ), )), |((degrees, minutes), _, direction)| { - let negate = direction == Direction::West || direction == Direction::South; + let (degrees, direction) = normalize_degrees_direction(degrees, direction); Self { - degrees: degrees * if negate { -1 } else { 1 }, + degrees, minutes, - direction: if direction.is_lat() { - Direction::North - } else { - Direction::East - }, + direction, } }, )(i) @@ -114,14 +110,19 @@ impl DMM { let degrees = d as i16; let minutes = d.fract() * 60_f64; - Self { + let (degrees, direction) = normalize_degrees_direction( degrees, - minutes, - direction: if is_latitude { + if is_latitude { Direction::North } else { Direction::East }, + ); + + Self { + degrees, + minutes, + direction, } } diff --git a/spatial-coordinate-systems/src/dms.rs b/spatial-coordinate-systems/src/dms.rs index 1f7c060..6eb94fd 100644 --- a/spatial-coordinate-systems/src/dms.rs +++ b/spatial-coordinate-systems/src/dms.rs @@ -1,5 +1,5 @@ use crate::{ - common::{optional_separator, parse_direction, parse_f64}, + common::{normalize_degrees_direction, optional_separator, parse_direction, parse_f64}, Direction, Error, LatLon, }; use nom::{ @@ -94,17 +94,13 @@ impl DMS { ), )), |((degrees, minutes, seconds), _, direction)| { - let negate = direction == Direction::West || direction == Direction::South; + let (degrees, direction) = normalize_degrees_direction(degrees, direction); Self { - degrees: degrees * if negate { -1 } else { 1 }, + degrees, minutes, seconds, - direction: if direction.is_lat() { - Direction::North - } else { - Direction::East - }, + direction, } }, )(i) @@ -116,15 +112,20 @@ impl DMS { let seconds = minutes.fract() * 60_f64; let minutes = minutes as i16; - Self { + let (degrees, direction) = normalize_degrees_direction( degrees, - minutes, - seconds, - direction: if is_latitude { + if is_latitude { Direction::North } else { Direction::East }, + ); + + Self { + degrees, + minutes, + seconds, + direction, } } diff --git a/spatial-coordinate-systems/src/lib.rs b/spatial-coordinate-systems/src/lib.rs index 478c2d0..747823b 100644 --- a/spatial-coordinate-systems/src/lib.rs +++ b/spatial-coordinate-systems/src/lib.rs @@ -61,6 +61,16 @@ impl Direction { pub fn is_positive(&self) -> bool { self == &Self::North || self == &Self::East } + + /// Flips the direction + pub fn inverse(&self) -> Self { + match self { + Direction::North => Direction::South, + Direction::South => Direction::North, + Direction::East => Direction::West, + Direction::West => Direction::East, + } + } } #[derive(Debug, PartialEq, Clone, EnumDiscriminants)] diff --git a/spatial-coordinate-systems/src/skyvector.rs b/spatial-coordinate-systems/src/skyvector.rs index 6aa7c59..05c1b3f 100644 --- a/spatial-coordinate-systems/src/skyvector.rs +++ b/spatial-coordinate-systems/src/skyvector.rs @@ -149,6 +149,16 @@ mod tests { "120000N1000000E" ); + assert_eq!( + Coordinate::from(LatLon::new(90.0_f64, 100.0_f64).unwrap()).0, + "900000N1000000E" + ); + + assert_eq!( + Coordinate::from(LatLon::new(-90.0_f64, 100.0_f64).unwrap()).0, + "900000S1000000E" + ); + // p!("0° 0' N", DMS); // p!("0° 0'N", DMS); // p!("N 0° 0'", DMS);