coordijk.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556
  1. /*
  2. * Copyright 2016-2018 Uber Technologies, Inc.
  3. *
  4. * Licensed under the Apache License, Version 2.0 (the "License");
  5. * you may not use this file except in compliance with the License.
  6. * You may obtain a copy of the License at
  7. *
  8. * http://www.apache.org/licenses/LICENSE-2.0
  9. *
  10. * Unless required by applicable law or agreed to in writing, software
  11. * distributed under the License is distributed on an "AS IS" BASIS,
  12. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. * See the License for the specific language governing permissions and
  14. * limitations under the License.
  15. */
  16. /** @file coordijk.c
  17. * @brief Hex IJK coordinate systems functions including conversions to/from
  18. * lat/lon.
  19. */
  20. #include "coordijk.h"
  21. #include <math.h>
  22. #include <stdio.h>
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include "constants.h"
  26. #include "geoCoord.h"
  27. #include "mathExtensions.h"
  28. /**
  29. * Sets an IJK coordinate to the specified component values.
  30. *
  31. * @param ijk The IJK coordinate to set.
  32. * @param i The desired i component value.
  33. * @param j The desired j component value.
  34. * @param k The desired k component value.
  35. */
  36. void _setIJK(CoordIJK* ijk, int i, int j, int k) {
  37. ijk->i = i;
  38. ijk->j = j;
  39. ijk->k = k;
  40. }
  41. /**
  42. * Determine the containing hex in ijk+ coordinates for a 2D cartesian
  43. * coordinate vector (from DGGRID).
  44. *
  45. * @param v The 2D cartesian coordinate vector.
  46. * @param h The ijk+ coordinates of the containing hex.
  47. */
  48. void _hex2dToCoordIJK(const Vec2d* v, CoordIJK* h) {
  49. double a1, a2;
  50. double x1, x2;
  51. int m1, m2;
  52. double r1, r2;
  53. // quantize into the ij system and then normalize
  54. h->k = 0;
  55. a1 = fabsl(v->x);
  56. a2 = fabsl(v->y);
  57. // first do a reverse conversion
  58. x2 = a2 / M_SIN60;
  59. x1 = a1 + x2 / 2.0L;
  60. // check if we have the center of a hex
  61. m1 = x1;
  62. m2 = x2;
  63. // otherwise round correctly
  64. r1 = x1 - m1;
  65. r2 = x2 - m2;
  66. if (r1 < 0.5L) {
  67. if (r1 < 1.0L / 3.0L) {
  68. if (r2 < (1.0L + r1) / 2.0L) {
  69. h->i = m1;
  70. h->j = m2;
  71. } else {
  72. h->i = m1;
  73. h->j = m2 + 1;
  74. }
  75. } else {
  76. if (r2 < (1.0L - r1)) {
  77. h->j = m2;
  78. } else {
  79. h->j = m2 + 1;
  80. }
  81. if ((1.0L - r1) <= r2 && r2 < (2.0 * r1)) {
  82. h->i = m1 + 1;
  83. } else {
  84. h->i = m1;
  85. }
  86. }
  87. } else {
  88. if (r1 < 2.0L / 3.0L) {
  89. if (r2 < (1.0L - r1)) {
  90. h->j = m2;
  91. } else {
  92. h->j = m2 + 1;
  93. }
  94. if ((2.0L * r1 - 1.0L) < r2 && r2 < (1.0L - r1)) {
  95. h->i = m1;
  96. } else {
  97. h->i = m1 + 1;
  98. }
  99. } else {
  100. if (r2 < (r1 / 2.0L)) {
  101. h->i = m1 + 1;
  102. h->j = m2;
  103. } else {
  104. h->i = m1 + 1;
  105. h->j = m2 + 1;
  106. }
  107. }
  108. }
  109. // now fold across the axes if necessary
  110. if (v->x < 0.0L) {
  111. if ((h->j % 2) == 0) // even
  112. {
  113. long long int axisi = h->j / 2;
  114. long long int diff = h->i - axisi;
  115. h->i = h->i - 2.0 * diff;
  116. } else {
  117. long long int axisi = (h->j + 1) / 2;
  118. long long int diff = h->i - axisi;
  119. h->i = h->i - (2.0 * diff + 1);
  120. }
  121. }
  122. if (v->y < 0.0L) {
  123. h->i = h->i - (2 * h->j + 1) / 2;
  124. h->j = -1 * h->j;
  125. }
  126. _ijkNormalize(h);
  127. }
  128. /**
  129. * Find the center point in 2D cartesian coordinates of a hex.
  130. *
  131. * @param h The ijk coordinates of the hex.
  132. * @param v The 2D cartesian coordinates of the hex center point.
  133. */
  134. void _ijkToHex2d(const CoordIJK* h, Vec2d* v) {
  135. int i = h->i - h->k;
  136. int j = h->j - h->k;
  137. v->x = i - 0.5L * j;
  138. v->y = j * M_SQRT3_2;
  139. }
  140. /**
  141. * Returns whether or not two ijk coordinates contain exactly the same
  142. * component values.
  143. *
  144. * @param c1 The first set of ijk coordinates.
  145. * @param c2 The second set of ijk coordinates.
  146. * @return 1 if the two addresses match, 0 if they do not.
  147. */
  148. int _ijkMatches(const CoordIJK* c1, const CoordIJK* c2) {
  149. return (c1->i == c2->i && c1->j == c2->j && c1->k == c2->k);
  150. }
  151. /**
  152. * Add two ijk coordinates.
  153. *
  154. * @param h1 The first set of ijk coordinates.
  155. * @param h2 The second set of ijk coordinates.
  156. * @param sum The sum of the two sets of ijk coordinates.
  157. */
  158. void _ijkAdd(const CoordIJK* h1, const CoordIJK* h2, CoordIJK* sum) {
  159. sum->i = h1->i + h2->i;
  160. sum->j = h1->j + h2->j;
  161. sum->k = h1->k + h2->k;
  162. }
  163. /**
  164. * Subtract two ijk coordinates.
  165. *
  166. * @param h1 The first set of ijk coordinates.
  167. * @param h2 The second set of ijk coordinates.
  168. * @param diff The difference of the two sets of ijk coordinates (h1 - h2).
  169. */
  170. void _ijkSub(const CoordIJK* h1, const CoordIJK* h2, CoordIJK* diff) {
  171. diff->i = h1->i - h2->i;
  172. diff->j = h1->j - h2->j;
  173. diff->k = h1->k - h2->k;
  174. }
  175. /**
  176. * Uniformly scale ijk coordinates by a scalar. Works in place.
  177. *
  178. * @param c The ijk coordinates to scale.
  179. * @param factor The scaling factor.
  180. */
  181. void _ijkScale(CoordIJK* c, int factor) {
  182. c->i *= factor;
  183. c->j *= factor;
  184. c->k *= factor;
  185. }
  186. /**
  187. * Normalizes ijk coordinates by setting the components to the smallest possible
  188. * values. Works in place.
  189. *
  190. * @param c The ijk coordinates to normalize.
  191. */
  192. void _ijkNormalize(CoordIJK* c) {
  193. // remove any negative values
  194. if (c->i < 0) {
  195. c->j -= c->i;
  196. c->k -= c->i;
  197. c->i = 0;
  198. }
  199. if (c->j < 0) {
  200. c->i -= c->j;
  201. c->k -= c->j;
  202. c->j = 0;
  203. }
  204. if (c->k < 0) {
  205. c->i -= c->k;
  206. c->j -= c->k;
  207. c->k = 0;
  208. }
  209. // remove the min value if needed
  210. int min = c->i;
  211. if (c->j < min) min = c->j;
  212. if (c->k < min) min = c->k;
  213. if (min > 0) {
  214. c->i -= min;
  215. c->j -= min;
  216. c->k -= min;
  217. }
  218. }
  219. /**
  220. * Determines the H3 digit corresponding to a unit vector in ijk coordinates.
  221. *
  222. * @param ijk The ijk coordinates; must be a unit vector.
  223. * @return The H3 digit (0-6) corresponding to the ijk unit vector, or
  224. * INVALID_DIGIT on failure.
  225. */
  226. Direction _unitIjkToDigit(const CoordIJK* ijk) {
  227. CoordIJK c = *ijk;
  228. _ijkNormalize(&c);
  229. Direction digit = INVALID_DIGIT;
  230. for (Direction i = CENTER_DIGIT; i < NUM_DIGITS; i++) {
  231. if (_ijkMatches(&c, &UNIT_VECS[i])) {
  232. digit = i;
  233. break;
  234. }
  235. }
  236. return digit;
  237. }
  238. /**
  239. * Find the normalized ijk coordinates of the indexing parent of a cell in a
  240. * counter-clockwise aperture 7 grid. Works in place.
  241. *
  242. * @param ijk The ijk coordinates.
  243. */
  244. void _upAp7(CoordIJK* ijk) {
  245. // convert to CoordIJ
  246. int i = ijk->i - ijk->k;
  247. int j = ijk->j - ijk->k;
  248. ijk->i = (int)lroundl((3 * i - j) / 7.0L);
  249. ijk->j = (int)lroundl((i + 2 * j) / 7.0L);
  250. ijk->k = 0;
  251. _ijkNormalize(ijk);
  252. }
  253. /**
  254. * Find the normalized ijk coordinates of the indexing parent of a cell in a
  255. * clockwise aperture 7 grid. Works in place.
  256. *
  257. * @param ijk The ijk coordinates.
  258. */
  259. void _upAp7r(CoordIJK* ijk) {
  260. // convert to CoordIJ
  261. int i = ijk->i - ijk->k;
  262. int j = ijk->j - ijk->k;
  263. ijk->i = (int)lroundl((2 * i + j) / 7.0L);
  264. ijk->j = (int)lroundl((3 * j - i) / 7.0L);
  265. ijk->k = 0;
  266. _ijkNormalize(ijk);
  267. }
  268. /**
  269. * Find the normalized ijk coordinates of the hex centered on the indicated
  270. * hex at the next finer aperture 7 counter-clockwise resolution. Works in
  271. * place.
  272. *
  273. * @param ijk The ijk coordinates.
  274. */
  275. void _downAp7(CoordIJK* ijk) {
  276. // res r unit vectors in res r+1
  277. CoordIJK iVec = {3, 0, 1};
  278. CoordIJK jVec = {1, 3, 0};
  279. CoordIJK kVec = {0, 1, 3};
  280. _ijkScale(&iVec, ijk->i);
  281. _ijkScale(&jVec, ijk->j);
  282. _ijkScale(&kVec, ijk->k);
  283. _ijkAdd(&iVec, &jVec, ijk);
  284. _ijkAdd(ijk, &kVec, ijk);
  285. _ijkNormalize(ijk);
  286. }
  287. /**
  288. * Find the normalized ijk coordinates of the hex centered on the indicated
  289. * hex at the next finer aperture 7 clockwise resolution. Works in place.
  290. *
  291. * @param ijk The ijk coordinates.
  292. */
  293. void _downAp7r(CoordIJK* ijk) {
  294. // res r unit vectors in res r+1
  295. CoordIJK iVec = {3, 1, 0};
  296. CoordIJK jVec = {0, 3, 1};
  297. CoordIJK kVec = {1, 0, 3};
  298. _ijkScale(&iVec, ijk->i);
  299. _ijkScale(&jVec, ijk->j);
  300. _ijkScale(&kVec, ijk->k);
  301. _ijkAdd(&iVec, &jVec, ijk);
  302. _ijkAdd(ijk, &kVec, ijk);
  303. _ijkNormalize(ijk);
  304. }
  305. /**
  306. * Find the normalized ijk coordinates of the hex in the specified digit
  307. * direction from the specified ijk coordinates. Works in place.
  308. *
  309. * @param ijk The ijk coordinates.
  310. * @param digit The digit direction from the original ijk coordinates.
  311. */
  312. void _neighbor(CoordIJK* ijk, Direction digit) {
  313. if (digit > CENTER_DIGIT && digit < NUM_DIGITS) {
  314. _ijkAdd(ijk, &UNIT_VECS[digit], ijk);
  315. _ijkNormalize(ijk);
  316. }
  317. }
  318. /**
  319. * Rotates ijk coordinates 60 degrees counter-clockwise. Works in place.
  320. *
  321. * @param ijk The ijk coordinates.
  322. */
  323. void _ijkRotate60ccw(CoordIJK* ijk) {
  324. // unit vector rotations
  325. CoordIJK iVec = {1, 1, 0};
  326. CoordIJK jVec = {0, 1, 1};
  327. CoordIJK kVec = {1, 0, 1};
  328. _ijkScale(&iVec, ijk->i);
  329. _ijkScale(&jVec, ijk->j);
  330. _ijkScale(&kVec, ijk->k);
  331. _ijkAdd(&iVec, &jVec, ijk);
  332. _ijkAdd(ijk, &kVec, ijk);
  333. _ijkNormalize(ijk);
  334. }
  335. /**
  336. * Rotates ijk coordinates 60 degrees clockwise. Works in place.
  337. *
  338. * @param ijk The ijk coordinates.
  339. */
  340. void _ijkRotate60cw(CoordIJK* ijk) {
  341. // unit vector rotations
  342. CoordIJK iVec = {1, 0, 1};
  343. CoordIJK jVec = {1, 1, 0};
  344. CoordIJK kVec = {0, 1, 1};
  345. _ijkScale(&iVec, ijk->i);
  346. _ijkScale(&jVec, ijk->j);
  347. _ijkScale(&kVec, ijk->k);
  348. _ijkAdd(&iVec, &jVec, ijk);
  349. _ijkAdd(ijk, &kVec, ijk);
  350. _ijkNormalize(ijk);
  351. }
  352. /**
  353. * Rotates indexing digit 60 degrees counter-clockwise. Returns result.
  354. *
  355. * @param digit Indexing digit (between 1 and 6 inclusive)
  356. */
  357. Direction _rotate60ccw(Direction digit) {
  358. switch (digit) {
  359. case K_AXES_DIGIT:
  360. return IK_AXES_DIGIT;
  361. case IK_AXES_DIGIT:
  362. return I_AXES_DIGIT;
  363. case I_AXES_DIGIT:
  364. return IJ_AXES_DIGIT;
  365. case IJ_AXES_DIGIT:
  366. return J_AXES_DIGIT;
  367. case J_AXES_DIGIT:
  368. return JK_AXES_DIGIT;
  369. case JK_AXES_DIGIT:
  370. return K_AXES_DIGIT;
  371. default:
  372. return digit;
  373. }
  374. }
  375. /**
  376. * Rotates indexing digit 60 degrees clockwise. Returns result.
  377. *
  378. * @param digit Indexing digit (between 1 and 6 inclusive)
  379. */
  380. Direction _rotate60cw(Direction digit) {
  381. switch (digit) {
  382. case K_AXES_DIGIT:
  383. return JK_AXES_DIGIT;
  384. case JK_AXES_DIGIT:
  385. return J_AXES_DIGIT;
  386. case J_AXES_DIGIT:
  387. return IJ_AXES_DIGIT;
  388. case IJ_AXES_DIGIT:
  389. return I_AXES_DIGIT;
  390. case I_AXES_DIGIT:
  391. return IK_AXES_DIGIT;
  392. case IK_AXES_DIGIT:
  393. return K_AXES_DIGIT;
  394. default:
  395. return digit;
  396. }
  397. }
  398. /**
  399. * Find the normalized ijk coordinates of the hex centered on the indicated
  400. * hex at the next finer aperture 3 counter-clockwise resolution. Works in
  401. * place.
  402. *
  403. * @param ijk The ijk coordinates.
  404. */
  405. void _downAp3(CoordIJK* ijk) {
  406. // res r unit vectors in res r+1
  407. CoordIJK iVec = {2, 0, 1};
  408. CoordIJK jVec = {1, 2, 0};
  409. CoordIJK kVec = {0, 1, 2};
  410. _ijkScale(&iVec, ijk->i);
  411. _ijkScale(&jVec, ijk->j);
  412. _ijkScale(&kVec, ijk->k);
  413. _ijkAdd(&iVec, &jVec, ijk);
  414. _ijkAdd(ijk, &kVec, ijk);
  415. _ijkNormalize(ijk);
  416. }
  417. /**
  418. * Find the normalized ijk coordinates of the hex centered on the indicated
  419. * hex at the next finer aperture 3 clockwise resolution. Works in place.
  420. *
  421. * @param ijk The ijk coordinates.
  422. */
  423. void _downAp3r(CoordIJK* ijk) {
  424. // res r unit vectors in res r+1
  425. CoordIJK iVec = {2, 1, 0};
  426. CoordIJK jVec = {0, 2, 1};
  427. CoordIJK kVec = {1, 0, 2};
  428. _ijkScale(&iVec, ijk->i);
  429. _ijkScale(&jVec, ijk->j);
  430. _ijkScale(&kVec, ijk->k);
  431. _ijkAdd(&iVec, &jVec, ijk);
  432. _ijkAdd(ijk, &kVec, ijk);
  433. _ijkNormalize(ijk);
  434. }
  435. /**
  436. * Finds the distance between the two coordinates. Returns result.
  437. *
  438. * @param c1 The first set of ijk coordinates.
  439. * @param c2 The second set of ijk coordinates.
  440. */
  441. int ijkDistance(const CoordIJK* c1, const CoordIJK* c2) {
  442. CoordIJK diff;
  443. _ijkSub(c1, c2, &diff);
  444. _ijkNormalize(&diff);
  445. CoordIJK absDiff = {abs(diff.i), abs(diff.j), abs(diff.k)};
  446. return MAX(absDiff.i, MAX(absDiff.j, absDiff.k));
  447. }
  448. /**
  449. * Transforms coordinates from the IJK+ coordinate system to the IJ coordinate
  450. * system.
  451. *
  452. * @param ijk The input IJK+ coordinates
  453. * @param ij The output IJ coordinates
  454. */
  455. void ijkToIj(const CoordIJK* ijk, CoordIJ* ij) {
  456. ij->i = ijk->i - ijk->k;
  457. ij->j = ijk->j - ijk->k;
  458. }
  459. /**
  460. * Transforms coordinates from the IJ coordinate system to the IJK+ coordinate
  461. * system.
  462. *
  463. * @param ij The input IJ coordinates
  464. * @param ijk The output IJK+ coordinates
  465. */
  466. void ijToIjk(const CoordIJ* ij, CoordIJK* ijk) {
  467. ijk->i = ij->i;
  468. ijk->j = ij->j;
  469. ijk->k = 0;
  470. _ijkNormalize(ijk);
  471. }
  472. /**
  473. * Convert IJK coordinates to cube coordinates, in place
  474. * @param ijk Coordinate to convert
  475. */
  476. void ijkToCube(CoordIJK* ijk) {
  477. ijk->i = -ijk->i + ijk->k;
  478. ijk->j = ijk->j - ijk->k;
  479. ijk->k = -ijk->i - ijk->j;
  480. }
  481. /**
  482. * Convert cube coordinates to IJK coordinates, in place
  483. * @param ijk Coordinate to convert
  484. */
  485. void cubeToIjk(CoordIJK* ijk) {
  486. ijk->i = -ijk->i;
  487. ijk->k = 0;
  488. _ijkNormalize(ijk);
  489. }