Geodetic::Coordinate::GEOREF¶
World Geographic Reference System¶
GEOREF is a grid-based geocode developed by the US military and adopted by ICAO for air navigation and air defense reporting. It encodes latitude/longitude into a compact alphanumeric string using a false coordinate system that shifts longitude by +180 and latitude by +90 to make all values positive.
The encoding reads longitude first, then latitude at each level:
| Level | Characters | Description | Resolution |
|---|---|---|---|
| Tile | 1-2 | 15-degree grid (24 lng x 12 lat letters) | 15 degrees |
| Degree | 3-4 | 1-degree subdivision within tile (15 letters each) | 1 degree |
| Minutes | 5+ | Numeric digit pairs (lng digits, then lat digits) | Variable |
The character set uses 24 letters (A-Z, omitting I and O) for tiles, and 15 letters (A-Q, omitting I and O) for degree subdivisions. Minute pairs are decimal digits.
Valid code lengths: 2, 4, 8, 10, 12, 14 characters (not 6 -- minimum numeric portion is 2 digits per axis).
GEOREF 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 GEOREF string
coord = Geodetic::Coordinate::GEOREF.new("GJPJ3417")
# From any coordinate (converts via LLA)
coord = Geodetic::Coordinate::GEOREF.new(lla_coord)
coord = Geodetic::Coordinate::GEOREF.new(utm_coord, precision: 10)
| Parameter | Type | Default | Description |
|---|---|---|---|
source |
String or Coord | -- | A GEOREF string or any coordinate object |
precision |
Integer | 8 | Code length: 2, 4, 8, 10, 12, or 14 |
Raises ArgumentError if the source string is empty, has an invalid length (including 6), or contains invalid characters. String input is case-insensitive (normalized to uppercase).
Attributes¶
| Attribute | Type | Access | Description |
|---|---|---|---|
code |
String | read-only | The GEOREF code string |
GEOREF is immutable -- there are no setter methods.
Precision¶
The precision (code length) determines the size of the encoded cell:
| Length | Resolution | Approximate Cell Size |
|---|---|---|
| 2 | 15 degrees | ~1,668 km x 1,668 km |
| 4 | 1 degree | ~111 km x 111 km |
| 8 | 1 minute | ~1.85 km x 1.85 km |
| 10 | 0.1 minute | ~185 m x 185 m |
| 12 | 0.01 minute | ~18.5 m x 18.5 m |
| 14 | 0.001 minute | ~1.85 m x 1.85 m |
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_gars
Class Methods¶
GEOREF.from_lla(lla_coord)
GEOREF.from_ecef(ecef_coord)
GEOREF.from_utm(utm_coord)
GEOREF.from_web_mercator(wm_coord)
GEOREF.from_gh(gh_coord)
GEOREF.from_gars(gars_coord)
# ... and all other coordinate systems
LLA Convenience Methods¶
lla = Geodetic::Coordinate::LLA.new(lat: 40.7128, lng: -74.0060)
georef = lla.to_georef # default precision 8
georef = lla.to_georef(precision: 10) # 0.1-minute precision
lla = Geodetic::Coordinate::LLA.from_georef(georef)
Serialization¶
to_s(truncate_to = nil)¶
Returns the GEOREF string. An optional integer truncates to that precision (re-encodes from decoded coordinates).
coord = GEOREF.new("GJPJ3417")
coord.to_s # => "GJPJ3417"
coord.to_s(4) # => "GJPJ"
coord.to_s(2) # => "GJ"
to_a¶
Returns [lat, lng] of the cell midpoint.
from_string / from_array¶
GEOREF.from_string("GJPJ3417") # from GEOREF string
GEOREF.from_array([38.0, -76.0]) # from [lat, lng]
Neighbors¶
Returns all 8 adjacent cells as GEOREF instances.
coord = GEOREF.new("GJPJ3417")
neighbors = coord.neighbors
# => { N: GEOREF, S: GEOREF, E: GEOREF, W: GEOREF, NE: GEOREF, NW: GEOREF, SE: GEOREF, SW: GEOREF }
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 GEOREF 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 GEOREF instances are equal if their code strings match exactly.
GEOREF.new("GJPJ3417") == GEOREF.new("GJPJ3417") # => true
GEOREF.new("GJPJ3417") == GEOREF.new("GJPJ3418") # => false
valid?¶
Returns true if the code has a valid length (2, 4, 8, 10, 12, or 14), valid tile letters, valid degree letters, and properly formatted minute digits.
Universal Distance and Bearing Methods¶
GEOREF supports all universal distance and bearing methods via the DistanceMethods and BearingMethods mixins:
a = GEOREF.new("GJPJ3417")
b = GEOREF.new("HJAL4243")
a.distance_to(b) # => Distance
a.straight_line_distance_to(b) # => Distance
a.bearing_to(b) # => Bearing
a.elevation_to(b) # => Float (degrees)
Character Sets¶
Tile longitude (24 letters): A B C D E F G H J K L M N P Q R S T U V W X Y Z
Tile latitude (12 letters): A B C D E F G H J K L M
Degree subdivision (15 letters): A B C D E F G H J K L M N P Q
All sets omit I and O to avoid confusion with digits 1 and 0.
Code Structure Examples¶
| Code | Meaning |
|---|---|
GJ |
15-degree tile (tile only) |
GJPJ |
1-degree cell within tile |
GJPJ3417 |
1-minute cell (lng 34', lat 17') |
GJPJ342171 |
0.1-minute cell |
GJPJ34211712 |
0.01-minute cell |