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
unsafecode, 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.
| Type | What it holds | Units |
|---|---|---|
Geodetic | latitude, longitude and height, like GPS gives you | degrees, metres |
Ecef | x, y, z from the centre of the Earth | metres |
Enu / Ned | how far east, north and up (or north, east and down) from you | metres |
Aer | azimuth, elevation and range: which way to point | degrees, metres |
Eci | x, y, z that don’t spin with the Earth, for satellites | metres |
Vec3 | a plain 3D vector, like a velocity | metres, 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.
WGS84is the default, but anyEllipsoidworks:GRS80.to_ecef(p).- A few low-level helpers use radians, and their names say so (
lat_rad,gmst_rad).Vec3::angle_toalso returns radians.
§🧭 Find what you need
| I want to… | Use |
|---|---|
| convert between latitude/longitude and x, y, z | geodetic_to_ecef, ecef_to_geodetic |
| find where something is, relative to me | LocalFrame::enu_of, LocalFrame::ned_of |
| work out which way to point, and back | LocalFrame::look_angles, LocalFrame::destination |
| find where a line of sight hits the ground | ground_strike, Ellipsoid::ray_intersect |
| measure a straight line through space | distance3d_m |
| measure distance along the ground | Ellipsoid::geodesic_inverse (exact), Ellipsoid::great_circle_distance_m (quick) |
| travel a distance on a bearing | Ellipsoid::geodesic_direct, Ellipsoid::great_circle_destination |
| check if something is inside a zone | Sphere, Cone, Cylinder, AltitudeBand (all are Volumes) |
| check if two objects will collide | Track::conflict, closest_approach |
| turn a velocity into heading, speed and climb | Course, LocalFrame::course_of_velocity |
| check line of sight, or how far I can see | Ellipsoid::line_of_sight, Ellipsoid::horizon_distance_m |
| track satellites | the eci module |
| shift between datums | Helmert7 |
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.
| Feature | What it adds |
|---|---|
serde | saving and loading every type |
mint | conversions to mint types, and through them to cgmath and others |
glam | conversions to glam::DVec3 |
nalgebra | conversions to nalgebra vectors and points |
geo-types | Geodetic ↔ geo_types::Point (x is longitude, y is latitude) |
Modules§
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.
- Altitude
Band - A range of heights with an optional floor and ceiling, metres — a slice of airspace. A
Nonebound is open on that side. Combine it with any 2D footprint test (fromgeo, 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,
xpoints to latitude 0° longitude 0°,yto longitude 90° east andzto the North Pole. The axes turn with the Earth, so a parked car keeps the sameEcef. - 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 withEcef::to_eci/Eci::to_ecef; see theecimodule. - 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 flatteningf. - 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+,-,* f64and 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 withposition_vectororcoordinate_frame. - Local
Frame - 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
Enuwith the axes reordered and up flipped to down. Supports+,-,* f64and unary-. - Sphere
- A ball of
radius_maround 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,/ f64and 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_mwith a separation threshold for aircraft, vessels or rendezvous — or useTrack::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 forWGS84.to_geodetic. - geodetic_
to_ ecef - Latitude/longitude/height → x, y, z on
WGS84. Shorthand forWGS84.to_ecef. - ground_
strike - Where the line of sight from
observeralongazimuth_deg(0 = north, clockwise) andelevation_deg(0 = horizon, negative = down) first meets the ground, onWGS84.Noneif it points into space or the observer is below the surface. Shorthand forLocalFrame::ground_strike.