Skip to content

Conversation

jbangelo
Copy link
Collaborator

@jbangelo jbangelo commented Aug 27, 2025

Yet another chunk of changes from #122. We're getting close to the end, only one or two more!

This one converts the coordinates module into Rust. There's a bit more than just a re-write in this one, I've cleaned up a few things and included an additional refactors to lay the groundwork for some potential additions in the future.

What's been changed

  • All of the coordinate types use an nalgebra::Vector type under the hood.
  • as_array_ref(), and as_mut_array_ref() on the coordinate types have been changed to only available in the crate (will remove them eventually once the C library dependency is removed)
  • Default implementations are now derived instead of manually implemented
  • AzimuthElevation has been changed to also use a nalgebra::Vector2 under the hood instead having two named fields.

What's been removed

  • as_ptr(), and as_mut_ptr() functions on the coordinate types have been removed
  • Implementations of AsRef on the coordinate types have been removed

What's been added

  • Added impl From<LLHDegrees> for ECEF, not sure how that had been missed previously
  • Added impl From<LLHRadians> for ECEF
  • Put most of the coordinate transformation code into an Ellipsoid trait since it's the same for any ellipsoid once the ellipsoid is defined
  • Added a WGS84 ellipsoid which is still the default for all operations
  • Also added terms for the GRS80 ellipsoid which is also commonly used, but left unused for now

@jbangelo jbangelo force-pushed the jbangelo/riir-coords branch 3 times, most recently from 3e3db5b to fd6d2ca Compare August 27, 2025 21:12
@jbangelo jbangelo marked this pull request as ready for review August 29, 2025 02:59
@jbangelo jbangelo requested a review from a team as a code owner August 29, 2025 02:59
@jbangelo jbangelo force-pushed the jbangelo/riir-coords branch from 34f83a3 to 64293ba Compare August 29, 2025 05:47
Comment on lines +142 to +202
#[must_use]
pub fn new(
reference_frame: ReferenceFrame,
position: ECEF,
velocity: Option<ECEF>,
epoch: GpsTime,
) -> Self {
Coordinate {
reference_frame,
position,
velocity,
epoch,
}
}

/// Create a new [`Coordinate`] object with a velocity value
#[must_use]
pub fn without_velocity(
reference_frame: ReferenceFrame,
position: ECEF,
epoch: GpsTime,
) -> Self {
Coordinate {
reference_frame,
position,
velocity: None,
epoch,
}
}

/// Create a new [`Coordinate`] object with no velocity
#[must_use]
pub fn with_velocity(
reference_frame: ReferenceFrame,
position: ECEF,
velocity: ECEF,
epoch: GpsTime,
) -> Self {
Coordinate {
reference_frame,
position,
velocity: Some(velocity),
epoch,
}
}
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This might be a good case to use a crate like bon, typed-builder or something similar to make a builder. You could do something like this

use bon::Builder

/// Complete coordinate used for transforming between reference frames
///
/// Velocities are optional, but when present they will be transformed
#[derive(Debug, PartialEq, PartialOrd, Clone, Copy, Builder)]
pub struct Coordinate {
    reference_frame: ReferenceFrame,
    position: ECEF,
    velocity: Option<ECEF>,
    epoch: GpsTime,
}

// ...

Coordinate::builder()
  .reference_frame(ref_frame)
  .position(pos)
  .velocity(vel) // could also use .maybe_velocity() to pass in Option<ECEF>
  .epoch(epoch)
  .build();

It uses compile time checks to ensure you don't miss any fields either but it might make having to create all sorts of different new combinations a bit easier to manage.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's a good point. I'll save it for a follow up PR.

@jbangelo jbangelo force-pushed the jbangelo/riir-coords branch from bef2294 to 4f18010 Compare August 30, 2025 00:24
Copy link
Contributor

@JADC362 JADC362 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! I left minor nits and comments, but overall looks clear, and all the From conversions are really handy.

return LLHRadians::new(latitude, longitude, height);
}

// Caluclate some other constants as defined in the Fukushima paper.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
// Caluclate some other constants as defined in the Fukushima paper.
// Calculate some other constants as defined in the Fukushima paper.

let mut f_n;

// Iterate a maximum of 10 times. This should be way more than enough for all
// sane inputs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
// sane inputs
// same inputs

// not divide by zero as only one of S or C should ever be zero.
//
// This incurs an extra division each iteration which the author was
// explicityl trying to avoid and it may be that this solution is just
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit

Suggested change
// explicityl trying to avoid and it may be that this solution is just
// explicitly trying to avoid and it may be that this solution is just

Also, would we like to leave a TODO or something here since you mention it may need more thought?
Perhaps I haven't understood the problem well, but what is the issue of having this extra division? Is it because it adds an extra step affecting performance or because it can lead to instability again?
If the latter is true, we could alternatively panic here if the number becomes "unstably large", I guess it may be better to panic than to return an incorrect number that we think is ok.
Again, perhaps all this answer is completely off, not sure if I understood the problem correctly.

@@ -16,3 +16,59 @@ pub(crate) const fn compile_time_max_u16(a: u16, b: u16) -> u16 {
b
}
}

/// Computes the square root of a given number at compile time using the Newton-Raphson method.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You just bring me memories from university with the "Newton-Raphson method" 😅

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants