Fix dms and dmm negative latlon
This commit is contained in:
parent
81e1fa58ec
commit
110d562630
@ -14,6 +14,8 @@ use crate::{
|
||||
LatLon,
|
||||
};
|
||||
|
||||
#[derive(Debug)]
|
||||
// TODO: Derive serialize
|
||||
#[cfg_attr(feature = "serde", derive(Serialize, Deserialize))]
|
||||
pub struct Coordinates {
|
||||
pub latlon: LatLon,
|
||||
@ -66,3 +68,15 @@ impl FromStr for Coordinates {
|
||||
Self::try_from(LatLon::from(&Coordinate::from_str(i)?))
|
||||
}
|
||||
}
|
||||
|
||||
// #[cfg(test)]
|
||||
// mod tests {
|
||||
// use super::*;
|
||||
|
||||
// #[test]
|
||||
// fn test_general() {
|
||||
// dbg!(Coordinates::from_str(
|
||||
// "69.79268710495744, -108.23886036872865"
|
||||
// ));
|
||||
// }
|
||||
// }
|
||||
|
@ -127,7 +127,12 @@ impl DMM {
|
||||
}
|
||||
|
||||
pub fn to_decimal_degrees(&self) -> f64 {
|
||||
self.degrees as f64 + self.minutes / 60_f64
|
||||
(self.degrees as f64 + self.minutes / 60_f64)
|
||||
* if self.direction.is_positive() {
|
||||
1.0_f64
|
||||
} else {
|
||||
-1.0_f64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -18,20 +18,23 @@ impl Coordinate {
|
||||
pub fn parse(i: &str) -> IResult<&str, Self> {
|
||||
map_res(
|
||||
tuple((DMS::parse, optional_separator(','), space0, DMS::parse)),
|
||||
|(lat, _, _, lon)| {
|
||||
// Ensure this is a north/south then east/west direction
|
||||
if !lat.direction.is_lat() {
|
||||
Err(Error::InvalidLatitudeBearing(lat.direction))
|
||||
} else if !lon.direction.is_lon() {
|
||||
Err(Error::InvalidLongitudeBearing(lon.direction))
|
||||
} else {
|
||||
let latlon = LatLon::new(lat.to_decimal_degrees(), lon.to_decimal_degrees())?;
|
||||
Ok(Coordinate(lat, lon, latlon))
|
||||
}
|
||||
},
|
||||
|(lat, _, _, lon)| Self::from_components(lat, lon),
|
||||
)(i)
|
||||
}
|
||||
|
||||
pub fn from_components(lat: DMS, lon: DMS) -> Result<Self, Error> {
|
||||
let (lat, lon) = (lat.normalize(), lon.normalize());
|
||||
// Ensure this is a north/south then east/west direction
|
||||
if !lat.direction.is_lat() {
|
||||
Err(Error::InvalidLatitudeBearing(lat.direction))
|
||||
} else if !lon.direction.is_lon() {
|
||||
Err(Error::InvalidLongitudeBearing(lon.direction))
|
||||
} else {
|
||||
let latlon = LatLon::new(lat.to_decimal_degrees(), lon.to_decimal_degrees())?;
|
||||
Ok(Coordinate(lat, lon, latlon))
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_lat(&self) -> DMS {
|
||||
self.0
|
||||
}
|
||||
@ -106,6 +109,17 @@ impl DMS {
|
||||
)(i)
|
||||
}
|
||||
|
||||
pub fn normalize(&self) -> Self {
|
||||
let (degrees, direction) = normalize_degrees_direction(self.degrees, self.direction);
|
||||
|
||||
Self {
|
||||
degrees,
|
||||
minutes: self.minutes,
|
||||
seconds: self.seconds,
|
||||
direction,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_decimal_degrees(d: f64, is_latitude: bool) -> Self {
|
||||
let degrees = d as i16;
|
||||
let minutes = d.abs().fract() * 60_f64;
|
||||
@ -130,7 +144,12 @@ impl DMS {
|
||||
}
|
||||
|
||||
pub fn to_decimal_degrees(&self) -> f64 {
|
||||
self.degrees as f64 + self.minutes as f64 / 60_f64 + self.seconds / 3_600_f64
|
||||
(self.degrees as f64 + self.minutes as f64 / 60_f64 + self.seconds / 3_600_f64)
|
||||
* if self.direction.is_positive() {
|
||||
1.0_f64
|
||||
} else {
|
||||
-1.0_f64
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,8 @@
|
||||
use crate::{common::parse_direction, Direction, Error, LatLon};
|
||||
use crate::{
|
||||
common::parse_direction,
|
||||
dms::{self, DMS},
|
||||
Direction, Error, LatLon,
|
||||
};
|
||||
use nom::{
|
||||
bytes::complete::take,
|
||||
character::complete::{self, space0},
|
||||
@ -30,34 +34,45 @@ impl Coordinate {
|
||||
opt(Self::parse_n_digits::<2>),
|
||||
parse_direction,
|
||||
)),
|
||||
|(lat_d, lat_m, lat_s, lat_direction, _, _, _, lon_d, lon_m, lon_s, lon_direction)| {
|
||||
// Ensure this is a north/south then east/west direction
|
||||
if !lat_direction.is_lat() {
|
||||
Err(Error::InvalidLatitudeBearing(lat_direction))
|
||||
} else if !lon_direction.is_lon() {
|
||||
Err(Error::InvalidLongitudeBearing(lon_direction))
|
||||
} else {
|
||||
let lat = Self::dms_to_f64_helper(lat_d, lat_m, lat_s, &lat_direction);
|
||||
let lon = Self::dms_to_f64_helper(lon_d, lon_m, lon_s, &lon_direction);
|
||||
|(lat_d, lat_m, lat_s, lat_direction, _, _, _, lon_d, lon_m, lon_s, lon_direction)| -> Result<_, Error> {
|
||||
let lat = DMS {
|
||||
degrees: lat_d as i16,
|
||||
minutes: lat_m.unwrap_or(0) as i16,
|
||||
seconds: lat_s.unwrap_or(0) as f64,
|
||||
direction: lat_direction,
|
||||
};
|
||||
let lon = DMS {
|
||||
degrees: lon_d as i16,
|
||||
minutes: lon_m.unwrap_or(0) as i16,
|
||||
seconds: lon_s.unwrap_or(0) as f64,
|
||||
direction: lon_direction,
|
||||
};
|
||||
|
||||
let latlon = LatLon::new(lat, lon)?;
|
||||
Ok(Coordinate(Self::latlon_to_string(&latlon), latlon))
|
||||
}
|
||||
let dms = dms::Coordinate::from_components(lat, lon)?;
|
||||
let latlon = LatLon::from(&dms);
|
||||
|
||||
// let lat = Self::dms_to_f64_helper(lat_d, lat_m, lat_s, &lat_direction);
|
||||
// let lon = Self::dms_to_f64_helper(lon_d, lon_m, lon_s, &lon_direction);
|
||||
|
||||
// let latlon = DMS {};
|
||||
// LatLon::new(lat, lon)?;
|
||||
Ok(Coordinate(Self::latlon_to_string(&latlon), latlon))
|
||||
},
|
||||
)(i)
|
||||
}
|
||||
|
||||
/// Helper to convert u8, Option<u8>, Option<u8> into an f64
|
||||
fn dms_to_f64_helper(d: u8, m: Option<u8>, s: Option<u8>, direction: &Direction) -> f64 {
|
||||
(d as f64
|
||||
+ m.map(|m| m as f64 / 100.0_f64).unwrap_or(0.0_f64)
|
||||
+ s.map(|s| s as f64 / 10_000.0_f64).unwrap_or(0.0_f64))
|
||||
* if direction.is_positive() {
|
||||
1.0_f64
|
||||
} else {
|
||||
-1.0_f64
|
||||
}
|
||||
}
|
||||
// fn dms_to_f64_helper(d: u8, m: Option<u8>, s: Option<u8>, direction: &Direction) -> f64 {
|
||||
|
||||
// (d as f64
|
||||
// + m.map(|m| m as f64 / 100.0_f64).unwrap_or(0.0_f64)
|
||||
// + s.map(|s| s as f64 / 10_000.0_f64).unwrap_or(0.0_f64))
|
||||
// * if direction.is_positive() {
|
||||
// 1.0_f64
|
||||
// } else {
|
||||
// -1.0_f64
|
||||
// }
|
||||
// }
|
||||
|
||||
/// Takes n digits from the input and parses it as a u8
|
||||
fn parse_n_digits<const C: u8>(i: &str) -> IResult<&str, u8> {
|
||||
@ -96,7 +111,7 @@ impl FromStr for Coordinate {
|
||||
|
||||
impl fmt::Display for Coordinate {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(f, "{}, {}", self.0, self.1)
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
@ -117,25 +132,25 @@ impl From<LatLon> for Coordinate {
|
||||
mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_helpers() {
|
||||
assert_eq!(
|
||||
Coordinate::dms_to_f64_helper(90, None, None, &Direction::North),
|
||||
90.0000_f64
|
||||
);
|
||||
assert_eq!(
|
||||
Coordinate::dms_to_f64_helper(90, None, None, &Direction::South),
|
||||
-90.0000_f64
|
||||
);
|
||||
assert_eq!(
|
||||
Coordinate::dms_to_f64_helper(90, Some(12), Some(8), &Direction::North),
|
||||
90.1208_f64
|
||||
);
|
||||
assert_eq!(
|
||||
Coordinate::dms_to_f64_helper(90, None, Some(8), &Direction::North),
|
||||
90.0008_f64
|
||||
);
|
||||
}
|
||||
// #[test]
|
||||
// fn test_helpers() {
|
||||
// assert_eq!(
|
||||
// Coordinate::dms_to_f64_helper(90, None, None, &Direction::North),
|
||||
// 90.0000_f64
|
||||
// );
|
||||
// assert_eq!(
|
||||
// Coordinate::dms_to_f64_helper(90, None, None, &Direction::South),
|
||||
// -90.0000_f64
|
||||
// );
|
||||
// assert_eq!(
|
||||
// Coordinate::dms_to_f64_helper(90, Some(12), Some(8), &Direction::North),
|
||||
// 90.1208_f64
|
||||
// );
|
||||
// assert_eq!(
|
||||
// Coordinate::dms_to_f64_helper(90, None, Some(8), &Direction::North),
|
||||
// 90.0008_f64
|
||||
// );
|
||||
// }
|
||||
|
||||
#[test]
|
||||
fn test_general() {
|
||||
@ -172,8 +187,9 @@ mod tests {
|
||||
Ok(Coordinate::from(LatLon::new(-90.0_f64, 100.0_f64).unwrap()))
|
||||
);
|
||||
|
||||
// TODO: Are these truncated or rounded?
|
||||
assert_eq!(
|
||||
Coordinate::from_str("697926N1082388W").unwrap().0,
|
||||
Coordinate::from_str("694733N1081419W").unwrap().0,
|
||||
Coordinate::from(LatLon::new(69.79268710495744, -108.23886036872865).unwrap()).0
|
||||
)
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user