Geodetic::Coordinate::HAM¶
Maidenhead Locator System¶
The Maidenhead Locator System (also called QTH Locator or grid square) is a hierarchical geocoding system used worldwide in amateur radio. It encodes latitude/longitude into a compact string of alternating letter and digit pairs.
The system uses a false coordinate origin that shifts longitude by +180 and latitude by +90, making all values positive before encoding. Four levels of subdivision produce strings of 2, 4, 6, or 8 characters:
| Level | Name | Characters | Grid Size | Divisions |
|---|---|---|---|---|
| 1 | Field | 2 letters (A-R) | 20 x 10 | 18 x 18 |
| 2 | Square | 2 digits (0-9) | 2 x 1 | 10 x 10 |
| 3 | Subsquare | 2 letters (a-x) | 5' x 2.5' | 24 x 24 |
| 4 | Extended | 2 digits (0-9) | 30" x 15" | 10 x 10 |
Convention: Field letters are uppercase, subsquare letters are lowercase (e.g., FN31pr).
HAM is a 2D coordinate system (no altitude). Conversions to/from other systems go through LLA as the intermediary. Each locator string represents a rectangular cell; the coordinate's point value is the cell's midpoint.
Constructor¶
# From a Maidenhead locator string
coord = Geodetic::Coordinate::HAM.new("FN31pr")
# From any coordinate (converts via LLA)
coord = Geodetic::Coordinate::HAM.new(lla_coord)
coord = Geodetic::Coordinate::HAM.new(utm_coord, precision: 8)
| Parameter | Type | Default | Description |
|---|---|---|---|
source |
String or Coord | — | A Maidenhead string or any coordinate object |
precision |
Integer | 6 | Locator length: 2, 4, 6, or 8 (must be even) |
Raises ArgumentError if the source string is empty, has odd length, exceeds 8 characters, or contains invalid characters for any level. String input normalizes Field to uppercase, Subsquare to lowercase.
Attributes¶
| Attribute | Type | Access | Description |
|---|---|---|---|
locator |
String | read-only | The Maidenhead locator string |
HAM is immutable — there are no setter methods.
Precision¶
The precision (locator length) determines the size of the grid square:
| Length | Level | Approximate Cell Size |
|---|---|---|
| 2 | Field | 1,113 km x 2,226 km |
| 4 | Square | 111 km x 222 km |
| 6 | Subsquare | 4.6 km x 9.3 km |
| 8 | Extended | 463 m x 926 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_olc
Class Methods¶
HAM.from_lla(lla_coord)
HAM.from_ecef(ecef_coord)
HAM.from_utm(utm_coord)
HAM.from_web_mercator(wm_coord)
HAM.from_gh(gh_coord)
HAM.from_gh36(gh36_coord)
HAM.from_olc(olc_coord)
# ... and all other coordinate systems
LLA Convenience Methods¶
lla = Geodetic::Coordinate::LLA.new(lat: 40.689167, lng: -74.044444)
ham = lla.to_ham # default precision 6
ham = lla.to_ham(precision: 8) # extended precision
lla = Geodetic::Coordinate::LLA.from_ham(ham)
Serialization¶
to_s(truncate_to = nil)¶
Returns the locator string. An optional integer truncates to that length (rounded down to even, minimum 2).
coord = HAM.new("FN31pr45")
coord.to_s # => "FN31pr45"
coord.to_s(6) # => "FN31pr"
coord.to_s(4) # => "FN31"
to_a¶
Returns [lat, lng] of the cell midpoint.
from_string / from_array¶
Neighbors¶
Returns all 8 adjacent grid squares as HAM instances.
coord = HAM.new("FN31pr")
neighbors = coord.neighbors
# => { N: HAM, S: HAM, E: HAM, W: HAM, NE: HAM, NW: HAM, SE: HAM, SW: HAM }
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 locator. Latitude is clamped to valid range near the poles; longitude wraps at the antimeridian.
Area¶
The to_area method returns the grid square 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 HAM instances are equal if their locator strings match exactly.
valid?¶
Returns true if the locator has valid characters at each level and an even length.
Universal Distance and Bearing Methods¶
HAM supports all universal distance and bearing methods via the DistanceMethods and BearingMethods mixins:
a = HAM.new("FN31pr")
b = HAM.new("IO91wm")
a.distance_to(b) # => Distance (~5,570 km)
a.straight_line_distance_to(b) # => Distance
a.bearing_to(b) # => Bearing (~51)
a.elevation_to(b) # => Float (degrees)
Well-Known Locators¶
| Location | Locator |
|---|---|
| New York City | FN30 |
| London | IO91 |
| Tokyo | PM95 |
| Sydney | QF56 |
| Origin (0, 0) | JJ00 |