Skip to content

Commit

Permalink
Angular conversions in CoordinateTuple
Browse files Browse the repository at this point in the history
  • Loading branch information
busstoptaktik committed Apr 3, 2024
1 parent 09c2140 commit 704c202
Show file tree
Hide file tree
Showing 2 changed files with 108 additions and 13 deletions.
112 changes: 106 additions & 6 deletions src/coordinate/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,22 +115,22 @@ pub trait CoordinateSet: CoordinateMetadata {
/// The CoordinateTuple is the ISO-19111 atomic spatial/spatiotemporal
/// referencing element. Loosely speaking, a CoordinateSet consists of
/// CoordinateTuples.
///
///
/// Note that (despite the formal name) the underlying data structure
/// need not be a tuple: It can be any item, for which it makes sense
/// to implement the CoordinateTuple trait.
///
///
/// The CoordinateTuple trait provides a number of convenience accessors
/// for accessing single coordinate elements or tuples of subsets.
/// These accessors are pragmatically named (x, y, xy, etc.). While these
/// names may be geodetically naive, they are suggestive and practical, and
/// aligns well with the internal coordinate order convention of most
/// Geodesy operators.
///
///
/// All accessors have default implementations, except the
/// [`unchecked_nth()`](crate::coordinate::CoordinateTuple::unchecked_nth) function,
/// which must be provided by the implementer.
///
///
/// When accessing dimensions outside of the domain of the CoordinateTuple,
/// [NaN](f64::NAN) will be returned.
#[rustfmt::skip]
Expand Down Expand Up @@ -170,12 +170,12 @@ pub trait CoordinateTuple {
fn y(&self) -> f64 {
if Self::DIMENSION > 1 { self.unchecked_nth(1) } else {f64::NAN}
}

/// Pragmatically named accessor for the third element of the CoordinateTuple.
fn z(&self) -> f64 {
if Self::DIMENSION > 2 { self.unchecked_nth(2) } else {f64::NAN}
}

/// Pragmatically named accessor for the fourth element of the CoordinateTuple.
fn t(&self) -> f64 {
if Self::DIMENSION > 3 { self.unchecked_nth(3) } else {f64::NAN}
Expand All @@ -195,36 +195,128 @@ pub trait CoordinateTuple {
fn xyzt(&self) -> (f64, f64, f64, f64) {
(self.x(), self.y(), self.z(), self.t())
}


/// A tuple containing the first two components of the CoordinateTuple
/// converted from radians to degrees
fn xy_in_degrees(&self) -> (f64, f64) {
(self.x().to_degrees(), self.y().to_degrees())
}

/// A tuple containing the first three components of the CoordinateTuple,
/// with the first two converted from radians to degrees.
fn xyz_in_degrees(&self) -> (f64, f64, f64) {
(self.x().to_degrees(), self.y().to_degrees(), self.z())
}

/// A tuple containing the first four components of the CoordinateTuple,
/// with the first two converted from radians to degrees.
fn xyzt_in_degrees(&self) -> (f64, f64, f64, f64) {
(self.x().to_degrees(), self.y().to_degrees(), self.z(), self.t())
}


/// A tuple containing the first two components of the CoordinateTuple,
/// converted from radians to seconds-of-arc
fn xy_in_arcsec(&self) -> (f64, f64) {
(self.x().to_degrees()*3600., self.y().to_degrees()*3600.)
}

/// A tuple containing the first three components of the CoordinateTuple,
/// with the first two converted to seconds-of-arc
fn xyz_in_arcsec(&self) -> (f64, f64, f64) {
(self.x().to_degrees()*3600., self.y().to_degrees()*3600., self.z())
}

/// A tuple containing the first four components of the CoordinateTuple,
/// with the first two converted to seconds-of-arc
fn xyzt_in_arcsec(&self) -> (f64, f64, f64, f64) {
(self.x().to_degrees()*3600., self.y().to_degrees()*3600., self.z(), self.t())
}

/// A tuple containing the first two components of the CoordinateTuple,
/// converted from degrees to radians
fn xy_in_radians(&self) -> (f64, f64) {
(self.x().to_radians(), self.y().to_radians())
}

/// A tuple containing the first three components of the CoordinateTuple,
/// with the first two converted from degrees to radians
fn xyz_in_radians(&self) -> (f64, f64, f64) {
(self.x().to_radians(), self.y().to_radians(), self.z())
}

/// A tuple containing the first four components of the CoordinateTuple,
/// with the first two converted from degrees to radians
fn xyzt_in_radians(&self) -> (f64, f64, f64, f64) {
(self.x().to_radians(), self.y().to_radians(), self.z(), self.t())
}

/// Replace the n'th (0-based) element of the `CoordinateTuple` with `value`.
/// May panic if n >= [DIMENSION].
/// See also [`set_nth()`](crate::coordinate::CoordinateTuple::nth).
fn unchecked_set_nth(&mut self, n: usize, value: f64);

/// Replace the `N` first (up to [DIMENSION]) elements of `self` with the
/// elements of `value`
fn set<const N: usize>(&mut self, value: [f64; N]) {
for i in 0..N.min(Self::DIMENSION) {
self.unchecked_set_nth(i, value[i])
}
}
}




// We must still implement the CoordinateTuple trait for
// the Geodesy data types Coor2D, Coor32, Coor3D, Coor4D


// We must still implement the CoordinateTuple trait for
// the Geodesy data types Coor2D, Coor32, Coor3D, Coor4D
impl CoordinateTuple for Coor2D {
const DIMENSION: usize = 2;
fn unchecked_nth(&self, n: usize) -> f64 {
self.0[n]
}

fn unchecked_set_nth(&mut self, n: usize, value: f64) {
self.0[n] = value;
}
}

impl CoordinateTuple for Coor3D {
const DIMENSION: usize = 3;
fn unchecked_nth(&self, n: usize) -> f64 {
self.0[n]
}

fn unchecked_set_nth(&mut self, n: usize, value: f64) {
self.0[n] = value;
}
}

impl CoordinateTuple for Coor4D {
const DIMENSION: usize = 4;
fn unchecked_nth(&self, n: usize) -> f64 {
self.0[n]
}

fn unchecked_set_nth(&mut self, n: usize, value: f64) {
self.0[n] = value;
}
}

impl CoordinateTuple for Coor32 {
const DIMENSION: usize = 2;
fn unchecked_nth(&self, n: usize) -> f64 {
self.0[n] as f64
}

fn unchecked_set_nth(&mut self, n: usize, value: f64) {
self.0[n] = value as f32;
}
}

// And let's also implement it for a plain 2D f64 tuple
Expand All @@ -238,4 +330,12 @@ impl CoordinateTuple for (f64, f64) {
_ => panic!()
}
}

fn unchecked_set_nth(&mut self, n: usize, value: f64) {
match n {
0 => self.0 = value,
1 => self.1 = value,
_ => ()
}
}
}
9 changes: 2 additions & 7 deletions src/ellipsoid/geodesics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,7 @@ impl Ellipsoid {
/// Federico Dolce and Michael Kirk, provides a Rust implementation of Karney's algorithm.
#[must_use]
#[allow(non_snake_case)]
pub fn geodesic_fwd<G: CoordinateTuple>(
&self,
from: &G,
azimuth: f64,
distance: f64,
) -> Coor4D {
pub fn geodesic_fwd<C: CoordinateTuple>(&self, from: &C, azimuth: f64, distance: f64) -> Coor4D {
// Coordinates of the point of origin, P1
let (L1, B1) = from.xy();

Expand Down Expand Up @@ -99,7 +94,7 @@ impl Ellipsoid {
/// See [`geodesic_fwd`](crate::Ellipsoid::geodesic_fwd)
#[must_use]
#[allow(non_snake_case)] // So we can use the mathematical notation from the original text
pub fn geodesic_inv<G: CoordinateTuple>(&self, from: &G, to: &G) -> Coor4D {
pub fn geodesic_inv<C: CoordinateTuple>(&self, from: &C, to: &C) -> Coor4D {
let (L1, B1) = from.xy();
let (L2, B2) = to.xy();
let B = B2 - B1;
Expand Down

0 comments on commit 704c202

Please sign in to comment.