h3Index.c 33 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974
  1. /*
  2. * Copyright 2016-2019 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 h3Index.c
  17. * @brief H3Index utility functions
  18. * (see h3api.h for the main library entry functions)
  19. */
  20. #include "h3Index.h"
  21. #include <faceijk.h>
  22. #include <inttypes.h>
  23. #include <math.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include "alloc.h"
  27. #include "baseCells.h"
  28. #include "faceijk.h"
  29. #include "mathExtensions.h"
  30. /**
  31. * Returns the H3 resolution of an H3 index.
  32. * @param h The H3 index.
  33. * @return The resolution of the H3 index argument.
  34. */
  35. int H3_EXPORT(h3GetResolution)(H3Index h) { return H3_GET_RESOLUTION(h); }
  36. /**
  37. * Returns the H3 base cell "number" of an H3 cell (hexagon or pentagon).
  38. *
  39. * Note: Technically works on H3 edges, but will return base cell of the
  40. * origin cell.
  41. *
  42. * @param h The H3 cell.
  43. * @return The base cell "number" of the H3 cell argument.
  44. */
  45. int H3_EXPORT(h3GetBaseCell)(H3Index h) { return H3_GET_BASE_CELL(h); }
  46. /**
  47. * Converts a string representation of an H3 index into an H3 index.
  48. * @param str The string representation of an H3 index.
  49. * @return The H3 index corresponding to the string argument, or H3_NULL if
  50. * invalid.
  51. */
  52. H3Index H3_EXPORT(stringToH3)(const char* str) {
  53. H3Index h = H3_NULL;
  54. // If failed, h will be unmodified and we should return H3_NULL anyways.
  55. sscanf(str, "%" PRIx64, &h);
  56. return h;
  57. }
  58. /**
  59. * Converts an H3 index into a string representation.
  60. * @param h The H3 index to convert.
  61. * @param str The string representation of the H3 index.
  62. * @param sz Size of the buffer `str`
  63. */
  64. void H3_EXPORT(h3ToString)(H3Index h, char* str, size_t sz) {
  65. // An unsigned 64 bit integer will be expressed in at most
  66. // 16 digits plus 1 for the null terminator.
  67. if (sz < 17) {
  68. // Buffer is potentially not large enough.
  69. return;
  70. }
  71. sprintf(str, "%" PRIx64, h);
  72. }
  73. /**
  74. * Returns whether or not an H3 index is a valid cell (hexagon or pentagon).
  75. * @param h The H3 index to validate.
  76. * @return 1 if the H3 index if valid, and 0 if it is not.
  77. */
  78. int H3_EXPORT(h3IsValid)(H3Index h) {
  79. if (H3_GET_HIGH_BIT(h) != 0) return 0;
  80. if (H3_GET_MODE(h) != H3_HEXAGON_MODE) return 0;
  81. if (H3_GET_RESERVED_BITS(h) != 0) return 0;
  82. int baseCell = H3_GET_BASE_CELL(h);
  83. if (baseCell < 0 || baseCell >= NUM_BASE_CELLS) return 0;
  84. int res = H3_GET_RESOLUTION(h);
  85. if (res < 0 || res > MAX_H3_RES) return 0;
  86. bool foundFirstNonZeroDigit = false;
  87. for (int r = 1; r <= res; r++) {
  88. Direction digit = H3_GET_INDEX_DIGIT(h, r);
  89. if (!foundFirstNonZeroDigit && digit != CENTER_DIGIT) {
  90. foundFirstNonZeroDigit = true;
  91. if (_isBaseCellPentagon(baseCell) && digit == K_AXES_DIGIT) {
  92. return 0;
  93. }
  94. }
  95. if (digit < CENTER_DIGIT || digit >= NUM_DIGITS) return 0;
  96. }
  97. for (int r = res + 1; r <= MAX_H3_RES; r++) {
  98. Direction digit = H3_GET_INDEX_DIGIT(h, r);
  99. if (digit != INVALID_DIGIT) return 0;
  100. }
  101. return 1;
  102. }
  103. /**
  104. * Initializes an H3 index.
  105. * @param hp The H3 index to initialize.
  106. * @param res The H3 resolution to initialize the index to.
  107. * @param baseCell The H3 base cell to initialize the index to.
  108. * @param initDigit The H3 digit (0-7) to initialize all of the index digits to.
  109. */
  110. void setH3Index(H3Index* hp, int res, int baseCell, Direction initDigit) {
  111. H3Index h = H3_INIT;
  112. H3_SET_MODE(h, H3_HEXAGON_MODE);
  113. H3_SET_RESOLUTION(h, res);
  114. H3_SET_BASE_CELL(h, baseCell);
  115. for (int r = 1; r <= res; r++) H3_SET_INDEX_DIGIT(h, r, initDigit);
  116. *hp = h;
  117. }
  118. /**
  119. * h3ToParent produces the parent index for a given H3 index
  120. *
  121. * @param h H3Index to find parent of
  122. * @param parentRes The resolution to switch to (parent, grandparent, etc)
  123. *
  124. * @return H3Index of the parent, or H3_NULL if you actually asked for a child
  125. */
  126. H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes) {
  127. int childRes = H3_GET_RESOLUTION(h);
  128. if (parentRes > childRes) {
  129. return H3_NULL;
  130. } else if (parentRes == childRes) {
  131. return h;
  132. } else if (parentRes < 0 || parentRes > MAX_H3_RES) {
  133. return H3_NULL;
  134. }
  135. H3Index parentH = H3_SET_RESOLUTION(h, parentRes);
  136. for (int i = parentRes + 1; i <= childRes; i++) {
  137. H3_SET_INDEX_DIGIT(parentH, i, H3_DIGIT_MASK);
  138. }
  139. return parentH;
  140. }
  141. /**
  142. * Determines whether one resolution is a valid child resolution of another.
  143. * Each resolution is considered a valid child resolution of itself.
  144. *
  145. * @param parentRes int resolution of the parent
  146. * @param childRes int resolution of the child
  147. *
  148. * @return The validity of the child resolution
  149. */
  150. static bool _isValidChildRes(int parentRes, int childRes) {
  151. if (childRes < parentRes || childRes > MAX_H3_RES) {
  152. return false;
  153. }
  154. return true;
  155. }
  156. /**
  157. * maxH3ToChildrenSize returns the maximum number of children possible for a
  158. * given child level.
  159. *
  160. * @param h H3Index to find the number of children of
  161. * @param childRes The resolution of the child level you're interested in
  162. *
  163. * @return int count of maximum number of children (equal for hexagons, less for
  164. * pentagons
  165. */
  166. int H3_EXPORT(maxH3ToChildrenSize)(H3Index h, int childRes) {
  167. int parentRes = H3_GET_RESOLUTION(h);
  168. if (!_isValidChildRes(parentRes, childRes)) {
  169. return 0;
  170. }
  171. return _ipow(7, (childRes - parentRes));
  172. }
  173. /**
  174. * makeDirectChild takes an index and immediately returns the immediate child
  175. * index based on the specified cell number. Bit operations only, could generate
  176. * invalid indexes if not careful (deleted cell under a pentagon).
  177. *
  178. * @param h H3Index to find the direct child of
  179. * @param cellNumber int id of the direct child (0-6)
  180. *
  181. * @return The new H3Index for the child
  182. */
  183. H3Index makeDirectChild(H3Index h, int cellNumber) {
  184. int childRes = H3_GET_RESOLUTION(h) + 1;
  185. H3Index childH = H3_SET_RESOLUTION(h, childRes);
  186. H3_SET_INDEX_DIGIT(childH, childRes, cellNumber);
  187. return childH;
  188. }
  189. /**
  190. * h3ToChildren takes the given hexagon id and generates all of the children
  191. * at the specified resolution storing them into the provided memory pointer.
  192. * It's assumed that maxH3ToChildrenSize was used to determine the allocation.
  193. *
  194. * @param h H3Index to find the children of
  195. * @param childRes int the child level to produce
  196. * @param children H3Index* the memory to store the resulting addresses in
  197. */
  198. void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
  199. int parentRes = H3_GET_RESOLUTION(h);
  200. if (!_isValidChildRes(parentRes, childRes)) {
  201. return;
  202. } else if (parentRes == childRes) {
  203. *children = h;
  204. return;
  205. }
  206. int bufferSize = H3_EXPORT(maxH3ToChildrenSize)(h, childRes);
  207. int bufferChildStep = (bufferSize / 7);
  208. int isAPentagon = H3_EXPORT(h3IsPentagon)(h);
  209. for (int i = 0; i < 7; i++) {
  210. if (isAPentagon && i == K_AXES_DIGIT) {
  211. H3Index* nextChild = children + bufferChildStep;
  212. while (children < nextChild) {
  213. *children = H3_NULL;
  214. children++;
  215. }
  216. } else {
  217. H3_EXPORT(h3ToChildren)(makeDirectChild(h, i), childRes, children);
  218. children += bufferChildStep;
  219. }
  220. }
  221. }
  222. /**
  223. * h3ToCenterChild produces the center child index for a given H3 index at
  224. * the specified resolution
  225. *
  226. * @param h H3Index to find center child of
  227. * @param childRes The resolution to switch to
  228. *
  229. * @return H3Index of the center child, or H3_NULL if you actually asked for a
  230. * parent
  231. */
  232. H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
  233. int parentRes = H3_GET_RESOLUTION(h);
  234. if (!_isValidChildRes(parentRes, childRes)) {
  235. return H3_NULL;
  236. } else if (childRes == parentRes) {
  237. return h;
  238. }
  239. H3Index child = H3_SET_RESOLUTION(h, childRes);
  240. for (int i = parentRes + 1; i <= childRes; i++) {
  241. H3_SET_INDEX_DIGIT(child, i, 0);
  242. }
  243. return child;
  244. }
  245. /**
  246. * compact takes a set of hexagons all at the same resolution and compresses
  247. * them by pruning full child branches to the parent level. This is also done
  248. * for all parents recursively to get the minimum number of hex addresses that
  249. * perfectly cover the defined space.
  250. * @param h3Set Set of hexagons
  251. * @param compactedSet The output array of compressed hexagons (preallocated)
  252. * @param numHexes The size of the input and output arrays (possible that no
  253. * contiguous regions exist in the set at all and no compression possible)
  254. * @return an error code on bad input data
  255. */
  256. int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
  257. const int numHexes) {
  258. if (numHexes == 0) {
  259. return COMPACT_SUCCESS;
  260. }
  261. int res = H3_GET_RESOLUTION(h3Set[0]);
  262. if (res == 0) {
  263. // No compaction possible, just copy the set to output
  264. for (int i = 0; i < numHexes; i++) {
  265. compactedSet[i] = h3Set[i];
  266. }
  267. return COMPACT_SUCCESS;
  268. }
  269. H3Index* remainingHexes = H3_MEMORY(malloc)(numHexes * sizeof(H3Index));
  270. if (!remainingHexes) {
  271. return COMPACT_ALLOC_FAILED;
  272. }
  273. memcpy(remainingHexes, h3Set, numHexes * sizeof(H3Index));
  274. H3Index* hashSetArray = H3_MEMORY(calloc)(numHexes, sizeof(H3Index));
  275. if (!hashSetArray) {
  276. H3_MEMORY(free)(remainingHexes);
  277. return COMPACT_ALLOC_FAILED;
  278. }
  279. H3Index* compactedSetOffset = compactedSet;
  280. int numRemainingHexes = numHexes;
  281. while (numRemainingHexes) {
  282. res = H3_GET_RESOLUTION(remainingHexes[0]);
  283. int parentRes = res - 1;
  284. // Put the parents of the hexagons into the temp array
  285. // via a hashing mechanism, and use the reserved bits
  286. // to track how many times a parent is duplicated
  287. for (int i = 0; i < numRemainingHexes; i++) {
  288. H3Index currIndex = remainingHexes[i];
  289. if (currIndex != 0) {
  290. H3Index parent = H3_EXPORT(h3ToParent)(currIndex, parentRes);
  291. // Modulus hash the parent into the temp array
  292. int loc = (int)(parent % numRemainingHexes);
  293. int loopCount = 0;
  294. while (hashSetArray[loc] != 0) {
  295. if (loopCount > numRemainingHexes) { // LCOV_EXCL_BR_LINE
  296. // LCOV_EXCL_START
  297. // This case should not be possible because at most one
  298. // index is placed into hashSetArray per
  299. // numRemainingHexes.
  300. H3_MEMORY(free)(remainingHexes);
  301. H3_MEMORY(free)(hashSetArray);
  302. return COMPACT_LOOP_EXCEEDED;
  303. // LCOV_EXCL_STOP
  304. }
  305. H3Index tempIndex =
  306. hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
  307. if (tempIndex == parent) {
  308. int count = H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
  309. int limitCount = 7;
  310. if (H3_EXPORT(h3IsPentagon)(
  311. tempIndex & H3_RESERVED_MASK_NEGATIVE)) {
  312. limitCount--;
  313. }
  314. // One is added to count for this check to match one
  315. // being added to count later in this function when
  316. // checking for all children being present.
  317. if (count + 1 > limitCount) {
  318. // Only possible on duplicate input
  319. H3_MEMORY(free)(remainingHexes);
  320. H3_MEMORY(free)(hashSetArray);
  321. return COMPACT_DUPLICATE;
  322. }
  323. H3_SET_RESERVED_BITS(parent, count);
  324. hashSetArray[loc] = H3_NULL;
  325. } else {
  326. loc = (loc + 1) % numRemainingHexes;
  327. }
  328. loopCount++;
  329. }
  330. hashSetArray[loc] = parent;
  331. }
  332. }
  333. // Determine which parent hexagons have a complete set
  334. // of children and put them in the compactableHexes array
  335. int compactableCount = 0;
  336. int maxCompactableCount =
  337. numRemainingHexes / 6; // Somehow all pentagons; conservative
  338. if (maxCompactableCount == 0) {
  339. memcpy(compactedSetOffset, remainingHexes,
  340. numRemainingHexes * sizeof(remainingHexes[0]));
  341. break;
  342. }
  343. H3Index* compactableHexes =
  344. H3_MEMORY(calloc)(maxCompactableCount, sizeof(H3Index));
  345. if (!compactableHexes) {
  346. H3_MEMORY(free)(remainingHexes);
  347. H3_MEMORY(free)(hashSetArray);
  348. return COMPACT_ALLOC_FAILED;
  349. }
  350. for (int i = 0; i < numRemainingHexes; i++) {
  351. if (hashSetArray[i] == 0) continue;
  352. int count = H3_GET_RESERVED_BITS(hashSetArray[i]) + 1;
  353. // Include the deleted direction for pentagons as implicitly "there"
  354. if (H3_EXPORT(h3IsPentagon)(hashSetArray[i] &
  355. H3_RESERVED_MASK_NEGATIVE)) {
  356. // We need this later on, no need to recalculate
  357. H3_SET_RESERVED_BITS(hashSetArray[i], count);
  358. // Increment count after setting the reserved bits,
  359. // since count is already incremented above, so it
  360. // will be the expected value for a complete hexagon.
  361. count++;
  362. }
  363. if (count == 7) {
  364. // Bingo! Full set!
  365. compactableHexes[compactableCount] =
  366. hashSetArray[i] & H3_RESERVED_MASK_NEGATIVE;
  367. compactableCount++;
  368. }
  369. }
  370. // Uncompactable hexes are immediately copied into the
  371. // output compactedSetOffset
  372. int uncompactableCount = 0;
  373. for (int i = 0; i < numRemainingHexes; i++) {
  374. H3Index currIndex = remainingHexes[i];
  375. if (currIndex != H3_NULL) {
  376. H3Index parent = H3_EXPORT(h3ToParent)(currIndex, parentRes);
  377. // Modulus hash the parent into the temp array
  378. // to determine if this index was included in
  379. // the compactableHexes array
  380. int loc = (int)(parent % numRemainingHexes);
  381. int loopCount = 0;
  382. bool isUncompactable = true;
  383. do {
  384. if (loopCount > numRemainingHexes) { // LCOV_EXCL_BR_LINE
  385. // LCOV_EXCL_START
  386. // This case should not be possible because at most one
  387. // index is placed into hashSetArray per input hexagon.
  388. H3_MEMORY(free)(compactableHexes);
  389. H3_MEMORY(free)(remainingHexes);
  390. H3_MEMORY(free)(hashSetArray);
  391. return COMPACT_LOOP_EXCEEDED;
  392. // LCOV_EXCL_STOP
  393. }
  394. H3Index tempIndex =
  395. hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
  396. if (tempIndex == parent) {
  397. int count = H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
  398. if (count == 7) {
  399. isUncompactable = false;
  400. }
  401. break;
  402. } else {
  403. loc = (loc + 1) % numRemainingHexes;
  404. }
  405. loopCount++;
  406. } while (hashSetArray[loc] != parent);
  407. if (isUncompactable) {
  408. compactedSetOffset[uncompactableCount] = remainingHexes[i];
  409. uncompactableCount++;
  410. }
  411. }
  412. }
  413. // Set up for the next loop
  414. memset(hashSetArray, 0, numHexes * sizeof(H3Index));
  415. compactedSetOffset += uncompactableCount;
  416. memcpy(remainingHexes, compactableHexes,
  417. compactableCount * sizeof(H3Index));
  418. numRemainingHexes = compactableCount;
  419. H3_MEMORY(free)(compactableHexes);
  420. }
  421. H3_MEMORY(free)(remainingHexes);
  422. H3_MEMORY(free)(hashSetArray);
  423. return COMPACT_SUCCESS;
  424. }
  425. /**
  426. * uncompact takes a compressed set of hexagons and expands back to the
  427. * original set of hexagons.
  428. * @param compactedSet Set of hexagons
  429. * @param numHexes The number of hexes in the input set
  430. * @param h3Set Output array of decompressed hexagons (preallocated)
  431. * @param maxHexes The size of the output array to bound check against
  432. * @param res The hexagon resolution to decompress to
  433. * @return An error code if output array is too small or any hexagon is
  434. * smaller than the output resolution.
  435. */
  436. int H3_EXPORT(uncompact)(const H3Index* compactedSet, const int numHexes,
  437. H3Index* h3Set, const int maxHexes, const int res) {
  438. int outOffset = 0;
  439. for (int i = 0; i < numHexes; i++) {
  440. if (compactedSet[i] == 0) continue;
  441. if (outOffset >= maxHexes) {
  442. // We went too far, abort!
  443. return -1;
  444. }
  445. int currentRes = H3_GET_RESOLUTION(compactedSet[i]);
  446. if (!_isValidChildRes(currentRes, res)) {
  447. // Nonsensical. Abort.
  448. return -2;
  449. }
  450. if (currentRes == res) {
  451. // Just copy and move along
  452. h3Set[outOffset] = compactedSet[i];
  453. outOffset++;
  454. } else {
  455. // Bigger hexagon to reduce in size
  456. int numHexesToGen =
  457. H3_EXPORT(maxH3ToChildrenSize)(compactedSet[i], res);
  458. if (outOffset + numHexesToGen > maxHexes) {
  459. // We're about to go too far, abort!
  460. return -1;
  461. }
  462. H3_EXPORT(h3ToChildren)(compactedSet[i], res, h3Set + outOffset);
  463. outOffset += numHexesToGen;
  464. }
  465. }
  466. return 0;
  467. }
  468. /**
  469. * maxUncompactSize takes a compacted set of hexagons are provides an
  470. * upper-bound estimate of the size of the uncompacted set of hexagons.
  471. * @param compactedSet Set of hexagons
  472. * @param numHexes The number of hexes in the input set
  473. * @param res The hexagon resolution to decompress to
  474. * @return The number of hexagons to allocate memory for, or a negative
  475. * number if an error occurs.
  476. */
  477. int H3_EXPORT(maxUncompactSize)(const H3Index* compactedSet, const int numHexes,
  478. const int res) {
  479. int maxNumHexagons = 0;
  480. for (int i = 0; i < numHexes; i++) {
  481. if (compactedSet[i] == 0) continue;
  482. int currentRes = H3_GET_RESOLUTION(compactedSet[i]);
  483. if (!_isValidChildRes(currentRes, res)) {
  484. // Nonsensical. Abort.
  485. return -1;
  486. }
  487. if (currentRes == res) {
  488. maxNumHexagons++;
  489. } else {
  490. // Bigger hexagon to reduce in size
  491. int numHexesToGen =
  492. H3_EXPORT(maxH3ToChildrenSize)(compactedSet[i], res);
  493. maxNumHexagons += numHexesToGen;
  494. }
  495. }
  496. return maxNumHexagons;
  497. }
  498. /**
  499. * h3IsResClassIII takes a hexagon ID and determines if it is in a
  500. * Class III resolution (rotated versus the icosahedron and subject
  501. * to shape distortion adding extra points on icosahedron edges, making
  502. * them not true hexagons).
  503. * @param h The H3Index to check.
  504. * @return Returns 1 if the hexagon is class III, otherwise 0.
  505. */
  506. int H3_EXPORT(h3IsResClassIII)(H3Index h) { return H3_GET_RESOLUTION(h) % 2; }
  507. /**
  508. * h3IsPentagon takes an H3Index and determines if it is actually a
  509. * pentagon.
  510. * @param h The H3Index to check.
  511. * @return Returns 1 if it is a pentagon, otherwise 0.
  512. */
  513. int H3_EXPORT(h3IsPentagon)(H3Index h) {
  514. return _isBaseCellPentagon(H3_GET_BASE_CELL(h)) &&
  515. !_h3LeadingNonZeroDigit(h);
  516. }
  517. /**
  518. * Returns the highest resolution non-zero digit in an H3Index.
  519. * @param h The H3Index.
  520. * @return The highest resolution non-zero digit in the H3Index.
  521. */
  522. Direction _h3LeadingNonZeroDigit(H3Index h) {
  523. for (int r = 1; r <= H3_GET_RESOLUTION(h); r++)
  524. if (H3_GET_INDEX_DIGIT(h, r)) return H3_GET_INDEX_DIGIT(h, r);
  525. // if we're here it's all 0's
  526. return CENTER_DIGIT;
  527. }
  528. /**
  529. * Rotate an H3Index 60 degrees counter-clockwise about a pentagonal center.
  530. * @param h The H3Index.
  531. */
  532. H3Index _h3RotatePent60ccw(H3Index h) {
  533. // rotate in place; skips any leading 1 digits (k-axis)
  534. int foundFirstNonZeroDigit = 0;
  535. for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
  536. // rotate this digit
  537. H3_SET_INDEX_DIGIT(h, r, _rotate60ccw(H3_GET_INDEX_DIGIT(h, r)));
  538. // look for the first non-zero digit so we
  539. // can adjust for deleted k-axes sequence
  540. // if necessary
  541. if (!foundFirstNonZeroDigit && H3_GET_INDEX_DIGIT(h, r) != 0) {
  542. foundFirstNonZeroDigit = 1;
  543. // adjust for deleted k-axes sequence
  544. if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT)
  545. h = _h3Rotate60ccw(h);
  546. }
  547. }
  548. return h;
  549. }
  550. /**
  551. * Rotate an H3Index 60 degrees clockwise about a pentagonal center.
  552. * @param h The H3Index.
  553. */
  554. H3Index _h3RotatePent60cw(H3Index h) {
  555. // rotate in place; skips any leading 1 digits (k-axis)
  556. int foundFirstNonZeroDigit = 0;
  557. for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
  558. // rotate this digit
  559. H3_SET_INDEX_DIGIT(h, r, _rotate60cw(H3_GET_INDEX_DIGIT(h, r)));
  560. // look for the first non-zero digit so we
  561. // can adjust for deleted k-axes sequence
  562. // if necessary
  563. if (!foundFirstNonZeroDigit && H3_GET_INDEX_DIGIT(h, r) != 0) {
  564. foundFirstNonZeroDigit = 1;
  565. // adjust for deleted k-axes sequence
  566. if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT) h = _h3Rotate60cw(h);
  567. }
  568. }
  569. return h;
  570. }
  571. /**
  572. * Rotate an H3Index 60 degrees counter-clockwise.
  573. * @param h The H3Index.
  574. */
  575. H3Index _h3Rotate60ccw(H3Index h) {
  576. for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
  577. Direction oldDigit = H3_GET_INDEX_DIGIT(h, r);
  578. H3_SET_INDEX_DIGIT(h, r, _rotate60ccw(oldDigit));
  579. }
  580. return h;
  581. }
  582. /**
  583. * Rotate an H3Index 60 degrees clockwise.
  584. * @param h The H3Index.
  585. */
  586. H3Index _h3Rotate60cw(H3Index h) {
  587. for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
  588. H3_SET_INDEX_DIGIT(h, r, _rotate60cw(H3_GET_INDEX_DIGIT(h, r)));
  589. }
  590. return h;
  591. }
  592. /**
  593. * Convert an FaceIJK address to the corresponding H3Index.
  594. * @param fijk The FaceIJK address.
  595. * @param res The cell resolution.
  596. * @return The encoded H3Index (or H3_NULL on failure).
  597. */
  598. H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
  599. // initialize the index
  600. H3Index h = H3_INIT;
  601. H3_SET_MODE(h, H3_HEXAGON_MODE);
  602. H3_SET_RESOLUTION(h, res);
  603. // check for res 0/base cell
  604. if (res == 0) {
  605. if (fijk->coord.i > MAX_FACE_COORD || fijk->coord.j > MAX_FACE_COORD ||
  606. fijk->coord.k > MAX_FACE_COORD) {
  607. // out of range input
  608. return H3_NULL;
  609. }
  610. H3_SET_BASE_CELL(h, _faceIjkToBaseCell(fijk));
  611. return h;
  612. }
  613. // we need to find the correct base cell FaceIJK for this H3 index;
  614. // start with the passed in face and resolution res ijk coordinates
  615. // in that face's coordinate system
  616. FaceIJK fijkBC = *fijk;
  617. // build the H3Index from finest res up
  618. // adjust r for the fact that the res 0 base cell offsets the indexing
  619. // digits
  620. CoordIJK* ijk = &fijkBC.coord;
  621. for (int r = res - 1; r >= 0; r--) {
  622. CoordIJK lastIJK = *ijk;
  623. CoordIJK lastCenter;
  624. if (isResClassIII(r + 1)) {
  625. // rotate ccw
  626. _upAp7(ijk);
  627. lastCenter = *ijk;
  628. _downAp7(&lastCenter);
  629. } else {
  630. // rotate cw
  631. _upAp7r(ijk);
  632. lastCenter = *ijk;
  633. _downAp7r(&lastCenter);
  634. }
  635. CoordIJK diff;
  636. _ijkSub(&lastIJK, &lastCenter, &diff);
  637. _ijkNormalize(&diff);
  638. H3_SET_INDEX_DIGIT(h, r + 1, _unitIjkToDigit(&diff));
  639. }
  640. // fijkBC should now hold the IJK of the base cell in the
  641. // coordinate system of the current face
  642. if (fijkBC.coord.i > MAX_FACE_COORD || fijkBC.coord.j > MAX_FACE_COORD ||
  643. fijkBC.coord.k > MAX_FACE_COORD) {
  644. // out of range input
  645. return H3_NULL;
  646. }
  647. // lookup the correct base cell
  648. int baseCell = _faceIjkToBaseCell(&fijkBC);
  649. H3_SET_BASE_CELL(h, baseCell);
  650. // rotate if necessary to get canonical base cell orientation
  651. // for this base cell
  652. int numRots = _faceIjkToBaseCellCCWrot60(&fijkBC);
  653. if (_isBaseCellPentagon(baseCell)) {
  654. // force rotation out of missing k-axes sub-sequence
  655. if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT) {
  656. // check for a cw/ccw offset face; default is ccw
  657. if (_baseCellIsCwOffset(baseCell, fijkBC.face)) {
  658. h = _h3Rotate60cw(h);
  659. } else {
  660. h = _h3Rotate60ccw(h);
  661. }
  662. }
  663. for (int i = 0; i < numRots; i++) h = _h3RotatePent60ccw(h);
  664. } else {
  665. for (int i = 0; i < numRots; i++) {
  666. h = _h3Rotate60ccw(h);
  667. }
  668. }
  669. return h;
  670. }
  671. /**
  672. * Encodes a coordinate on the sphere to the H3 index of the containing cell at
  673. * the specified resolution.
  674. *
  675. * Returns 0 on invalid input.
  676. *
  677. * @param g The spherical coordinates to encode.
  678. * @param res The desired H3 resolution for the encoding.
  679. * @return The encoded H3Index (or H3_NULL on failure).
  680. */
  681. H3Index H3_EXPORT(geoToH3)(const GeoCoord* g, int res) {
  682. if (res < 0 || res > MAX_H3_RES) {
  683. return H3_NULL;
  684. }
  685. if (!isfinite(g->lat) || !isfinite(g->lon)) {
  686. return H3_NULL;
  687. }
  688. FaceIJK fijk;
  689. _geoToFaceIjk(g, res, &fijk);
  690. return _faceIjkToH3(&fijk, res);
  691. }
  692. /**
  693. * Convert an H3Index to the FaceIJK address on a specified icosahedral face.
  694. * @param h The H3Index.
  695. * @param fijk The FaceIJK address, initialized with the desired face
  696. * and normalized base cell coordinates.
  697. * @return Returns 1 if the possibility of overage exists, otherwise 0.
  698. */
  699. int _h3ToFaceIjkWithInitializedFijk(H3Index h, FaceIJK* fijk) {
  700. CoordIJK* ijk = &fijk->coord;
  701. int res = H3_GET_RESOLUTION(h);
  702. // center base cell hierarchy is entirely on this face
  703. int possibleOverage = 1;
  704. if (!_isBaseCellPentagon(H3_GET_BASE_CELL(h)) &&
  705. (res == 0 ||
  706. (fijk->coord.i == 0 && fijk->coord.j == 0 && fijk->coord.k == 0)))
  707. possibleOverage = 0;
  708. for (int r = 1; r <= res; r++) {
  709. if (isResClassIII(r)) {
  710. // Class III == rotate ccw
  711. _downAp7(ijk);
  712. } else {
  713. // Class II == rotate cw
  714. _downAp7r(ijk);
  715. }
  716. _neighbor(ijk, H3_GET_INDEX_DIGIT(h, r));
  717. }
  718. return possibleOverage;
  719. }
  720. /**
  721. * Convert an H3Index to a FaceIJK address.
  722. * @param h The H3Index.
  723. * @param fijk The corresponding FaceIJK address.
  724. */
  725. void _h3ToFaceIjk(H3Index h, FaceIJK* fijk) {
  726. int baseCell = H3_GET_BASE_CELL(h);
  727. // adjust for the pentagonal missing sequence; all of sub-sequence 5 needs
  728. // to be adjusted (and some of sub-sequence 4 below)
  729. if (_isBaseCellPentagon(baseCell) && _h3LeadingNonZeroDigit(h) == 5)
  730. h = _h3Rotate60cw(h);
  731. // start with the "home" face and ijk+ coordinates for the base cell of c
  732. *fijk = baseCellData[baseCell].homeFijk;
  733. if (!_h3ToFaceIjkWithInitializedFijk(h, fijk))
  734. return; // no overage is possible; h lies on this face
  735. // if we're here we have the potential for an "overage"; i.e., it is
  736. // possible that c lies on an adjacent face
  737. CoordIJK origIJK = fijk->coord;
  738. // if we're in Class III, drop into the next finer Class II grid
  739. int res = H3_GET_RESOLUTION(h);
  740. if (isResClassIII(res)) {
  741. // Class III
  742. _downAp7r(&fijk->coord);
  743. res++;
  744. }
  745. // adjust for overage if needed
  746. // a pentagon base cell with a leading 4 digit requires special handling
  747. int pentLeading4 =
  748. (_isBaseCellPentagon(baseCell) && _h3LeadingNonZeroDigit(h) == 4);
  749. if (_adjustOverageClassII(fijk, res, pentLeading4, 0) != NO_OVERAGE) {
  750. // if the base cell is a pentagon we have the potential for secondary
  751. // overages
  752. if (_isBaseCellPentagon(baseCell)) {
  753. while (_adjustOverageClassII(fijk, res, 0, 0) != NO_OVERAGE)
  754. continue;
  755. }
  756. if (res != H3_GET_RESOLUTION(h)) _upAp7r(&fijk->coord);
  757. } else if (res != H3_GET_RESOLUTION(h)) {
  758. fijk->coord = origIJK;
  759. }
  760. }
  761. /**
  762. * Determines the spherical coordinates of the center point of an H3 index.
  763. *
  764. * @param h3 The H3 index.
  765. * @param g The spherical coordinates of the H3 cell center.
  766. */
  767. void H3_EXPORT(h3ToGeo)(H3Index h3, GeoCoord* g) {
  768. FaceIJK fijk;
  769. _h3ToFaceIjk(h3, &fijk);
  770. _faceIjkToGeo(&fijk, H3_GET_RESOLUTION(h3), g);
  771. }
  772. /**
  773. * Determines the cell boundary in spherical coordinates for an H3 index.
  774. *
  775. * @param h3 The H3 index.
  776. * @param gb The boundary of the H3 cell in spherical coordinates.
  777. */
  778. void H3_EXPORT(h3ToGeoBoundary)(H3Index h3, GeoBoundary* gb) {
  779. FaceIJK fijk;
  780. _h3ToFaceIjk(h3, &fijk);
  781. if (H3_EXPORT(h3IsPentagon)(h3)) {
  782. _faceIjkPentToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3), 0,
  783. NUM_PENT_VERTS, gb);
  784. } else {
  785. _faceIjkToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3), 0, NUM_HEX_VERTS,
  786. gb);
  787. }
  788. }
  789. /**
  790. * Returns the max number of possible icosahedron faces an H3 index
  791. * may intersect.
  792. *
  793. * @return int count of faces
  794. */
  795. int H3_EXPORT(maxFaceCount)(H3Index h3) {
  796. // a pentagon always intersects 5 faces, a hexagon never intersects more
  797. // than 2 (but may only intersect 1)
  798. return H3_EXPORT(h3IsPentagon)(h3) ? 5 : 2;
  799. }
  800. /**
  801. * Find all icosahedron faces intersected by a given H3 index, represented
  802. * as integers from 0-19. The array is sparse; since 0 is a valid value,
  803. * invalid array values are represented as -1. It is the responsibility of
  804. * the caller to filter out invalid values.
  805. *
  806. * @param h3 The H3 index
  807. * @param out Output array. Must be of size maxFaceCount(h3).
  808. */
  809. void H3_EXPORT(h3GetFaces)(H3Index h3, int* out) {
  810. int res = H3_GET_RESOLUTION(h3);
  811. int isPentagon = H3_EXPORT(h3IsPentagon)(h3);
  812. // We can't use the vertex-based approach here for class II pentagons,
  813. // because all their vertices are on the icosahedron edges. Their
  814. // direct child pentagons cross the same faces, so use those instead.
  815. if (isPentagon && !isResClassIII(res)) {
  816. // Note that this would not work for res 15, but this is only run on
  817. // Class II pentagons, it should never be invoked for a res 15 index.
  818. H3Index childPentagon = makeDirectChild(h3, 0);
  819. H3_EXPORT(h3GetFaces)(childPentagon, out);
  820. return;
  821. }
  822. // convert to FaceIJK
  823. FaceIJK fijk;
  824. _h3ToFaceIjk(h3, &fijk);
  825. // Get all vertices as FaceIJK addresses. For simplicity, always
  826. // initialize the array with 6 verts, ignoring the last one for pentagons
  827. FaceIJK fijkVerts[NUM_HEX_VERTS];
  828. int vertexCount;
  829. if (isPentagon) {
  830. vertexCount = NUM_PENT_VERTS;
  831. _faceIjkPentToVerts(&fijk, &res, fijkVerts);
  832. } else {
  833. vertexCount = NUM_HEX_VERTS;
  834. _faceIjkToVerts(&fijk, &res, fijkVerts);
  835. }
  836. // We may not use all of the slots in the output array,
  837. // so fill with invalid values to indicate unused slots
  838. int faceCount = H3_EXPORT(maxFaceCount)(h3);
  839. for (int i = 0; i < faceCount; i++) {
  840. out[i] = INVALID_FACE;
  841. }
  842. // add each vertex face, using the output array as a hash set
  843. for (int i = 0; i < vertexCount; i++) {
  844. FaceIJK* vert = &fijkVerts[i];
  845. // Adjust overage, determining whether this vertex is
  846. // on another face
  847. if (isPentagon) {
  848. _adjustPentVertOverage(vert, res);
  849. } else {
  850. _adjustOverageClassII(vert, res, 0, 1);
  851. }
  852. // Save the face to the output array
  853. int face = vert->face;
  854. int pos = 0;
  855. // Find the first empty output position, or the first position
  856. // matching the current face
  857. while (out[pos] != INVALID_FACE && out[pos] != face) pos++;
  858. out[pos] = face;
  859. }
  860. }
  861. /**
  862. * pentagonIndexCount returns the number of pentagons (same at any resolution)
  863. *
  864. * @return int count of pentagon indexes
  865. */
  866. int H3_EXPORT(pentagonIndexCount)() { return NUM_PENTAGONS; }
  867. /**
  868. * Generates all pentagons at the specified resolution
  869. *
  870. * @param res The resolution to produce pentagons at.
  871. * @param out Output array. Must be of size pentagonIndexCount().
  872. */
  873. void H3_EXPORT(getPentagonIndexes)(int res, H3Index* out) {
  874. int i = 0;
  875. for (int bc = 0; bc < NUM_BASE_CELLS; bc++) {
  876. if (_isBaseCellPentagon(bc)) {
  877. H3Index pentagon;
  878. setH3Index(&pentagon, res, bc, 0);
  879. out[i++] = pentagon;
  880. }
  881. }
  882. }
  883. /**
  884. * Returns whether or not a resolution is a Class III grid. Note that odd
  885. * resolutions are Class III and even resolutions are Class II.
  886. * @param res The H3 resolution.
  887. * @return 1 if the resolution is a Class III grid, and 0 if the resolution is
  888. * a Class II grid.
  889. */
  890. int isResClassIII(int res) { return res % 2; }