added current code
This commit is contained in:
parent
557558acc6
commit
41e5e9b032
39 changed files with 2431 additions and 215 deletions
|
|
@ -1,17 +1,19 @@
|
|||
use crate::ACCURACY_BOUNDARY;
|
||||
use geojson::{Position, Value};
|
||||
use std::convert::From;
|
||||
use std::f64::consts::{FRAC_PI_2, PI, TAU};
|
||||
use crate::ACCURACY_BOUNDARY;
|
||||
use serde::{Serialize, Deserialize};
|
||||
|
||||
|
||||
/// Spherical coordinates in radians.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct RadianCoordinate {
|
||||
pub lat: f64,
|
||||
pub lon: f64,
|
||||
}
|
||||
|
||||
/// Spherical coordinates in degrees.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Default)]
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct DegreeCoordinate {
|
||||
pub lat: f64,
|
||||
pub lon: f64,
|
||||
|
|
@ -25,14 +27,14 @@ impl From<DegreeCoordinate> for RadianCoordinate {
|
|||
|
||||
impl From<DegreeCoordinate> for geojson::Value {
|
||||
fn from(coordinate: DegreeCoordinate) -> Self {
|
||||
Value::Point(vec![coordinate.lat, coordinate.lon])
|
||||
Value::Point(vec![coordinate.lon, coordinate.lat])
|
||||
}
|
||||
}
|
||||
|
||||
impl From<RadianCoordinate> for Position {
|
||||
fn from(coordinate: RadianCoordinate) -> Self {
|
||||
let coordinate = DegreeCoordinate::from(coordinate);
|
||||
vec![coordinate.lat, coordinate.lon]
|
||||
vec![coordinate.lon, coordinate.lat]
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -70,12 +72,11 @@ impl RadianCoordinate {
|
|||
/// returns the longitude of a point when the coordinate system is
|
||||
/// transformed, such that `north_pole` is the north pole of that system.
|
||||
pub fn get_transformed_longitude(&self, north_pole: &RadianCoordinate) -> f64 {
|
||||
|
||||
if self.lat == FRAC_PI_2 {
|
||||
return self.lon
|
||||
return self.lon;
|
||||
};
|
||||
|
||||
let top = (self.lon- north_pole.lon).sin() * self.lat.cos();
|
||||
let top = (self.lon - north_pole.lon).sin() * self.lat.cos();
|
||||
let bottom = (self.lat.sin() * north_pole.lat.cos())
|
||||
- (self.lat.cos() * north_pole.lat.sin() * (self.lon - north_pole.lon).cos());
|
||||
|
||||
|
|
@ -118,40 +119,6 @@ impl RadianCoordinate {
|
|||
2.0 * a.sqrt().atan2((1.0_f64 - a).sqrt())
|
||||
}
|
||||
|
||||
/// checks whether the strike is between the shorter angle between the points
|
||||
/// `a` and `b` while using `pole` as the north pole.
|
||||
pub fn strike_between(
|
||||
&self,
|
||||
pole: &RadianCoordinate,
|
||||
a: &RadianCoordinate,
|
||||
b: &RadianCoordinate,
|
||||
) -> bool {
|
||||
let mut lon = self.get_transformed_longitude(pole).rem_euclid(2.0 * PI);
|
||||
let a_lon = a.get_transformed_longitude(pole).rem_euclid(2.0 * PI);
|
||||
let b_lon = b.get_transformed_longitude(pole).rem_euclid(2.0 * PI);
|
||||
|
||||
// select the start boundary of the smaller circle segment in the
|
||||
// positive direction
|
||||
let start;
|
||||
let mut end;
|
||||
|
||||
if (b_lon - a_lon) > PI {
|
||||
start = b_lon;
|
||||
end = a_lon;
|
||||
} else {
|
||||
start = a_lon;
|
||||
end = b_lon;
|
||||
}
|
||||
|
||||
// rotate the values such that the start is interpreted as 0 and
|
||||
// handle the wrap around.
|
||||
// The start of the interval is now at 0 and the end should be smaller
|
||||
// than PI.
|
||||
end = (end - start).rem_euclid(2.0 * PI);
|
||||
lon = (lon - start).rem_euclid(2.0 * PI);
|
||||
|
||||
0_f64 <= lon && lon <= end
|
||||
}
|
||||
}
|
||||
|
||||
impl DegreeCoordinate {
|
||||
|
|
@ -163,6 +130,30 @@ impl DegreeCoordinate {
|
|||
|
||||
DegreeCoordinate { lat, lon }
|
||||
}
|
||||
|
||||
/// returns a SphericalCoordinate parsed from the given string.
|
||||
pub fn from_string_tuple(input: &str) -> Result<DegreeCoordinate, CoordinateParsingError> {
|
||||
let splits: Vec<&str> = input.split(",").collect();
|
||||
|
||||
if splits.len() != 2 {
|
||||
return Err(CoordinateParsingError::NoSemicolon);
|
||||
}
|
||||
|
||||
let lat = splits[0];
|
||||
let lon = splits[1];
|
||||
|
||||
let lat = match lat.parse::<f64>() {
|
||||
Ok(lat) => lat,
|
||||
Err(_) => { return Err(CoordinateParsingError::NotAFloat); }
|
||||
};
|
||||
|
||||
let lon = match lon.parse::<f64>() {
|
||||
Ok(lon) => lon,
|
||||
Err(_) => { return Err(CoordinateParsingError::NotAFloat); }
|
||||
};
|
||||
|
||||
Ok(DegreeCoordinate{lat, lon})
|
||||
}
|
||||
}
|
||||
|
||||
/// normalizes longitude values given in radians to the range (-PI, PI]
|
||||
|
|
@ -190,3 +181,45 @@ fn test_normalize_lon() {
|
|||
assert!((normalize_lon(PI + FRAC_PI_2) - (-FRAC_PI_2)).abs() < 10e-12);
|
||||
assert!((normalize_lon(-PI - FRAC_PI_2) - (FRAC_PI_2)).abs() < 10e-12);
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, PartialEq)]
|
||||
pub enum LongitudeDirection {
|
||||
East,
|
||||
West,
|
||||
None,
|
||||
}
|
||||
|
||||
pub fn east_or_west(from: f64, to: f64) -> LongitudeDirection {
|
||||
let delta = normalize_lon(from - to);
|
||||
|
||||
if delta > 0.0 && delta < PI {
|
||||
LongitudeDirection::West
|
||||
} else if delta < 0.0 && delta > -PI {
|
||||
LongitudeDirection::East
|
||||
} else {
|
||||
LongitudeDirection::None
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum CoordinateParsingError {
|
||||
NoSemicolon,
|
||||
NotAFloat,
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_east_or_west() {
|
||||
assert_eq!(east_or_west(0.0, 0.0), LongitudeDirection::None);
|
||||
assert_eq!(east_or_west(0.0, 1.0), LongitudeDirection::East);
|
||||
assert_eq!(east_or_west(0.0, -1.0), LongitudeDirection::West);
|
||||
assert_eq!(east_or_west(1.0, -1.0), LongitudeDirection::West);
|
||||
assert_eq!(east_or_west(-1.0, 1.0), LongitudeDirection::East);
|
||||
|
||||
assert_eq!(east_or_west(0.5, 1.0), LongitudeDirection::East);
|
||||
assert_eq!(east_or_west(-1.0, -0.5), LongitudeDirection::East);
|
||||
|
||||
// wrap around tests
|
||||
assert_eq!(east_or_west(3.0, -3.0), LongitudeDirection::East);
|
||||
assert_eq!(east_or_west(-3.0, 3.0), LongitudeDirection::West);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue