Skip to main content

Crate geo3d

Crate geo3d 

Source
Expand description

§🌍 geo3d

3D positions on Earth, made simple.

Give geo3d a GPS position, then ask everyday questions:

  • 📍 Where is that plane, seen from here?
  • 📡 Which way should the antenna point?
  • 📏 How far apart are they?
  • 👀 Can they see each other?
  • 💥 Are they going to collide?

It’s pure Rust, with no dependencies.

use geo3d::{Geodetic, LocalFrame};

let me = Geodetic::new(51.5, -0.12, 30.0);          // latitude, longitude, height in metres
let plane = Geodetic::new(51.6, -0.12, 3_000.0);

let look = LocalFrame::new(me).look_angles(plane);   // which way to point
// due north, 14.9° up, 11.5 km away
assert!(look.elevation_deg > 14.0 && look.range_m > 11_000.0);

§✨ Why geo3d?

  • 🎯 Accurate. Conversions are exact, and distances along the ground are good to 15 nanometres. Everything is tested against GeographicLib, the reference library.
  • 🛡️ Reliable. It handles the tricky places, like the poles and opposite sides of the Earth, without NaN or panics.
  • 🧩 Easy to use. Degrees and metres everywhere, with named fields. Latitude always comes first.
  • 🪶 Light and fast. No dependencies, no unsafe code, and nothing allocates. Works on Rust 1.85 and newer.

§🗺️ The basics

Latitude and longitude are angles, so you can’t subtract two of them to get a distance. geo3d turns positions into frames where normal 3D maths works.

TypeWhat it holdsUnits
Geodeticlatitude, longitude and height, like GPS gives youdegrees, metres
Ecefx, y, z from the centre of the Earthmetres
Enu / Nedhow far east, north and up (or north, east and down) from youmetres
Aerazimuth, elevation and range: which way to pointdegrees, metres
Ecix, y, z that don’t spin with the Earth, for satellitesmetres
Vec3a plain 3D vector, like a velocitymetres, m/s

A few rules hold everywhere:

  • Latitude comes first: Geodetic::new(lat, lon, height).
  • Bearings go clockwise from north, from 0° to 360°.
  • Heights are above the WGS84 ellipsoid, like GPS. They are not heights above sea level.
  • WGS84 is the default, but any Ellipsoid works: GRS80.to_ecef(p).
  • A few low-level helpers use radians, and their names say so (lat_rad, gmst_rad). Vec3::angle_to also returns radians.

§🧭 Find what you need

I want to…Use
convert between latitude/longitude and x, y, zgeodetic_to_ecef, ecef_to_geodetic
find where something is, relative to meLocalFrame::enu_of, LocalFrame::ned_of
work out which way to point, and backLocalFrame::look_angles, LocalFrame::destination
find where a line of sight hits the groundground_strike, Ellipsoid::ray_intersect
measure a straight line through spacedistance3d_m
measure distance along the groundEllipsoid::geodesic_inverse (exact), Ellipsoid::great_circle_distance_m (quick)
travel a distance on a bearingEllipsoid::geodesic_direct, Ellipsoid::great_circle_destination
check if something is inside a zoneSphere, Cone, Cylinder, AltitudeBand (all are Volumes)
check if two objects will collideTrack::conflict, closest_approach
turn a velocity into heading, speed and climbCourse, LocalFrame::course_of_velocity
check line of sight, or how far I can seeEllipsoid::line_of_sight, Ellipsoid::horizon_distance_m
track satellitesthe eci module
shift between datumsHelmert7

More worked examples, a comparison with other crates and an accuracy table are in the README.

§🧩 Optional features

They’re all off by default, so a plain cargo add geo3d pulls in nothing else.

FeatureWhat it adds
serdesaving and loading every type
mintconversions to mint types, and through them to cgmath and others
glamconversions to glam::DVec3
nalgebraconversions to nalgebra vectors and points
geo-typesGeodetic ↔ geo_types::Point (x is longitude, y is latitude)

Modules§

eci
Earth-fixed (Ecef) ↔ inertial (Eci): undo the Earth’s spin for satellite work.

Structs§

