Normalize dms and dmm to always have positive degrees

This commit is contained in:
Austen Adler 2023-04-22 13:23:20 -04:00
parent 80ca551fa9
commit c5b8b360ed
5 changed files with 54 additions and 23 deletions

View File

@ -36,6 +36,15 @@ pub fn parse_direction(i: &str) -> IResult<&str, Direction> {
))(i) ))(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> { pub fn parse_f64(i: &str) -> IResult<&str, f64> {
map_opt( map_opt(
tuple(( tuple((

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
common::{optional_separator, parse_direction, parse_f64}, common::{normalize_degrees_direction, optional_separator, parse_direction, parse_f64},
Direction, Error, LatLon, Direction, Error, LatLon,
}; };
use nom::{ use nom::{
@ -95,16 +95,12 @@ impl DMM {
), ),
)), )),
|((degrees, minutes), _, direction)| { |((degrees, minutes), _, direction)| {
let negate = direction == Direction::West || direction == Direction::South; let (degrees, direction) = normalize_degrees_direction(degrees, direction);
Self { Self {
degrees: degrees * if negate { -1 } else { 1 }, degrees,
minutes, minutes,
direction: if direction.is_lat() { direction,
Direction::North
} else {
Direction::East
},
} }
}, },
)(i) )(i)
@ -114,14 +110,19 @@ impl DMM {
let degrees = d as i16; let degrees = d as i16;
let minutes = d.fract() * 60_f64; let minutes = d.fract() * 60_f64;
Self { let (degrees, direction) = normalize_degrees_direction(
degrees, degrees,
minutes, if is_latitude {
direction: if is_latitude {
Direction::North Direction::North
} else { } else {
Direction::East Direction::East
}, },
);
Self {
degrees,
minutes,
direction,
} }
} }

View File

@ -1,5 +1,5 @@
use crate::{ use crate::{
common::{optional_separator, parse_direction, parse_f64}, common::{normalize_degrees_direction, optional_separator, parse_direction, parse_f64},
Direction, Error, LatLon, Direction, Error, LatLon,
}; };
use nom::{ use nom::{
@ -94,17 +94,13 @@ impl DMS {
), ),
)), )),
|((degrees, minutes, seconds), _, direction)| { |((degrees, minutes, seconds), _, direction)| {
let negate = direction == Direction::West || direction == Direction::South; let (degrees, direction) = normalize_degrees_direction(degrees, direction);
Self { Self {
degrees: degrees * if negate { -1 } else { 1 }, degrees,
minutes, minutes,
seconds, seconds,
direction: if direction.is_lat() { direction,
Direction::North
} else {
Direction::East
},
} }
}, },
)(i) )(i)
@ -116,15 +112,20 @@ impl DMS {
let seconds = minutes.fract() * 60_f64; let seconds = minutes.fract() * 60_f64;
let minutes = minutes as i16; let minutes = minutes as i16;
Self { let (degrees, direction) = normalize_degrees_direction(
degrees, degrees,
minutes, if is_latitude {
seconds,
direction: if is_latitude {
Direction::North Direction::North
} else { } else {
Direction::East Direction::East
}, },
);
Self {
degrees,
minutes,
seconds,
direction,
} }
} }

View File

@ -61,6 +61,16 @@ impl Direction {
pub fn is_positive(&self) -> bool { pub fn is_positive(&self) -> bool {
self == &Self::North || self == &Self::East 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)] #[derive(Debug, PartialEq, Clone, EnumDiscriminants)]

View File

@ -149,6 +149,16 @@ mod tests {
"120000N1000000E" "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!("0° 0'N", DMS); // p!("0° 0'N", DMS);
// p!("N 0° 0'", DMS); // p!("N 0° 0'", DMS);