HERE Lanes Coordinate Encoding
Coordinate values for HERE HERE Lanes are relative to the WGS84 (G1674) GCS, and expressed as decimal degrees with 7 digits of precision after the decimal point. In the Protocol Buffer representation, we apply a couple of techniques to minimize their storage requirements.
Rather than using floating point values, we represent latitude and longitudes as 31 and 32-bit signed integers, respectively. We apportion the -180º to 180º degree longitude span over the available 232 range of discrete values. For latitudes in the -90º to 90º range, we use a reduced 231 integer value, as the range is half.
This results in an each sequential integer value being
360° / 232 = 180° / 231 = 0.00000008381903171539306640625 degrees apart
This corresponds to a resolution of around 1 cm at the meridian/equator. The resulting lat/lon integer values are then encoded as Morton Codes, interleaving their bits into a single 64-bit signed integer:
- First bit is always 0, so all values are positive
- 2nd bit is leftmost bit of longitude (bit 32)
- 3rd bit is leftmost bit of latitude (bit 31)
- Remaining 61 bits alternate between longitude and latitude, ending with bit 1 from longitude as it was one bit longer.
Here is a walk though for a sample location in Sydney, lat/lon -33.86663, 151.20578:
- Convert the lat and lon values to their integer segment units. (Note: You should always "floor" the resulting number.)
Lat: -33.86663 / (180°/231) = -404044634.09925688888888888888889 = -404044635
Lon: 151.20578 / (360°/232) = 1803955222.4060302222222222222222 = 1803955222
- Convert the integer lat/long values to their 31 and 32-bit two-complement binary representations:
Lat: -404044635 = 11100111 11101010 11000100 10100101 -> (strip high-bit)
= 1100111111010101100010010100101
Lon: 1803955222 = 01101011 10000110 00101100 00010110 -> (keep high bit)
= 01101011100001100010110000010110
- Interleave the lon and lat with a leading "0" to produce a 64-bit integer:
0 (leading)
0 1 1 0 1 0 1 1 1 0 0 0 0 1 1 0 0 0 1 0 1 1 0 0 0 0 0 1 0 1 1 0 (lon)
1 1 0 0 1 1 1 1 1 1 0 1 0 1 0 1 1 0 0 0 1 0 0 1 0 1 0 0 1 0 1 (lat)
=> 0011110001101111111010001001110010100100011100001000100100110110
- Convert value back to 64-bit signed integer:
0011110001101111111010001001110010100100011100001000100100110110
= 0x3C6FE89CA4708936= 4354955124161939766