Skip to main content

Crate jord

Crate jord 

Source
Expand description

§Jord - Geographical Position Calculations

crates.io docs.rs downloads build coverage license

Jord (Swedish) is Earth (English)

jord is a Rust crate for exact geodetic, geocentric and great-circle position calculations on both spherical and ellipsoidal Earth models — ECEF/n-vector conversions, local reference frames (NED, ENU, body, wander-azimuth), great circle navigation, kinematics, and spherical polygon (“Loop”) geometry.

If you’re looking for planar/projected geometry and boolean operations on generic 2D shapes, see the geo crate instead — jord focuses specifically on accurate positions and geometry on the Earth (geodesic/great-circle math, not straight-edge planar math), and provides optional interop with geo-types/geo-traits for the pieces that do overlap.

For ellipsoidal geodesic distance/bearing (Vincenty/Karney), see geographiclib-rs (pure Rust) or geographiclib (C++ bindings, faster) - jord’s GeodeticPosition converts to their plain lat/lon/metres inputs via .latitude().as_degrees() etc…

§Table of contents

§Installation

cargo add jord

or add it to Cargo.toml directly:

[dependencies]
jord = "0.20.0"

To enable an optional feature, e.g. geo-types:

cargo add jord --features geo-types

§Capabilities

  • Conversions between ECEF (earth-centred, earth-fixed), latitude/longitude and n-vector positions, for both spherical and ellipsoidal models.
  • Local reference frames:
    • Body, local-level/wander-azimuth, NED (north, east, down) and ENU (east, north, up).
    • Delta between two positions, destination position from a reference position and a delta.
    • Frame transformation (translation and/or rotation).
  • Great circle (spherical) navigation: surface distance, initial & final bearing, interpolated position, mean position, minor arc intersection, cross track distance, angle turned, side of position, projection on minor arc & great circle, …
  • Kinematics (spherical): closest point of approach between tracks, minimum speed for intercept, time to intercept.
  • Spherical Loops (“simple polygon”): convex/concave, clockwise/anti-clockwise, contains position, spherical excess, topological relationship, minimum bounding rectangle, triangulation, spherical excess, …
  • Spherical Caps and Rectangular Regions.
  • Location-dependent radii of ellipsoids.

§Literature

The following references provide the theoretical basis of most of the algorithms:

§Cargo features

All of the following are disabled by default:

§Solutions to the 10 examples from NavLab

§Example 1: A and B to delta

Given two positions A and B. Find the exact vector from A to B in meters north, east and down, and find the direction (azimuth/bearing) to B, relative to north. Use WGS-84 ellipsoid.

use jord::{Angle, GeodeticPosition, Length, NVector, PositionVector, Surface};
use jord::local::NedFrame;
use jord::ellipsoidal::Ellipsoid;

let a = GeodeticPosition::new(
    NVector::from_lat_long_degrees(1.0, 2.0),
    Length::from_metres(3.0)
);

let b = GeodeticPosition::new(
    NVector::from_lat_long_degrees(4.0, 5.0),
    Length::from_metres(6.0)
);

let e = Ellipsoid::WGS84;
let ned = NedFrame::from_geodetic(a, e);
let delta = ned.local_vector_to(e.geodetic_to_geocentric_position(b));

assert_eq!(Length::from_metres(331730.863), delta.x().round_mm()); // north
assert_eq!(Length::from_metres(332998.501), delta.y().round_mm()); // east
assert_eq!(Length::from_metres(17398.304), delta.z().round_mm()); // down
assert_eq!(Length::from_metres(470357.384), delta.slant_range().round_mm());
assert_eq!(Angle::from_degrees(45.10926), delta.bearing().round_d5());
assert_eq!(Angle::from_degrees(-2.11983), delta.elevation().round_d5());

§Example 2: B and delta to C

Given the position of vehicle B and a bearing and distance to an object C. Find the exact position of C. Use WGS-72 ellipsoid.

