pub struct Coordinate<In> { /* private fields */ }Expand description
Defines a point (ie, position) in the coordinate system specified by In.
You can construct one using Cartesian or
spherical coordinates, or using bearing +
range. You can also use the coordinate! macro
for a concise constructor with named arguments.
Depending on the convention of the coordinate system (eg, NedLike, FrdLike, or
RightHandedXyzLike), you’ll have different appropriately-named accessors for the
coordinate’s cartesian components like Coordinate::ned_north or Coordinate::frd_front.
Note that this type implements Deserialize despite having unsafe constructors – this is
because doing otherwise would be extremely unergonomic. However, when deserializing, the
coordinate system of the deserialized value is not checked, so this is a foot-gun to be
mindful of.
Implementations§
Source§impl<In> Coordinate<In>
impl<In> Coordinate<In>
Sourcepub fn build(components: <In::Convention as HasComponents>::Components) -> Self
pub fn build(components: <In::Convention as HasComponents>::Components) -> Self
Constructs a coordinate at the given (x, y, z) Cartesian point in the CoordinateSystem
In.
Sourcepub fn builder() -> Builder<In, Unset, Unset, Unset>where
In: CoordinateSystem,
pub fn builder() -> Builder<In, Unset, Unset, Unset>where
In: CoordinateSystem,
Provides a constructor for a Coordinate in the CoordinateSystem In.
Sourcepub fn from_cartesian(
x: impl Into<Length>,
y: impl Into<Length>,
z: impl Into<Length>,
) -> Self
👎Deprecated: prefer Coordinate::builder to avoid risk of argument order confusion
pub fn from_cartesian( x: impl Into<Length>, y: impl Into<Length>, z: impl Into<Length>, ) -> Self
Coordinate::builder to avoid risk of argument order confusionConstructs a coordinate at the given (x, y, z) Cartesian point in the CoordinateSystem
In.
Prefer Coordinate::builder, Coordinate::build, or coordinate to avoid risk of
argument order confusion. This function will be removed in a future version of Sguaba in
favor of those.
The meaning of x, y, and z is dictated by the CoordinateSystem::Convention of
In. For example, in NedLike, x is North, y is East, and z is “down” (ie,
orthogonal to the earth’s surface).
This method is permanently deprecated because it is particularly vulnerable to argument
order confusion (eg, accidentally passing in the “down” component of a FRD coordinate
first instead of last). Methods like Coordinate::builder and the coordinate! macro
should be preferred instead, as they do not have this problem. However, this method is
left for use-cases where those alternatives cannot be used, such as when writing code
that is fully generic over the coordinate system, and thus cannot use the safer
constructors provided by those APIs. If this applies to you, make sure you apply due
diligence when writing out the argument ordering.
Sourcepub fn from_spherical(
radius: impl Into<Length>,
polar: impl Into<Angle>,
azimuth: impl Into<Angle>,
) -> Self
pub fn from_spherical( radius: impl Into<Length>, polar: impl Into<Angle>, azimuth: impl Into<Angle>, ) -> Self
Constructs a coordinate at the given (r, θ, φ) spherical point in the CoordinateSystem
In.
This constructor follows the physics convention for spherical coordinates, which defines
- r as the radial distance, meaning the slant distance to origin;
- θ (theta) as the polar angle meaning the angle with respect to positive polar axis (Z); and
- φ (phi) as the azimuthal angle, meaning the angle of rotation from the initial meridian plane (positive X towards positive Y).
The axes and planes above are in turn dictated by the CoordinateSystem::Convention of
In. For example, in NedLike, the polar angle is the angle relative to straight down
and the azimuthal angle is the angle from North. In FrdLike, the polar angle is the
angle relative to “down” and the azimuthal angle is the angle from forward.
Note that this convention does not necessarily match the conventions of each coordinate
system. For example, in NedLike and FrdLike coordinate systems, we often talk about
“azimuth and elevation”, but those are distinct from the spherical coordinates. In that
context, the definition of azimuth (luckily) matches that of spherical coordinates, but
elevation tends to be defined as the angle from the positive X axis rather than from the
positive Z axis. If you want to define a coordinate based on azimuth and elevation, use
Coordinate::from_bearing.
§Examples
use approx::assert_relative_eq;
use sguaba::{coordinate, system, Coordinate};
use uom::si::f64::{Angle, Length};
use uom::si::{angle::degree, length::meter};
system!(struct Ned using NED);
let zero = Length::new::<meter>(0.);
let unit = Length::new::<meter>(1.);
assert_relative_eq!(
Coordinate::<Ned>::from_spherical(unit, Angle::new::<degree>(0.), Angle::new::<degree>(0.)),
coordinate!(n = zero, e = zero, d = unit),
);
assert_relative_eq!(
Coordinate::<Ned>::from_spherical(unit, Angle::new::<degree>(90.), Angle::new::<degree>(0.)),
coordinate!(n = unit, e = zero, d = zero),
);
assert_relative_eq!(
Coordinate::<Ned>::from_spherical(unit, Angle::new::<degree>(90.), Angle::new::<degree>(90.)),
coordinate!(n = zero, e = unit, d = zero),
);Sourcepub fn from_bearing(bearing: Bearing<In>, range: impl Into<Length>) -> Selfwhere
In: BearingDefined,
pub fn from_bearing(bearing: Bearing<In>, range: impl Into<Length>) -> Selfwhere
In: BearingDefined,
Constructs a coordinate at the given azimuth, elevation, and range in the
CoordinateSystem In.
This constructor is based on the bearing as it defined by the implementation of
BearingDefined for In. For NedLike and FrdLike coordinate systems, this is:
- azimuth is the angle clockwise as seen from “up” along the XY plane from the positive X axis (eg, North or Forward); and
- elevation is the angle towards Z from the XY plane; and
- r is the radial distance, meaning the slant distance to origin.
See also horizontal coordinate systems.
§Examples
use approx::assert_relative_eq;
use sguaba::{coordinate, system, Bearing, Coordinate};
use uom::si::f64::{Angle, Length};
use uom::si::{angle::degree, length::meter};
system!(struct Ned using NED);
let zero = Length::new::<meter>(0.);
let unit = Length::new::<meter>(1.);
assert_relative_eq!(
Coordinate::<Ned>::from_bearing(
Bearing::builder()
.azimuth(Angle::new::<degree>(0.))
.elevation(Angle::new::<degree>(0.)).expect("elevation is in-range")
.build(),
unit
),
coordinate!(n = unit, e = zero, d = zero),
);
assert_relative_eq!(
Coordinate::<Ned>::from_bearing(
Bearing::builder()
.azimuth(Angle::new::<degree>(90.))
.elevation(Angle::new::<degree>(0.)).expect("elevation is in-range")
.build(),
unit
),
coordinate!(n = zero, e = unit, d = zero),
);
assert_relative_eq!(
Coordinate::<Ned>::from_bearing(
Bearing::builder()
.azimuth(Angle::new::<degree>(90.))
.elevation(Angle::new::<degree>(90.)).expect("elevation is in-range")
.build(),
unit
),
coordinate!(n = zero, e = zero, d = -unit),
);Sourcepub fn origin() -> Self
pub fn origin() -> Self
Constructs a coordinate at the origin of the coordinate system In.
§Examples
use sguaba::{coordinate, system, Coordinate};
use uom::si::f64::{Length};
use uom::si::length::meter;
system!(struct Ned using NED);
let zero = Length::new::<meter>(0.);
assert_eq!(
Coordinate::<Ned>::origin(),
coordinate!(n = zero, e = zero, d = zero),
);Sourcepub unsafe fn map_as_zero_in<To>(self) -> RigidBodyTransform<In, To>
pub unsafe fn map_as_zero_in<To>(self) -> RigidBodyTransform<In, To>
Constructs a translation into CoordinateSystem To such that self is “zero” in To.
Less informally, if this translation is applied to this Coordinate<In>, it will yield
Coordinate::origin in Coordination<To>.
Conversely, if the inverse of this translation is applied to Coordinate::origin in
Orientation<To>, it will yield this Coordinate<In>.
Or, alternatively phrased, this yields a translation transformation that
- takes a coordinate, vector, or orientation observed by the object with this position
in the coordinate system
In; and - returns that coordinate or vector as if it were observed in a coordinate system (
To) where thisCoordinate<In>isCoordinate::origin.
Or, if you prefer a more mathematical description: this defines the pose of the whole
coordinate system To in In.
§Safety
This method allows you to end up with erroneous transforms if you’re not careful. See
Pose::map_as_zero_in for more details.
Specifically in the case of Coordinate, you are also asserting that only translation
(ie, no rotation) is needed to convert from In to To.
§Examples
use approx::assert_relative_eq;
use sguaba::{system, Bearing, Coordinate, engineering::Orientation, systems::Ecef};
use uom::si::f64::Length;
use uom::si::length::meter;
system!(struct PlaneCenteredEcef using right-handed XYZ);
// plane position in ECEF
let position = Coordinate::<Ecef>::builder()
.x(Length::new::<meter>(30_000.))
.y(Length::new::<meter>(25_000.))
.z(Length::new::<meter>(19_000.))
.build();
// plane observes something at a particular ECEF coordinate
let observation = Coordinate::<PlaneCenteredEcef>::builder()
.x(Length::new::<meter>(1_000.))
.y(Length::new::<meter>(6_000.))
.z(Length::new::<meter>(0.))
.build();
// if we now want this vector to be relative to the plane (ie, a direction
// of arrival vector), we need to map from one space to the other. so, we
// declare that the plane's position in ECEF is zero (ie, origin) in
// `PlaneCenteredEcef`:
let ecef_to_plane_centered_ecef = unsafe { position.map_as_zero_in::<PlaneCenteredEcef>() };
// this transformation lets us move from ECEF to plane-centered ECEF
// and vice-versa:
let observation_in_ecef = ecef_to_plane_centered_ecef.inverse_transform(observation);Sourcepub fn cast<NewIn>(self) -> Coordinate<NewIn>where
In: EquivalentTo<NewIn>,
pub fn cast<NewIn>(self) -> Coordinate<NewIn>where
In: EquivalentTo<NewIn>,
Casts the coordinate system type parameter of the coordinate to the equivalent coordinate
system NewIn.
See EquivalentTo for details on when this is useful (and safe).
Note that this performs no transform on the coordinate’s components, as that should be
unnecessary when EquivalentTo is implemented.
use sguaba::{coordinate, system, systems::EquivalentTo, Coordinate};
use uom::si::{f64::Length, length::meter};
system!(struct PlaneNedFromCrate1 using NED);
system!(struct PlaneNedFromCrate2 using NED);
// SAFETY: these are truly the same thing just defined in different places
unsafe impl EquivalentTo<PlaneNedFromCrate1> for PlaneNedFromCrate2 {}
unsafe impl EquivalentTo<PlaneNedFromCrate2> for PlaneNedFromCrate1 {}
let zero = Length::new::<meter>(0.);
let unit = Length::new::<meter>(1.);
let coordinate_in_1 = coordinate!(n = unit, e = zero, d = unit; in PlaneNedFromCrate1);
assert_eq!(
coordinate!{
n = coordinate_in_1.ned_north(),
e = coordinate_in_1.ned_east(),
d = coordinate_in_1.ned_down(),
},
coordinate_in_1.cast::<PlaneNedFromCrate2>()
);Source§impl<In> Coordinate<In>where
In: CoordinateSystem<Convention = RightHandedXyzLike>,
impl<In> Coordinate<In>where
In: CoordinateSystem<Convention = RightHandedXyzLike>,
Source§impl<In> Coordinate<In>where
In: CoordinateSystem<Convention = NedLike>,
impl<In> Coordinate<In>where
In: CoordinateSystem<Convention = NedLike>,
Source§impl<In> Coordinate<In>where
In: CoordinateSystem<Convention = FrdLike>,
impl<In> Coordinate<In>where
In: CoordinateSystem<Convention = FrdLike>,
Source§impl<In> Coordinate<In>where
In: CoordinateSystem<Convention = EnuLike>,
impl<In> Coordinate<In>where
In: CoordinateSystem<Convention = EnuLike>,
Source§impl<In> Coordinate<In>
impl<In> Coordinate<In>
Sourcepub fn to_cartesian(&self) -> [Length; 3]
pub fn to_cartesian(&self) -> [Length; 3]
Returns the cartesian components of this coordinate in XYZ order.
To turn this into a simple (ie, unitless) [f64; 3], use array::map combined with
.get::<meter>().
Sourcepub fn distance_from_origin(&self) -> Length
pub fn distance_from_origin(&self) -> Length
Computes the distance of this point from the coordinate system’s origin.
§Examples
use approx::assert_relative_eq;
use sguaba::{coordinate, Coordinate, Vector, systems::Ecef};
use uom::si::f64::{Length};
use uom::si:: length::meter;
let zero = Length::new::<meter>(0.);
let unit = Length::new::<meter>(1.);
let p = coordinate!(x = unit, y = unit, z = zero; in Ecef);
assert_eq!(
p.distance_from_origin(),
(p - Coordinate::<Ecef>::origin()).magnitude(),
);Sourcepub fn distance_from(&self, other: &Self) -> Length
pub fn distance_from(&self, other: &Self) -> Length
Computes the distance between this point and the given point.
§Examples
use approx::assert_relative_eq;
use sguaba::{coordinate, Coordinate, Vector, systems::Ecef};
use uom::si::f64::{Length};
use uom::si:: length::meter;
let zero = Length::new::<meter>(0.);
let unit = Length::new::<meter>(1.);
let p = coordinate!(x = unit, y = unit, z = zero; in Ecef);
assert_eq!(
p.distance_from(&Coordinate::<Ecef>::origin()),
p.distance_from_origin(),
);
assert_eq!(
p.distance_from(&p),
zero,
);Sourcepub fn bearing_from_origin(&self) -> Option<Bearing<In>>where
In: BearingDefined,
pub fn bearing_from_origin(&self) -> Option<Bearing<In>>where
In: BearingDefined,
Calculates the bearing towards the point from Coordinate::origin.
Returns None for Coordinate::origin as the azimuth to it is ill-defined.
Returns an azimuth of zero for coordinates along the Z axis.
Source§impl Coordinate<Ecef>
impl Coordinate<Ecef>
Sourcepub fn from_wgs84(wgs84: &Wgs84) -> Self
pub fn from_wgs84(wgs84: &Wgs84) -> Self
Converts latitude, longitude, and altitude to the Earth-Centered, Earth-Fixed coordinate system.
See: https://en.wikipedia.org/wiki/Geographic_coordinate_conversion#From_geodetic_to_ECEF_coordinates
Sourcepub fn to_wgs84(&self) -> Wgs84
pub fn to_wgs84(&self) -> Wgs84
Converts an Earth-Centered, Earth-Fixed coordinate into latitude, longitude, and altitude.
Note that this conversion is not trivial and needs to be approximated.
The implementation currently only guarantees conversion to WGS84 datums with altitude between -10km and 50km from the surface of the WGS84 ellipsoid, roughly corresponding to the bottom of the Mariana Trench to the top of the stratosphere. Outside this range, the implementation may panic.
This implementation currently uses Ferrari’s solution, but this may change in the future.
Trait Implementations§
Source§impl<In> AbsDiffEq for Coordinate<In>
Available on crate features approx only.
impl<In> AbsDiffEq for Coordinate<In>
approx only.Source§type Epsilon = Quantity<dyn Dimension<M = Z0, L = PInt<UInt<UTerm, B1>>, T = Z0, N = Z0, Th = Z0, I = Z0, Kind = dyn Kind, J = Z0>, dyn Units<f64, electric_current = ampere, length = meter, amount_of_substance = mole, mass = kilogram, time = second, luminous_intensity = candela, thermodynamic_temperature = kelvin>, f64>
type Epsilon = Quantity<dyn Dimension<M = Z0, L = PInt<UInt<UTerm, B1>>, T = Z0, N = Z0, Th = Z0, I = Z0, Kind = dyn Kind, J = Z0>, dyn Units<f64, electric_current = ampere, length = meter, amount_of_substance = mole, mass = kilogram, time = second, luminous_intensity = candela, thermodynamic_temperature = kelvin>, f64>
Source§fn default_epsilon() -> Self::Epsilon
fn default_epsilon() -> Self::Epsilon
Source§fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool
fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool
Source§fn abs_diff_ne(&self, other: &Rhs, epsilon: Self::Epsilon) -> bool
fn abs_diff_ne(&self, other: &Rhs, epsilon: Self::Epsilon) -> bool
AbsDiffEq::abs_diff_eq.Source§impl<In> Add<Vector<In>> for Coordinate<In>
impl<In> Add<Vector<In>> for Coordinate<In>
Source§impl<In> AddAssign<Vector<In>> for Coordinate<In>
impl<In> AddAssign<Vector<In>> for Coordinate<In>
Source§fn add_assign(&mut self, rhs: Vector<In>)
fn add_assign(&mut self, rhs: Vector<In>)
+= operation. Read moreSource§impl<In> Clone for Coordinate<In>
impl<In> Clone for Coordinate<In>
Source§impl<In: Debug> Debug for Coordinate<In>
impl<In: Debug> Debug for Coordinate<In>
Source§impl<In> Default for Coordinate<In>
impl<In> Default for Coordinate<In>
Source§impl<'de, In> Deserialize<'de> for Coordinate<In>
impl<'de, In> Deserialize<'de> for Coordinate<In>
Source§fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
fn deserialize<__D>(__deserializer: __D) -> Result<Self, __D::Error>where
__D: Deserializer<'de>,
Source§impl<In> Display for Coordinate<In>
impl<In> Display for Coordinate<In>
Source§impl From<Coordinate<Ecef>> for Wgs84
impl From<Coordinate<Ecef>> for Wgs84
Source§fn from(ecef: Coordinate<Ecef>) -> Self
fn from(ecef: Coordinate<Ecef>) -> Self
Source§impl<In> From<Coordinate<In>> for Vector<In, Z0>
impl<In> From<Coordinate<In>> for Vector<In, Z0>
Source§fn from(value: Coordinate<In>) -> Self
fn from(value: Coordinate<In>) -> Self
Source§impl<From, To> Mul<Coordinate<To>> for RigidBodyTransform<From, To>
impl<From, To> Mul<Coordinate<To>> for RigidBodyTransform<From, To>
Source§type Output = Coordinate<From>
type Output = Coordinate<From>
* operator.Source§impl<From, To> Mul<Coordinate<To>> for Rotation<From, To>
impl<From, To> Mul<Coordinate<To>> for Rotation<From, To>
Source§type Output = Coordinate<From>
type Output = Coordinate<From>
* operator.Source§impl<From, To> Mul<RigidBodyTransform<From, To>> for Coordinate<From>
impl<From, To> Mul<RigidBodyTransform<From, To>> for Coordinate<From>
Source§type Output = Coordinate<To>
type Output = Coordinate<To>
* operator.Source§impl<From, To> Mul<Rotation<From, To>> for Coordinate<From>
impl<From, To> Mul<Rotation<From, To>> for Coordinate<From>
Source§impl<In> Neg for Coordinate<In>
impl<In> Neg for Coordinate<In>
Source§impl<In> PartialEq for Coordinate<In>
impl<In> PartialEq for Coordinate<In>
Source§impl<In> RelativeEq for Coordinate<In>
Available on crate features approx only.
impl<In> RelativeEq for Coordinate<In>
approx only.Source§fn default_max_relative() -> Self::Epsilon
fn default_max_relative() -> Self::Epsilon
Source§fn relative_eq(
&self,
other: &Self,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool
fn relative_eq( &self, other: &Self, epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool
Source§fn relative_ne(
&self,
other: &Rhs,
epsilon: Self::Epsilon,
max_relative: Self::Epsilon,
) -> bool
fn relative_ne( &self, other: &Rhs, epsilon: Self::Epsilon, max_relative: Self::Epsilon, ) -> bool
RelativeEq::relative_eq.Source§impl<In> Serialize for Coordinate<In>
impl<In> Serialize for Coordinate<In>
Source§impl<In> Sub<Vector<In>> for Coordinate<In>
impl<In> Sub<Vector<In>> for Coordinate<In>
Source§impl<In> Sub for Coordinate<In>
impl<In> Sub for Coordinate<In>
Source§impl<In> SubAssign<Vector<In>> for Coordinate<In>
impl<In> SubAssign<Vector<In>> for Coordinate<In>
Source§fn sub_assign(&mut self, rhs: Vector<In>)
fn sub_assign(&mut self, rhs: Vector<In>)
-= operation. Read moreimpl<In> Copy for Coordinate<In>
Auto Trait Implementations§
impl<In> Freeze for Coordinate<In>
impl<In> RefUnwindSafe for Coordinate<In>where
In: RefUnwindSafe,
impl<In> Send for Coordinate<In>where
In: Send,
impl<In> Sync for Coordinate<In>where
In: Sync,
impl<In> Unpin for Coordinate<In>where
In: Unpin,
impl<In> UnsafeUnpin for Coordinate<In>
impl<In> UnwindSafe for Coordinate<In>where
In: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
impl<SS, SP> SupersetOf<SS> for SPwhere
SS: SubsetOf<SP>,
Source§fn to_subset(&self) -> Option<SS>
fn to_subset(&self) -> Option<SS>
self from the equivalent element of its
superset. Read moreSource§fn is_in_subset(&self) -> bool
fn is_in_subset(&self) -> bool
self is actually part of its subset T (and can be converted to it).Source§fn to_subset_unchecked(&self) -> SS
fn to_subset_unchecked(&self) -> SS
self.to_subset but without any property checks. Always succeeds.Source§fn from_subset(element: &SS) -> SP
fn from_subset(element: &SS) -> SP
self to the equivalent element of its superset.