--- title: "Grid Reference Systems: MGRS, Geohash, GARS, and Georef" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Grid Reference Systems: MGRS, Geohash, GARS, and Georef} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r, include = FALSE} knitr::opts_chunk$set( collapse = TRUE, comment = "#>" ) ``` ```{r setup} library(geographiclib) ``` ## Contents - [Example Locations](#example-locations) - [MGRS - Military Grid Reference System](#mgrs---military-grid-reference-system) - [Geohash](#geohash) - [GARS - Global Area Reference System](#gars---global-area-reference-system) - [Georef - World Geographic Reference System](#georef---world-geographic-reference-system) - [Comparison of Systems](#comparison-of-systems) - [GeoCoords - Universal Coordinate Parsing](#geocoords---universal-coordinate-parsing) - [DMS - Degrees, Minutes, Seconds Conversion](#dms---degrees-minutes-seconds-conversion) - [See Also](#see-also) This vignette covers the grid reference systems available in geographiclib: MGRS, Geohash, GARS, and Georef. These systems encode geographic coordinates as alphanumeric strings, useful for human communication and data storage. It also covers GeoCoords for universal coordinate parsing and conversion, and DMS functions for degrees-minutes-seconds formatting. ## Example Locations We'll use locations from both hemispheres throughout this vignette: ```{r locations} locations <- data.frame( name = c("Sydney", "Hobart", "McMurdo Station", "South Pole", "London", "New York", "Tokyo", "Ushuaia"), lon = c(151.21, 147.32, 166.67, 0, -0.13, -74.01, 139.69, -68.30), lat = c(-33.87, -42.88, -77.85, -90, 51.51, 40.71, 35.69, -54.80) ) locations ``` ## MGRS - Military Grid Reference System MGRS is used by NATO militaries and provides unambiguous location references worldwide. It's based on UTM zones (or UPS for polar regions). ### Basic Conversion ```{r mgrs-basic} # Convert all locations to MGRS pts <- cbind(locations$lon, locations$lat) codes <- mgrs_fwd(pts) data.frame(name = locations$name, mgrs = codes) ``` ### Understanding MGRS Codes An MGRS code has several components: - **Grid Zone Designator** (e.g., "56H"): UTM zone number + latitude band letter - **100km Square ID** (e.g., "LU"): Two letters identifying the 100km square - **Numerical Location**: Easting and northing within the square ```{r mgrs-structure} # Sydney's MGRS code broken down sydney_mgrs <- mgrs_fwd(c(151.21, -33.87)) sydney_mgrs # Get full metadata from reverse conversion mgrs_rev(sydney_mgrs) ``` ### Precision Levels MGRS precision ranges from 100km (precision 0) to 1m (precision 5): ```{r mgrs-precision} hobart <- c(147.32, -42.88) precisions <- data.frame( precision = 0:5, resolution = c("100 km", "10 km", "1 km", "100 m", "10 m", "1 m"), code = sapply(0:5, function(p) mgrs_fwd(hobart, precision = p)) ) precisions ``` ### Polar Regions (UPS) For polar regions (>84°N or <80°S), MGRS uses Universal Polar Stereographic: ```{r mgrs-polar} # Antarctic locations antarctic <- cbind( lon = c(166.67, 0, 77.85, -60), lat = c(-77.85, -90, -85, -82) ) antarctic_mgrs <- mgrs_fwd(antarctic) antarctic_mgrs # Note zone = 0 indicates UPS mgrs_rev(antarctic_mgrs) ``` ### Vectorized Operations All MGRS functions are fully vectorized: ```{r mgrs-vectorized} # Different precisions for different points varied_precision <- mgrs_fwd(pts, precision = c(5, 4, 3, 2, 1, 0, 5, 4)) data.frame(name = locations$name, mgrs = varied_precision) ``` ## Geohash Geohash encodes locations as base-32 strings with a useful property: truncating a geohash reduces precision but still contains the original point. ### Basic Conversion ```{r geohash-basic} codes <- geohash_fwd(pts, len = 8) data.frame(name = locations$name, geohash = codes) ``` ### The Truncation Property This is Geohash's key feature - shorter codes are valid parent cells: ```{r geohash-truncation} # Full precision for Sydney sydney_gh <- geohash_fwd(c(151.21, -33.87), len = 12) sydney_gh # Truncate to see parent cells data.frame( length = 12:4, geohash = substr(sydney_gh, 1, 12:4) ) ``` ### Resolution by Length ```{r geohash-resolution} geohash_resolution(1:12) ``` ### Finding Required Length for Precision ```{r geohash-length} # What length for ~1km precision? geohash_length(resolution = 1/111) # ~1 degree / 111 km # What length for ~10m precision? geohash_length(resolution = 10/111000) ``` ### Southern Hemisphere Examples ```{r geohash-southern} southern <- cbind( lon = c(151.21, 147.32, 166.67, -68.30, 77.85), lat = c(-33.87, -42.88, -77.85, -54.80, -85) ) rownames(southern) <- c("Sydney", "Hobart", "McMurdo", "Ushuaia", "Amundsen-Scott area") # Convert and reverse gh_codes <- geohash_fwd(southern, len = 8) gh_codes geohash_rev(gh_codes) ``` ## GARS - Global Area Reference System GARS is a military grid system with three precision levels: 30-minute, 15-minute, and 5-minute cells. ### Basic Conversion ```{r gars-basic} codes <- gars_fwd(pts, precision = 2) # 5-minute precision data.frame(name = locations$name, gars = codes) ``` ### Precision Levels ```{r gars-precision} sydney <- c(151.21, -33.87) gars_codes <- data.frame( precision = 0:2, resolution = c("30 minute", "15 minute", "5 minute"), code = sapply(0:2, function(p) gars_fwd(sydney, precision = p)) ) gars_codes ``` ### GARS for Antarctic Locations ```{r gars-antarctic} antarctic_pts <- cbind( lon = c(166.67, 0, 77.85), lat = c(-77.85, -85, -82) ) gars_fwd(antarctic_pts, precision = 2) ``` ## Georef - World Geographic Reference System Georef is used primarily in aviation. It divides the world into 15° × 15° tiles then subdivides progressively. ### Basic Conversion ```{r georef-basic} codes <- georef_fwd(pts, precision = 2) data.frame(name = locations$name, georef = codes) ``` ### Precision Levels ```{r georef-precision} sydney <- c(151.21, -33.87) georef_codes <- data.frame( precision = c(-1, 0, 2, 3), resolution = c("15 degree", "1 degree", "0.01 minute", "0.001 minute"), code = sapply(c(-1, 0, 2, 3), function(p) georef_fwd(sydney, precision = p)) ) georef_codes ``` ### Georef for Flight Planning Georef is particularly useful for aviation across hemispheres: ```{r georef-flight} # Flight path: Sydney to Santiago via Antarctica flight_pts <- cbind( lon = c(151.21, 166.67, -70, -70.67), lat = c(-33.87, -77.85, -85, -33.45) ) rownames(flight_pts) <- c("Sydney", "McMurdo", "Over Antarctica", "Santiago") georef_fwd(flight_pts, precision = 2) ``` ## Comparison of Systems Each system has different strengths: | System | Best For | Precision Range | Key Feature | |--------|----------|-----------------|-------------| | MGRS | Military, hiking | 100km - 1m | Unambiguous worldwide | | Geohash | Databases, URLs | ~5000km - 1mm | Truncation preserves containment | | GARS | Military aviation | 30min - 5min | Simple, easy to read | | Georef | Aviation | 15° - 0.001min | Used in flight planning | | GeoCoords | Format conversion | N/A | Parses multiple input formats | | DMS | Human-readable | Variable | Degrees, minutes, seconds notation | ```{r comparison} # Same location in all systems pt <- c(147.32, -42.88) # Hobart data.frame( system = c("MGRS", "Geohash", "GARS", "Georef", "DMS"), code = c( mgrs_fwd(pt, precision = 3), geohash_fwd(pt, len = 8), gars_fwd(pt, precision = 2), georef_fwd(pt, precision = 2), paste( dms_encode(pt[2], prec = 4, indicator = "latitude"), dms_encode(pt[1], prec = 4, indicator = "longitude") ) ) ) ``` ## GeoCoords - Universal Coordinate Parsing The `geocoords_parse()` function provides a flexible way to parse coordinate strings in multiple formats. This is particularly useful when working with data from different sources that may use different coordinate formats. ### Parsing Various Formats `geocoords_parse()` accepts coordinates in many formats: ```{r geocoords-parse} # Parse MGRS codes geocoords_parse("33TWN0500049000") # Parse UTM strings geocoords_parse("33N 505000 4900000") # Parse DMS (degrees, minutes, seconds) geocoords_parse("44d 0' 0\" N 33d 0' 0\" E") # Parse decimal degrees (lat lon format) geocoords_parse("44.0 33.0") ``` ### Parsing Multiple Coordinates The function is vectorized for batch processing: ```{r geocoords-batch} # Mixed format inputs inputs <- c( "56HLU1060372300", # MGRS (Sydney area) "55G 530000 5250000", # UTM (Hobart area) "-33.87 151.21", # Decimal degrees "51d 30' 0\" N 0d 7' 0\" W" # DMS (London) ) parsed <- geocoords_parse(inputs) parsed[, c("lat", "lon", "zone", "northp")] ``` ### Integration with Other Functions Once parsed, coordinates can be used with any grid reference or projection function: ```{r geocoords-integration} # Parse any input format input <- "33TWN0500049000" coords <- geocoords_parse(input) # Then use with any system pt <- c(coords$lon, coords$lat) data.frame( input = input, lat = coords$lat, lon = coords$lon, mgrs = mgrs_fwd(pt, precision = 5), geohash = geohash_fwd(pt, len = 8), gars = gars_fwd(pt, precision = 2), georef = georef_fwd(pt, precision = 2) ) ``` ## DMS - Degrees, Minutes, Seconds Conversion ## DMS - Degrees, Minutes, Seconds Conversion The DMS functions provide flexible parsing and formatting of angles in degrees-minutes-seconds notation. This is useful for working with coordinate data from various sources that use different formats. ### Parsing DMS Strings `dms_decode()` parses DMS strings and returns the angle in decimal degrees: ```{r dms-decode} # Parse with hemisphere indicator dms_decode("40d26'47\"N") # Parse various formats dms_decode(c( "40:26:47", # Colon-separated "-74d0'21.5\"", # Negative with d-'-" separators "51d30'N", # Degrees and minutes only "40.446S" # Decimal with hemisphere )) ``` The function returns both the angle and an indicator showing whether a hemisphere designator was present (0=none, 1=latitude N/S, 2=longitude E/W). ### Parsing Coordinate Pairs For latitude/longitude pairs, `dms_decode_latlon()` handles the hemisphere logic automatically: ```{r dms-latlon} # Parse a coordinate pair dms_decode_latlon("40d26'47\"N", "74d0'21.5\"W") # Vectorized for multiple coordinates dms_decode_latlon( c("40d26'47\"N", "51d30'0\"N", "-33d52'10\""), c("74d0'21.5\"W", "0d7'0\"W", "151d12'30\"") ) ``` ### Parsing Angles and Azimuths For angles without coordinates (like bearings or field-of-view): ```{r dms-angle-azimuth} # Parse angles (no hemisphere designators allowed) dms_decode_angle(c("45:30:0", "123d45'6\"", "90.5")) # Parse azimuths (E/W allowed, result in [-180, 180]) dms_decode_azimuth(c("45:30:0", "90W", "135E")) ``` ### Encoding to DMS Strings Convert decimal degrees to formatted DMS strings: ```{r dms-encode} # Basic encoding with automatic component selection dms_encode(40.446195, prec = 5) dms_encode(c(40.446, -74.006), prec = 3) # With hemisphere indicators dms_encode(40.446195, prec = 5, indicator = "latitude") dms_encode(-74.006328, prec = 5, indicator = "longitude") # Azimuth format (always positive, 0-360) dms_encode(-45.5, indicator = "azimuth", prec = 4) ``` ### Output Formats Control the output format with precision and separator options: ```{r dms-format} angle <- 40.446195 # Different precisions data.frame( prec = 0:6, output = sapply(0:6, function(p) dms_encode(angle, prec = p)) ) # Colon separator (ISO 6709 style) dms_encode(angle, prec = 5, sep = ":") # Force specific trailing component dms_encode(angle, component = "minute", prec = 4) dms_encode(angle, component = "second", prec = 2) ``` ### Splitting and Combining Components Work with individual degree, minute, second components: ```{r dms-split-combine} # Split into degrees and minutes dms_split(c(40.446, -74.256)) # Split into degrees, minutes, and seconds dms_split(c(40.446195, -74.006328), seconds = TRUE) # Combine components back to decimal dms_combine(40, 26, 47) dms_combine( d = c(40, -74, 51), m = c(26, 0, 30), s = c(47, 21.5, 0) ) ``` ### Round-Trip Conversion DMS encoding and decoding are inverses (within precision limits): ```{r dms-roundtrip} # Original coordinates original <- c(40.446195, -74.006328, 51.507351) # Encode to DMS encoded <- dms_encode(original, prec = 6, indicator = "latitude") encoded # Decode back decoded <- dms_decode(encoded) data.frame( original = original, encoded = encoded, decoded = decoded$angle, diff = abs(original - decoded$angle) ) ``` ### Integration with GeoCoords DMS functions complement GeoCoords for complete coordinate handling: ```{r dms-geocoords} # Parse mixed-format input with GeoCoords input <- "40d26'47\"N 74d0'21.5\"W" coords <- geocoords_parse(input) # Format output in different styles data.frame( format = c("decimal", "DMS", "DMS-colon", "MGRS"), value = c( sprintf("%.6f, %.6f", coords$lat, coords$lon), paste( dms_encode(coords$lat, prec = 5, indicator = "latitude"), dms_encode(coords$lon, prec = 5, indicator = "longitude") ), paste( dms_encode(coords$lat, prec = 5, sep = ":"), dms_encode(coords$lon, prec = 5, sep = ":") ), mgrs_fwd(c(coords$lon, coords$lat), precision = 4) ) ) ``` ## See Also - `vignette("projections")` for map projections (UTM/UPS, LCC, etc.) - `vignette("geodesics")` for distance and bearing calculations - [MGRS on Wikipedia](https://en.wikipedia.org/wiki/Military_Grid_Reference_System) - [Geohash on Wikipedia](https://en.wikipedia.org/wiki/Geohash)