Aer
Where to point from an observer: azimuth in degrees clockwise from north, elevation in degrees above the horizon, and range in metres. The look angles a radar, antenna or telescope uses.
AltitudeBand
A range of heights with an optional floor and ceiling, metres — a slice of airspace. A None bound is open on that side. Combine it with any 2D footprint test (from geo, PostGIS, …) for an extruded shape:
Cone
A cone from an apex, pointing along an azimuth and elevation (degrees), with a half-angle spread (degrees) and a reach (metres) — a camera’s field of view, an antenna beam or a scan sector.
Course
Motion over the ground at a position: course in degrees clockwise from north, ground speed and climb rate in m/s — what ADS-B, AIS and GNSS receivers report. Turn it into an ECEF velocity at a position with LocalFrame::velocity_of_course.
Cpa
The closest point of approach of two moving objects: when, and how close.
Cylinder
A circle on the ground extruded through an AltitudeBand — circular airspace, or a geofence with a height range. Distance from the centre is measured flat in the centre’s local frame, which is accurate for radii up to a few hundred km.
Ecef
A position in Earth-Centred, Earth-Fixed coordinates, metres. The origin is the Earth’s centre, x points to latitude 0° longitude 0°, y to longitude 90° east and z to the North Pole. The axes turn with the Earth, so a parked car keeps the same Ecef.
Eci
A position in Earth-Centred Inertial coordinates, metres: like Ecef, but the axes do not turn with the Earth. This is the TEME frame that SGP4 / TLE satellite propagators output, not J2000 / GCRF. Convert with Ecef::to_eci / Eci::to_ecef; see the eci module.
Ellipsoid
A reference ellipsoid: the smooth, slightly flattened sphere that latitude, longitude and height are measured on. Defined by its equatorial radius a (metres) and flattening f.
Enu
An offset in a local East-North-Up frame, metres: how far east, north and up something is from an observer. Get one from a LocalFrame. Supports +, -, * f64 and unary -.
Geodesic
The shortest path between two positions along the ellipsoid surface.
Geodetic
A position as latitude and longitude in degrees and height in metres — what a GPS receiver reports.
Helmert7
A 7-parameter Helmert (Bursa-Wolf) transformation: moves ECEF positions from one datum to another with a shift (metres), a small rotation (radians) and a scale change (unitless, ppm × 1e-6). Build it from published parameters with position_vector or coordinate_frame.
LocalFrame
A local East-North-Up frame anchored at an observer — a flat “map” tangent to the Earth at that point, with up along the ellipsoid normal.
Ned
An offset in a local North-East-Down frame, metres — the aerospace convention. The same as Enu with the axes reordered and up flipped to down. Supports +, -, * f64 and unary -.
Sphere
A ball of radius_m around a centre — a range, coverage or proximity bubble. Distance is the straight line through space.
Track
A moving object: ECEF position (metres) and velocity (m/s), assumed constant.
Vec3
A plain 3D vector: a direction, an offset or a velocity. Metres (or m/s), unitless for a direction. Supports +, -, * f64, / f64 and unary -.

Constants§

AIRY_1830
Airy 1830 (OSGB36, Great Britain).
BESSEL_1841
Bessel 1841.
CLARKE_1866
Clarke 1866 (NAD27).
GRS80
GRS 80 — under most modern national datums (NAD83, GDA94/2020, ETRS89).
INTERNATIONAL_1924
International 1924 (Hayford).
PZ90
PZ-90 (GLONASS).
WGS72
WGS 72.
WGS84
WGS 84 — GPS, and the frame CesiumJS renders in. The default.

Traits§

Volume
A 3D shape that can answer “is this position inside?”.

Functions§

closest_approach
When and how close two objects get, from their ECEF positions (metres) and velocities (m/s), assuming both keep going in a straight line at steady speed. Compare distance_m with a separation threshold for aircraft, vessels or rendezvous — or use Track::conflict.
distance3d_m
The straight-line distance between two positions through space, metres — the slant range between things at height, not the distance along the surface. On WGS84.
ecef_to_geodetic
x, y, z → latitude/longitude/height on WGS84. Shorthand for WGS84.to_geodetic.
geodetic_to_ecef
Latitude/longitude/height → x, y, z on WGS84. Shorthand for WGS84.to_ecef.
ground_strike
Where the line of sight from observer along azimuth_deg (0 = north, clockwise) and elevation_deg (0 = horizon, negative = down) first meets the ground, on WGS84. None if it points into space or the observer is below the surface. Shorthand for LocalFrame::ground_strike.