use jord::{Angle, GeodeticPosition, LatLong, Length, NVector,PositionVector, Surface, Vec3};
use jord::local::{BodyFrame, BodyVector};
use jord::ellipsoidal::Ellipsoid;

let b = GeodeticPosition::new(
    NVector::new(Vec3::new_unit(1.0, 2.0, 3.0)),
    Length::from_metres(400.0)
);

let e = Ellipsoid::WGS72;

let yaw = Angle::from_degrees(10.0);
let pitch = Angle::from_degrees(20.0);
let roll = Angle::from_degrees(30.0);
let body = BodyFrame::from_geodetic(yaw, pitch, roll, b, e);
let delta = BodyVector::from_metres(3000.0, 2000.0, 100.0);

let c = e.geocentric_to_geodetic_position(body.destination_position(delta));
let c_ll = LatLong::from_nvector(c.horizontal_position());

assert_eq!(Angle::from_degrees(53.32638), c_ll.latitude().round_d5());
assert_eq!(Angle::from_degrees(63.46812), c_ll.longitude().round_d5());
assert_eq!(Length::from_metres(406.007), c.height().round_mm());

§Example 3: ECEF-vector to geodetic latitude

Given an ECEF-vector of a position. Find geodetic latitude, longitude and height (using WGS-84 ellipsoid).

use jord::{Angle, GeocentricPosition, LatLong, Length, Surface};
use jord::ellipsoidal::Ellipsoid;

let c = GeocentricPosition::from_metres(0.9*6371e3, -1.0*6371e3, 1.1*6371e3);
let p = Ellipsoid::WGS84.geocentric_to_geodetic_position(c);

let p_ll = LatLong::from_nvector(p.horizontal_position());
assert_eq!(Angle::from_degrees(39.37875), p_ll.latitude().round_d5());
assert_eq!(Angle::from_degrees(-48.01279), p_ll.longitude().round_d5());
assert_eq!(Length::from_metres(4702059.834), p.height().round_mm());

§Example 4: Geodetic latitude to ECEF-vector

Given geodetic latitude, longitude and height. Find the ECEF-vector (using WGS-84 ellipsoid).

use jord::{GeocentricPosition, GeodeticPosition, Length, NVector, PositionVector, Surface};
use jord::ellipsoidal::Ellipsoid;

let p = GeodeticPosition::new(
    NVector::from_lat_long_degrees(1.0, 2.0),
    Length::from_metres(3.0)
);

let c = Ellipsoid::WGS84.geodetic_to_geocentric_position(p);

assert_eq!(
    GeocentricPosition::from_metres(6_373_290.277, 222_560.201, 110_568.827),
    c.round_mm(),
);

The following examples assume a spherical Earth model

§Example 5: Surface distance

Given position A and B. Find the surface distance (i.e. great circle distance).

use jord::{Length, NVector};
use jord::spherical::Sphere;

let a = NVector::from_lat_long_degrees(88.0, 0.0);
let b = NVector::from_lat_long_degrees(89.0, -170.0);

assert_eq!(
    Length::from_kilometres(332.456),
    Sphere::EARTH.distance(a, b).round_m()
);

§Example 6: Interpolated position

Given the position of B at time t0 and t1. Find an interpolated position at time ti.

use jord::{LatLong, NVector};
use jord::spherical::Sphere;

let a = NVector::from_lat_long_degrees(89.9, -150.0);
let b = NVector::from_lat_long_degrees(89.9, 150.0);

let t0 = 10.0;
let t1 = 20.0;
let ti = 16.0;

let f = (ti - t0) / (t1 - t0);
let pi = Sphere::interpolated_position(a, b, f);

assert!(pi.is_some());
assert_eq!(
    LatLong::from_degrees(89.91282, 173.41323),
    LatLong::from_nvector(pi.unwrap()).round_d5()
);

