Expand description
Convert WGS84 latitude-longitude to and from UTM, UPS, and MGRS.
The whole globe is covered: every valid latitude and longitude has a UTM
(latitudes -80 to 84) or UPS (the polar caps) representation and an MGRS
reference at every precision from 0 to 11 digit pairs, and every valid MGRS
reference names a cell with a well defined center. Forward and reverse both
ship. The projection core is the Krueger series to order n^6 from Karney,
“Transverse Mercator with an accuracy of a few nanometers” (2011). The MGRS
grid follows NGA TM 8358.1, checked cell by cell against GeographicLib’s
GeoConvert.
This crate is std (the projection core needs the f64 math functions) and
has zero runtime dependencies.
use mgrs_convert::{LatLon, Mgrs, Precision};
let position = LatLon::new(40.748333, -73.985278)?;
let cell = position.to_mgrs(Precision::ONE_METER);
assert_eq!(cell.to_string(), "18TWL8566411315");
let parsed: Mgrs = "18TWL8566411315".parse()?;
assert_eq!(parsed, cell);
let center = parsed.to_latlon();
assert!((center.lat() - 40.748333).abs() < 1e-5);
assert!((center.lon() + 73.985278).abs() < 1e-5);§Types
Four types, one error enum, nothing else:
LatLon, a validated geodetic coordinate. ItsLatLon::to_mgrsis infallible because every valid input has an MGRS reference.UtmUps, a grid coordinate, where zone 0 is UPS. ItsUtmUps::to_mgrsis fallible by design: the accepted transfer range extends 100 km past the MGRS grid on every side, and the ring in between returnsError::OutsideMgrsExtentinstead of panicking.Mgrs, a grid cell. Only constructible through validated paths, so itsDisplayis total. Reverse conversion returns the cell center.Precision, the validated digit-pair count, 0 through 11.
§Boundary behavior
- Latitude 0 and
-0.0are both northern, band N, on every path. - The UTM latitude interval is [-80, 84), matching GeoConvert: -80 exactly is UTM band C, 84 exactly is UPS north, and the last UTM latitude is one ulp below 84 (band X).
- A coordinate exactly on an excluded upper grid edge is nudged inside by 2^-28 m before truncation, so it formats as the last cell of its own square.
- Grid-zone-only references such as
"18T"are rejected withParseErrorKind::GridZoneOnly, because a cell six degrees wide has no useful center.
§Migrating from geoconvert
geoconvert 1.0 call | replacement |
|---|---|
LatLon::create(lat, lon) | LatLon::new |
latlon.to_mgrs(6) | latlon.to_mgrs(Precision::new(6)?) |
Mgrs::parse_str(s) | s.parse::<Mgrs>() |
mgrs.to_string() | unchanged |
mgrs.to_latlon() | unchanged |
UtmUps::create(z, north, e, n) | UtmUps::utm or UtmUps::ups |
utmups.to_mgrs(p) | utmups.to_mgrs(Precision::new(p)?)? |
Mgrs::create(...) | removed, construct via to_mgrs or parse |
The two new ?s are deliberate: precision validation and the MGRS-extent
check return errors a caller can print instead of panicking.
use mgrs_convert::{Error, Precision, UtmUps};
// Precision is validated at the edge.
assert!(matches!(Precision::new(12), Err(Error::PrecisionOutOfRange { .. })));
// The transfer ring converts to lat/lon but has no MGRS reference.
let ring = UtmUps::utm(18, true, 50_000.0, 4_511_315.0)?;
assert!(matches!(ring.to_mgrs(Precision::ONE_METER), Err(Error::OutsideMgrsExtent { .. })));§Performance
Linear per conversion, no allocation outside Display, no lookup table
computed at runtime. The doctest below is the quadratic-regression tripwire:
one hundred thousand round trips inside a generous fixed budget.
use mgrs_convert::{LatLon, Precision};
let start = std::time::Instant::now();
let mut checksum = 0.0_f64;
for i in 0..100_000_u32 {
let lat = -80.0 + (f64::from(i) * 1.6377) % 160.0;
let lon = -180.0 + (f64::from(i) * 3.9119) % 360.0;
let p = LatLon::new(lat, lon)?;
let back = p.to_utmups().to_latlon();
checksum += back.lat();
}
assert!(checksum.is_finite());
assert!(start.elapsed().as_secs() < 60, "quadratic regression tripwire");Structs§
- LatLon
- Geodetic coordinate on WGS84. Constructor-validated: latitude is a finite value in [-90, 90], longitude is finite and normalized to [-180, 180).
- Mgrs
- An MGRS cell, only constructible through the validated paths
LatLon::to_mgrs,UtmUps::to_mgrs, andstr::parse, soDisplayis total. - Precision
- Digit pairs in an MGRS reference, 0 through 11. Cell size is 10^(5-p) metres: 100 km at 0, 1 m at 5, 1 mm at 8, 1 um at 11.
- UtmUps
- UTM or UPS coordinate. Zone 0 is UPS, matching GeographicLib’s convention.
Enums§
- Error
- The reasons a conversion or a parse can fail.
- Parse
Error Kind - The first parse rule an invalid MGRS string broke.