Geodetic::Coordinate::GARS¶
Global Area Reference System¶
GARS is a standardized geospatial reference system developed by the National Geospatial-Intelligence Agency (NGA). It divides the Earth into hierarchical grid cells at three precision levels, designed for military targeting, air defense, and joint operations.
The encoding uses a false coordinate origin that shifts longitude by +180 and latitude by +90. Cells are identified by a combination of numeric longitude bands, alphabetic latitude bands, and optional subdivision digits:
| Level | Characters | Size | Description |
|---|---|---|---|
| 30-minute cell | 5 (NNNll) | 30' x 30' | 3-digit lon band + 2-letter lat band |
| Quadrant | 6 (NNNllq) | 15' x 15' | + quadrant digit 1-4 |
| Keypad | 7 (NNNllqk) | 5' x 5' | + keypad digit 1-9 |
Quadrant Layout¶
Within each 30-minute cell, quadrants are numbered:
Keypad Layout¶
Within each quadrant, keypads follow telephone-style numbering:
+---+---+---+
| 1 | 2 | 3 | (north)
+---+---+---+
| 4 | 5 | 6 |
+---+---+---+
| 7 | 8 | 9 | (south)
+---+---+---+
GARS is a 2D coordinate system (no altitude). Conversions to/from other systems go through LLA as the intermediary. Each code represents a rectangular cell; the coordinate's point value is the cell's midpoint.
Constructor¶
# From a GARS string
coord = Geodetic::Coordinate::GARS.new("006AG39")
# From any coordinate (converts via LLA)
coord = Geodetic::Coordinate::GARS.new(lla_coord)
coord = Geodetic::Coordinate::GARS.new(utm_coord, precision: 6)
| Parameter | Type | Default | Description |
|---|---|---|---|
source |
String or Coord | -- | A GARS string or any coordinate object |
precision |
Integer | 7 | Code length: 5, 6, or 7 |
Raises ArgumentError if the source string is empty, has an invalid length, contains an out-of-range longitude band (must be 001-720), invalid latitude letters (I and O excluded), invalid quadrant digit (must be 1-4), or invalid keypad digit (must be 1-9). Letter input is case-insensitive (normalized to uppercase).
Attributes¶
| Attribute | Type | Access | Description |
|---|---|---|---|
code |
String | read-only | The GARS code string |
GARS is immutable -- there are no setter methods.
Precision¶
The precision (code length) determines the size of the encoded cell:
| Length | Level | Approximate Cell Size |
|---|---|---|
| 5 | 30-minute cell | ~55.6 km x 55.6 km |
| 6 | 15-minute quadrant | ~27.8 km x 27.8 km |
| 7 | 5-minute keypad | ~9.3 km x 9.3 km |
Conversions¶
All conversions chain through LLA. The datum parameter defaults to Geodetic::WGS84.
Instance Methods¶
coord.to_lla # => LLA (midpoint of the cell)
coord.to_ecef
coord.to_utm
coord.to_enu(reference_lla)
coord.to_ned(reference_lla)
coord.to_mgrs
coord.to_usng
coord.to_web_mercator
coord.to_ups
coord.to_state_plane(zone_code)
coord.to_bng
coord.to_gh36
coord.to_gh
coord.to_ham
coord.to_olc
coord.to_georef
Class Methods¶
GARS.from_lla(lla_coord)
GARS.from_ecef(ecef_coord)
GARS.from_utm(utm_coord)
GARS.from_web_mercator(wm_coord)
GARS.from_gh(gh_coord)
GARS.from_georef(georef_coord)
# ... and all other coordinate systems
LLA Convenience Methods¶
lla = Geodetic::Coordinate::LLA.new(lat: 40.7128, lng: -74.0060)
gars = lla.to_gars # default precision 7
gars = lla.to_gars(precision: 5) # 30-minute cell only
lla = Geodetic::Coordinate::LLA.from_gars(gars)
Serialization¶
to_s(truncate_to = nil)¶
Returns the GARS string. An optional integer truncates to that precision (re-encodes from decoded coordinates).
coord = GARS.new("006AG39")
coord.to_s # => "006AG39"
coord.to_s(6) # => "006AG3"
coord.to_s(5) # => "006AG"
to_a¶
Returns [lat, lng] of the cell midpoint.
from_string / from_array¶
Neighbors¶
Returns all 8 adjacent cells as GARS instances.
coord = GARS.new("361HN35")
neighbors = coord.neighbors
# => { N: GARS, S: GARS, E: GARS, W: GARS, NE: GARS, NW: GARS, SE: GARS, SW: GARS }
neighbors[:N].to_lla.lat > coord.to_lla.lat # => true
neighbors[:E].to_lla.lng > coord.to_lla.lng # => true
Neighbors preserve the same precision as the original code. Latitude is clamped to valid range near the poles; longitude wraps at the antimeridian.
Area¶
The to_area method returns the GARS cell as a Geodetic::Areas::BoundingBox.
area = coord.to_area
# => Geodetic::Areas::BoundingBox
area.includes?(coord.to_lla) # => true (midpoint is inside the cell)
area.nw # => LLA (northwest corner)
area.se # => LLA (southeast corner)
Equality¶
Two GARS instances are equal if their code strings match exactly.
GARS.new("006AG39") == GARS.new("006AG39") # => true
GARS.new("006AG39") == GARS.new("006AG38") # => false
valid?¶
Returns true if the code has a valid length (5, 6, or 7), a longitude band between 001-720, valid latitude letters (A-Z excluding I and O), a valid quadrant digit (1-4), and a valid keypad digit (1-9).
Universal Distance and Bearing Methods¶
GARS supports all universal distance and bearing methods via the DistanceMethods and BearingMethods mixins:
a = GARS.new("361HN35")
b = GARS.new("212LX43")
a.distance_to(b) # => Distance
a.straight_line_distance_to(b) # => Distance
a.bearing_to(b) # => Bearing
a.elevation_to(b) # => Float (degrees)
Encoding Details¶
Longitude Bands¶
720 bands of 0.5 degrees each, numbered 001-720 from west to east: - Band 001: -180.0 to -179.5 - Band 361: 0.0 to 0.5 - Band 720: 179.5 to 180.0
Latitude Bands¶
360 bands of 0.5 degrees each, encoded as 2-letter pairs (AA-QZ) from south to north: - AA: -90.0 to -89.5 - HN: 0.0 to 0.5 - QZ: 89.5 to 90.0
The 24-letter alphabet (A-Z, excluding I and O) gives 24 x 15 = 360 valid combinations.
Well-Known GARS Codes¶
| Location | GARS Code | Description |
|---|---|---|
| Null Island (0, 0) | 361HN | 30-minute cell at equator/prime meridian |
| New York City | 212LX43 | 5-minute cell |
| Western boundary | 001xx | Longitude -180.0 |