§Example 7: Mean position/center

Given three positions A, B, and C. Find the mean position (center/midpoint).

use jord::{LatLong, NVector};
use jord::spherical::Sphere;

let ps = vec![
    NVector::from_lat_long_degrees(90.0, 0.0),
    NVector::from_lat_long_degrees(60.0, 10.0),
    NVector::from_lat_long_degrees(50.0, -20.0)
];

let m = Sphere::mean_position(&ps);

assert!(m.is_some());
assert_eq!(
    LatLong::from_degrees(67.23615, -6.91751),
    LatLong::from_nvector(m.unwrap()).round_d5()
);

§Example 8: A and azimuth/distance to B

Given position A and an azimuth/bearing and a (great circle) distance. Find the destination point B.

use jord::{Angle, LatLong, Length, NVector};
use jord::spherical::Sphere;

let p =  NVector::from_lat_long_degrees(80.0, -90.0);
let azimuth = Angle::from_degrees(200.0);
let distance = Length::from_metres(1000.0);

let d = Sphere::EARTH.destination_position(p, azimuth, distance);

assert_eq!(
    LatLong::from_degrees(79.99155, -90.01770),
    LatLong::from_nvector(d).round_d5()
);

§Example 9: Intersection of two paths / triangulation

Given path A going through A1 and A2, and path B going through B1 and B2. Find the intersection of the two paths.

use jord::{LatLong, NVector};
use jord::spherical::MinorArc;

let a = MinorArc::new(
    NVector::from_lat_long_degrees(50.0, 180.0),
    NVector::from_lat_long_degrees(90.0, 180.0)
);

let b = MinorArc::new(
    NVector::from_lat_long_degrees(60.0, 160.0),
    NVector::from_lat_long_degrees(80.0, -140.0)
);

let i = a.intersection(b);

assert!(i.is_some());
assert_eq!(
    LatLong::from_degrees(74.16345, 180.0),
    LatLong::from_nvector(i.unwrap()).round_d5()
);

§Example 10: Cross track distance (cross track error)

Given path A going through A1 and A2, and a point B. Find the cross track distance/cross track error between B and the path.

use jord::{LatLong, Length, NVector};
use jord::spherical::{GreatCircle, Sphere};

let a = GreatCircle::new(
    NVector::from_lat_long_degrees(0.0, 0.0),
    NVector::from_lat_long_degrees(10.0, 0.0)
);

let b =  NVector::from_lat_long_degrees(1.0, 0.1);

let d = Sphere::EARTH.cross_track_distance(b, a);

assert_eq!(Length::from_metres(11117.8), d.round_dm());

§Contributing

Issues and pull requests are welcome on GitHub.

§License

jord is licensed under the MIT license.

Modules§

ellipsoidal
Geographical position calculations assuming an ellipsoidal model.
local
Local (topocentric) reference frames and the vectors within them.
spherical
Geographical position calculations assuming a spherical model.

Macros§

impl_measurement
Macro that creates the code to implement operator overrides.

Structs§

Angle
A one-dimensional angle.
GeocentricPosition
A geocentric position or Earth Centred Earth Fixed (ECEF) vector.
GeodeticPosition
A geodetic position: the horiztonal coordinates (as a NVector) and height above the surface.
LatLong
An horizontal position represented by a pair of latitude-longitude.
Length
A length.
Mat33
A 3*3 matrix.
NVector
An horizontal position represented by a n-vector: the unit and normal vector to the surface.
Speed
A speed.
Vec3
A 3-element vector.
Vehicle
The state of a vehicle: its horizontal position and velocity (bearing and speed).

Traits§

Measurement
Trait implemented by all measurable quantities.
PositionVector
Position vector: allows to represent the position of a general coordinate frame B relative to a reference coordinate frame A as the position vector from A to B.
Surface
The reference surface for a celestial body (e.g. Earth) on which calculations are done.