NDSはWGS84座標系(1984年世界測地系)を使用しています。これは一般的に知られる経度・緯度の座標系です。特定の位置を指定する際には、その地点の経度と緯度を指定することで、正確な位置を一意に特定できます。
NDSはEGM96(1996年地球重力モデル)を使用して高度情報を表現します。EGM96で表される高度情報は標高を良好に近似しており、WGS84の高度情報よりも正確です。
経度は32ビットintで符号化され、[-180, 180]の範囲を表現できます。緯度は31ビットintで符号化され、[-90, 90]の範囲を表現できます。
例:エッフェル塔の計算(Eiffel Tower 2.2945° 48.858222°)
lon = 2.2945 lon_to_int32 = pow(2, 31) * 2.2945 / 180 = 2147483648 * 2.2945 / 180 = 27374451.279644444444444444444444 = 27374451(切り捨てfloorを使用) = 0x1a1b373(16進数) = 0001101000011011001101110011(2進数)
lat = 48.858222 lat_to_int32 = pow(2, 30) * 48.858222 / 90 = 1073741824 * 48.858222 / 90 = 582901293.41863253333333333333333 = 582901293(切り捨てfloorを使用) = 0x22be5e2d(16進数) = 00100010101111100101111000101101(2進数)
モートン符号(morton code)を使用して符号化します x = x31x30...x1x0 y = y30...y1y0 c = x31y30x30...y1x1y0x0 全長63ビット(32+31)
x = 0x1a1b373 1 1 0 1 0 0 0 0 1 1 0 1 1 0 0 1 1 0 1 1 1 0 0 1 1 y = 0x22be5e2d 1 0 0 0 1 0 1 0 1 1 1 1 1 0 0 1 0 1 1 1 1 0 0 0 1 0 1 1 0 1 c = 0x809cea967ad1da7 100000001001110011101010100101100111101011010001110110100111
x = 0x1a1b373 1 1 0 1 0 0 0 0 1 1 0 1 1 0 0 1 1 0 1 1 1 0 0 1 1
y = 0x22be5e2d 1 0 0 0 1 0 1 0 1 1 1 1 1 0 0 1 0 1 1 1 1 0 0 0 1 0 1 1 0 1
c = 0x809cea967ad1da7 100000001001110011101010100101100111101011010001110110100111
63ビットに整列 000100000001001110011101010100101100111101011010001110110100111
したがって、この点のLevel10のタイル番号は Level10 = c.left(2n+1) = c.left(2*10+1) = c.left(21) = 0 0010 0000 0010 0111 0011 = 0x20273 = 131699
したがって、この点のLevel13のタイル番号は Level13 = c.left(2n+1) = c.left(2*13+1) = c.left(27) = 000 1000 0000 1001 1100 1110 1010 = 0x809CEA = 8428778
1 struct CoordinateConverter {
2 double longitude;
3 double latitude;
4 int32_t encodedLon;
5 int32_t encodedLat;
6 uint64_t mortonCode;
7
8 CoordinateConverter(double lon, double lat) : longitude(lon), latitude(lat), encodedLon(0), encodedLat(0), mortonCode(0) {
9 encodedLon = convertLongitude(lon);
10 encodedLat = convertLatitude(lat);
11 mortonCode = calculateMortonCode(encodedLon, encodedLat);
12
13 printf("座標:[%10.6lf,%10.6lf], NDS:[%12d,%12d] モートン:[%24lu]\n", longitude, latitude, encodedLon, encodedLat, mortonCode);
14 }
15
16 int32_t convertLongitude(double lon) {
17 bool isPositive = true;
18 if (lon < 0) {
19 isPositive = false;
20 }
21 auto temp = pow(2, 31) * lon / 180.0;
22 return isPositive ? std::floor(temp) : std::ceil(temp);
23 }
24
25 int32_t convertLatitude(double lat) {
26 bool isPositive = true;
27 if (lat < 0) {
28 isPositive = false;
29 lat += 180.0;
30 }
31 auto temp = pow(2, 30) * lat / 90.0;
32 return isPositive ? std::floor(temp) : std::ceil(temp);
33 }
34
35 uint64_t calculateMortonCode(int32_t lonValue, int32_t latValue) {
36 uint64_t mortonResult = 0;
37 for (int i = 0; i < 32; i++) {
38 uint64_t temp64 = 0;
39 temp64 = (lonValue >> i) & 0x1;
40 temp64 |= ((latValue >> i) & 0x1) << 1;
41 mortonResult |= (temp64 << 2 * i);
42 }
43
44 return mortonResult;
45 }
46 };