h3 3.6.2 → 3.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (161) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +23 -0
  3. data/Gemfile.lock +6 -6
  4. data/README.md +1 -1
  5. data/ext/h3/src/.github/workflows/test-linux.yml +118 -0
  6. data/ext/h3/src/.github/workflows/test-macos.yml +42 -0
  7. data/ext/h3/src/.github/workflows/test-website.yml +32 -0
  8. data/ext/h3/src/.github/workflows/test-windows.yml +44 -0
  9. data/ext/h3/src/.gitignore +5 -0
  10. data/ext/h3/src/.travis.yml +16 -46
  11. data/ext/h3/src/CHANGELOG.md +43 -0
  12. data/ext/h3/src/CMakeLists.txt +133 -33
  13. data/ext/h3/src/CONTRIBUTING.md +1 -1
  14. data/ext/h3/src/README.md +60 -10
  15. data/ext/h3/src/RELEASE.md +3 -1
  16. data/ext/h3/src/VERSION +1 -1
  17. data/ext/h3/src/dev-docs/RFCs/rfc-template.md +21 -0
  18. data/ext/h3/src/dev-docs/RFCs/v4.0.0/error-handling-rfc.md +21 -0
  19. data/ext/h3/src/dev-docs/RFCs/v4.0.0/names_for_concepts_types_functions.md +276 -0
  20. data/ext/h3/src/dev-docs/RFCs/v4.0.0/overrideable-allocators-rfc.md +141 -0
  21. data/ext/h3/src/dev-docs/RFCs/v4.0.0/polyfill-modes-rfc.md +21 -0
  22. data/ext/h3/src/dev-docs/RFCs/v4.0.0/vertex-mode-rfc.md +50 -0
  23. data/ext/h3/src/dev-docs/build_windows.md +6 -1
  24. data/ext/h3/src/dev-docs/creating_bindings.md +3 -3
  25. data/ext/h3/src/dev-docs/custom_alloc.md +27 -0
  26. data/ext/h3/src/docs/{overview/mainpage.md → README.md} +2 -3
  27. data/ext/h3/src/docs/api/misc.md +76 -0
  28. data/ext/h3/src/docs/community/applications.md +1 -0
  29. data/ext/h3/src/docs/community/bindings.md +7 -1
  30. data/ext/h3/src/docs/community/tutorials.md +8 -3
  31. data/ext/h3/src/docs/core-library/coordsystems.md +5 -4
  32. data/ext/h3/src/docs/core-library/filters.md +8 -9
  33. data/ext/h3/src/docs/core-library/geoToH3desc.md +2 -3
  34. data/ext/h3/src/docs/core-library/h3ToGeoBoundaryDesc.md +4 -5
  35. data/ext/h3/src/docs/core-library/h3ToGeoDesc.md +3 -4
  36. data/ext/h3/src/docs/core-library/h3indexing.md +26 -17
  37. data/ext/h3/src/docs/core-library/overview.md +2 -3
  38. data/ext/h3/src/docs/core-library/restable.md +1 -2
  39. data/ext/h3/src/docs/core-library/usage.md +1 -2
  40. data/ext/h3/src/docs/table-of-contents.json +47 -0
  41. data/ext/h3/src/docs/{overview/usecases.md → usecases.md} +6 -11
  42. data/ext/h3/src/scripts/binding_functions.sh +1 -1
  43. data/ext/h3/src/scripts/coverage.sh.in +1 -1
  44. data/ext/h3/src/scripts/update_version.sh +2 -2
  45. data/ext/h3/src/src/apps/applib/include/args.h +1 -0
  46. data/ext/h3/src/src/apps/applib/include/test.h +1 -0
  47. data/ext/h3/src/src/apps/applib/include/utility.h +7 -1
  48. data/ext/h3/src/src/apps/applib/lib/args.c +2 -0
  49. data/ext/h3/src/src/apps/applib/lib/kml.c +2 -0
  50. data/ext/h3/src/src/apps/applib/lib/test.c +1 -0
  51. data/ext/h3/src/src/apps/applib/lib/utility.c +133 -2
  52. data/ext/h3/src/src/apps/benchmarks/benchmarkH3Api.c +1 -1
  53. data/ext/h3/src/{website/html.config.js → src/apps/benchmarks/benchmarkH3UniEdge.c} +15 -12
  54. data/ext/h3/src/src/apps/filters/h3ToComponents.c +1 -0
  55. data/ext/h3/src/src/apps/filters/h3ToGeo.c +1 -0
  56. data/ext/h3/src/src/apps/filters/h3ToGeoBoundary.c +1 -0
  57. data/ext/h3/src/src/apps/filters/h3ToLocalIj.c +1 -0
  58. data/ext/h3/src/src/apps/filters/hexRange.c +1 -0
  59. data/ext/h3/src/src/apps/filters/kRing.c +1 -0
  60. data/ext/h3/src/src/apps/filters/localIjToH3.c +1 -0
  61. data/ext/h3/src/src/apps/miscapps/generateFaceCenterPoint.c +1 -0
  62. data/ext/h3/src/src/apps/miscapps/generateNumHexagons.c +1 -0
  63. data/ext/h3/src/src/apps/miscapps/generatePentagonDirectionFaces.c +67 -0
  64. data/ext/h3/src/src/apps/miscapps/h3ToGeoBoundaryHier.c +1 -0
  65. data/ext/h3/src/src/apps/miscapps/h3ToGeoHier.c +1 -0
  66. data/ext/h3/src/src/apps/miscapps/h3ToHier.c +1 -0
  67. data/ext/h3/src/src/apps/testapps/mkRandGeo.c +1 -0
  68. data/ext/h3/src/src/apps/testapps/mkRandGeoBoundary.c +1 -0
  69. data/ext/h3/src/src/apps/testapps/testBBox.c +1 -0
  70. data/ext/h3/src/src/apps/testapps/testBaseCells.c +15 -1
  71. data/ext/h3/src/src/apps/testapps/testCompact.c +75 -0
  72. data/ext/h3/src/src/apps/testapps/testCoordIj.c +1 -0
  73. data/ext/h3/src/src/apps/testapps/testGeoCoord.c +40 -13
  74. data/ext/h3/src/src/apps/testapps/testGeoToH3.c +1 -0
  75. data/ext/h3/src/src/apps/testapps/testH3Api.c +1 -0
  76. data/ext/h3/src/src/apps/testapps/testH3CellArea.c +47 -0
  77. data/ext/h3/src/src/apps/testapps/testH3CellAreaExhaustive.c +180 -0
  78. data/ext/h3/src/src/apps/testapps/testH3Distance.c +1 -0
  79. data/ext/h3/src/src/apps/testapps/testH3DistanceExhaustive.c +1 -0
  80. data/ext/h3/src/src/apps/testapps/testH3GetFaces.c +1 -0
  81. data/ext/h3/src/src/apps/testapps/testH3Index.c +33 -3
  82. data/ext/h3/src/src/apps/testapps/testH3Line.c +1 -0
  83. data/ext/h3/src/src/apps/testapps/testH3LineExhaustive.c +1 -0
  84. data/ext/h3/src/src/apps/testapps/testH3Memory.c +175 -0
  85. data/ext/h3/src/src/apps/testapps/testH3NeighborRotations.c +1 -0
  86. data/ext/h3/src/src/apps/testapps/testH3SetToLinkedGeo.c +1 -0
  87. data/ext/h3/src/src/apps/testapps/testH3SetToVertexGraph.c +1 -0
  88. data/ext/h3/src/src/apps/testapps/testH3ToCenterChild.c +1 -0
  89. data/ext/h3/src/src/apps/testapps/testH3ToChildren.c +1 -0
  90. data/ext/h3/src/src/apps/testapps/testH3ToGeo.c +1 -0
  91. data/ext/h3/src/src/apps/testapps/testH3ToGeoBoundary.c +1 -0
  92. data/ext/h3/src/src/apps/testapps/testH3ToLocalIj.c +9 -5
  93. data/ext/h3/src/src/apps/testapps/testH3ToLocalIjExhaustive.c +1 -0
  94. data/ext/h3/src/src/apps/testapps/testH3ToParent.c +1 -0
  95. data/ext/h3/src/src/apps/testapps/testH3UniEdge.c +45 -16
  96. data/ext/h3/src/src/apps/testapps/testH3UniEdgeExhaustive.c +111 -0
  97. data/ext/h3/src/src/apps/testapps/testHexRanges.c +1 -0
  98. data/ext/h3/src/src/apps/testapps/testHexRing.c +1 -0
  99. data/ext/h3/src/src/apps/testapps/testKRing.c +1 -0
  100. data/ext/h3/src/src/apps/testapps/testLinkedGeo.c +1 -0
  101. data/ext/h3/src/src/apps/testapps/testMaxH3ToChildrenSize.c +1 -0
  102. data/ext/h3/src/src/apps/testapps/testPentagonIndexes.c +1 -0
  103. data/ext/h3/src/src/apps/testapps/testPolyfill.c +72 -9
  104. data/ext/h3/src/src/apps/testapps/testPolyfillReported.c +157 -0
  105. data/ext/h3/src/src/apps/testapps/testPolygon.c +1 -0
  106. data/ext/h3/src/src/apps/testapps/testVec2d.c +1 -0
  107. data/ext/h3/src/src/apps/testapps/testVec3d.c +1 -0
  108. data/ext/h3/src/src/apps/testapps/testVertex.c +66 -0
  109. data/ext/h3/src/src/apps/testapps/testVertexGraph.c +1 -0
  110. data/ext/h3/src/src/h3lib/include/algos.h +8 -0
  111. data/ext/h3/src/src/h3lib/include/alloc.h +40 -0
  112. data/ext/h3/src/src/h3lib/include/baseCells.h +4 -0
  113. data/ext/h3/src/src/h3lib/include/bbox.h +4 -1
  114. data/ext/h3/src/src/h3lib/include/faceijk.h +3 -2
  115. data/ext/h3/src/src/h3lib/include/geoCoord.h +2 -3
  116. data/ext/h3/src/src/h3lib/include/h3Index.h +37 -4
  117. data/ext/h3/src/src/h3lib/include/h3api.h.in +65 -17
  118. data/ext/h3/src/src/h3lib/include/linkedGeo.h +1 -0
  119. data/ext/h3/src/src/h3lib/include/polygon.h +1 -0
  120. data/ext/h3/src/src/h3lib/include/polygonAlgos.h +1 -0
  121. data/ext/h3/src/src/h3lib/include/vertex.h +44 -0
  122. data/ext/h3/src/src/h3lib/include/vertexGraph.h +1 -0
  123. data/ext/h3/src/src/h3lib/lib/algos.c +300 -75
  124. data/ext/h3/src/src/h3lib/lib/baseCells.c +26 -4
  125. data/ext/h3/src/src/h3lib/lib/bbox.c +56 -31
  126. data/ext/h3/src/src/h3lib/lib/coordijk.c +2 -0
  127. data/ext/h3/src/src/h3lib/lib/faceijk.c +32 -21
  128. data/ext/h3/src/src/h3lib/lib/geoCoord.c +162 -44
  129. data/ext/h3/src/src/h3lib/lib/h3Index.c +81 -43
  130. data/ext/h3/src/src/h3lib/lib/h3UniEdge.c +42 -57
  131. data/ext/h3/src/src/h3lib/lib/linkedGeo.c +20 -15
  132. data/ext/h3/src/src/h3lib/lib/localij.c +1 -1
  133. data/ext/h3/src/src/h3lib/lib/polygon.c +2 -0
  134. data/ext/h3/src/src/h3lib/lib/vec2d.c +1 -0
  135. data/ext/h3/src/src/h3lib/lib/vec3d.c +1 -0
  136. data/ext/h3/src/src/h3lib/lib/vertex.c +134 -0
  137. data/ext/h3/src/src/h3lib/lib/vertexGraph.c +8 -5
  138. data/ext/h3/src/website/.eslintignore +2 -0
  139. data/ext/h3/src/website/.gitignore +57 -0
  140. data/ext/h3/src/website/.nvmrc +1 -0
  141. data/ext/h3/src/website/README.md +8 -6
  142. data/ext/h3/src/website/gatsby-config.js +83 -0
  143. data/ext/h3/src/website/package.json +20 -12
  144. data/ext/h3/src/website/scripts/build-to-gh-pages.sh +7 -5
  145. data/ext/h3/src/website/src/.gitkeep +0 -0
  146. data/ext/h3/src/website/templates/documentation.jsx +129 -0
  147. data/ext/h3/src/website/yarn.lock +13723 -0
  148. data/lib/h3/bindings/private.rb +3 -0
  149. data/lib/h3/miscellaneous.rb +123 -0
  150. data/lib/h3/version.rb +1 -1
  151. data/spec/miscellaneous_spec.rb +117 -0
  152. data/spec/regions_spec.rb +1 -1
  153. metadata +35 -14
  154. data/ext/h3/src/.ycm_extra_conf.py +0 -92
  155. data/ext/h3/src/appveyor.yml +0 -50
  156. data/ext/h3/src/src/apps/testapps/testPolyfill_GH136.c +0 -58
  157. data/ext/h3/src/website/src/config.js +0 -46
  158. data/ext/h3/src/website/src/mdRoutes.js +0 -151
  159. data/ext/h3/src/website/src/styles/_variables.scss +0 -16
  160. data/ext/h3/src/website/src/styles/index.scss +0 -3
  161. data/ext/h3/src/website/static/index.html +0 -15
@@ -18,11 +18,14 @@
18
18
  * (see h3api.h for the main library entry functions)
19
19
  */
20
20
  #include "h3Index.h"
21
+
21
22
  #include <faceijk.h>
22
23
  #include <inttypes.h>
23
24
  #include <math.h>
24
25
  #include <stdlib.h>
25
26
  #include <string.h>
27
+
28
+ #include "alloc.h"
26
29
  #include "baseCells.h"
27
30
  #include "faceijk.h"
28
31
  #include "mathExtensions.h"
@@ -35,20 +38,25 @@
35
38
  int H3_EXPORT(h3GetResolution)(H3Index h) { return H3_GET_RESOLUTION(h); }
36
39
 
37
40
  /**
38
- * Returns the H3 base cell number of an H3 index.
39
- * @param h The H3 index.
40
- * @return The base cell of the H3 index argument.
41
+ * Returns the H3 base cell "number" of an H3 cell (hexagon or pentagon).
42
+ *
43
+ * Note: Technically works on H3 edges, but will return base cell of the
44
+ * origin cell.
45
+ *
46
+ * @param h The H3 cell.
47
+ * @return The base cell "number" of the H3 cell argument.
41
48
  */
42
49
  int H3_EXPORT(h3GetBaseCell)(H3Index h) { return H3_GET_BASE_CELL(h); }
43
50
 
44
51
  /**
45
52
  * Converts a string representation of an H3 index into an H3 index.
46
53
  * @param str The string representation of an H3 index.
47
- * @return The H3 index corresponding to the string argument, or 0 if invalid.
54
+ * @return The H3 index corresponding to the string argument, or H3_NULL if
55
+ * invalid.
48
56
  */
49
57
  H3Index H3_EXPORT(stringToH3)(const char* str) {
50
- H3Index h = H3_INVALID_INDEX;
51
- // If failed, h will be unmodified and we should return 0 anyways.
58
+ H3Index h = H3_NULL;
59
+ // If failed, h will be unmodified and we should return H3_NULL anyways.
52
60
  sscanf(str, "%" PRIx64, &h);
53
61
  return h;
54
62
  }
@@ -70,13 +78,17 @@ void H3_EXPORT(h3ToString)(H3Index h, char* str, size_t sz) {
70
78
  }
71
79
 
72
80
  /**
73
- * Returns whether or not an H3 index is valid.
81
+ * Returns whether or not an H3 index is a valid cell (hexagon or pentagon).
74
82
  * @param h The H3 index to validate.
75
83
  * @return 1 if the H3 index if valid, and 0 if it is not.
76
84
  */
77
85
  int H3_EXPORT(h3IsValid)(H3Index h) {
86
+ if (H3_GET_HIGH_BIT(h) != 0) return 0;
87
+
78
88
  if (H3_GET_MODE(h) != H3_HEXAGON_MODE) return 0;
79
89
 
90
+ if (H3_GET_RESERVED_BITS(h) != 0) return 0;
91
+
80
92
  int baseCell = H3_GET_BASE_CELL(h);
81
93
  if (baseCell < 0 || baseCell >= NUM_BASE_CELLS) return 0;
82
94
 
@@ -127,16 +139,16 @@ void setH3Index(H3Index* hp, int res, int baseCell, Direction initDigit) {
127
139
  * @param h H3Index to find parent of
128
140
  * @param parentRes The resolution to switch to (parent, grandparent, etc)
129
141
  *
130
- * @return H3Index of the parent, or 0 if you actually asked for a child
142
+ * @return H3Index of the parent, or H3_NULL if you actually asked for a child
131
143
  */
132
144
  H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes) {
133
145
  int childRes = H3_GET_RESOLUTION(h);
134
146
  if (parentRes > childRes) {
135
- return H3_INVALID_INDEX;
147
+ return H3_NULL;
136
148
  } else if (parentRes == childRes) {
137
149
  return h;
138
150
  } else if (parentRes < 0 || parentRes > MAX_H3_RES) {
139
- return H3_INVALID_INDEX;
151
+ return H3_NULL;
140
152
  }
141
153
  H3Index parentH = H3_SET_RESOLUTION(h, parentRes);
142
154
  for (int i = parentRes + 1; i <= childRes; i++) {
@@ -220,7 +232,7 @@ void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
220
232
  if (isAPentagon && i == K_AXES_DIGIT) {
221
233
  H3Index* nextChild = children + bufferChildStep;
222
234
  while (children < nextChild) {
223
- *children = H3_INVALID_INDEX;
235
+ *children = H3_NULL;
224
236
  children++;
225
237
  }
226
238
  } else {
@@ -237,12 +249,13 @@ void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
237
249
  * @param h H3Index to find center child of
238
250
  * @param childRes The resolution to switch to
239
251
  *
240
- * @return H3Index of the center child, or 0 if you actually asked for a parent
252
+ * @return H3Index of the center child, or H3_NULL if you actually asked for a
253
+ * parent
241
254
  */
242
255
  H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
243
256
  int parentRes = H3_GET_RESOLUTION(h);
244
257
  if (!_isValidChildRes(parentRes, childRes)) {
245
- return H3_INVALID_INDEX;
258
+ return H3_NULL;
246
259
  } else if (childRes == parentRes) {
247
260
  return h;
248
261
  }
@@ -267,7 +280,7 @@ H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
267
280
  int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
268
281
  const int numHexes) {
269
282
  if (numHexes == 0) {
270
- return 0;
283
+ return COMPACT_SUCCESS;
271
284
  }
272
285
  int res = H3_GET_RESOLUTION(h3Set[0]);
273
286
  if (res == 0) {
@@ -275,11 +288,18 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
275
288
  for (int i = 0; i < numHexes; i++) {
276
289
  compactedSet[i] = h3Set[i];
277
290
  }
278
- return 0;
291
+ return COMPACT_SUCCESS;
292
+ }
293
+ H3Index* remainingHexes = H3_MEMORY(malloc)(numHexes * sizeof(H3Index));
294
+ if (!remainingHexes) {
295
+ return COMPACT_ALLOC_FAILED;
279
296
  }
280
- H3Index* remainingHexes = malloc(numHexes * sizeof(H3Index));
281
297
  memcpy(remainingHexes, h3Set, numHexes * sizeof(H3Index));
282
- H3Index* hashSetArray = calloc(numHexes, sizeof(H3Index));
298
+ H3Index* hashSetArray = H3_MEMORY(calloc)(numHexes, sizeof(H3Index));
299
+ if (!hashSetArray) {
300
+ H3_MEMORY(free)(remainingHexes);
301
+ return COMPACT_ALLOC_FAILED;
302
+ }
283
303
  H3Index* compactedSetOffset = compactedSet;
284
304
  int numRemainingHexes = numHexes;
285
305
  while (numRemainingHexes) {
@@ -301,23 +321,31 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
301
321
  // This case should not be possible because at most one
302
322
  // index is placed into hashSetArray per
303
323
  // numRemainingHexes.
304
- free(remainingHexes);
305
- free(hashSetArray);
306
- return -1;
324
+ H3_MEMORY(free)(remainingHexes);
325
+ H3_MEMORY(free)(hashSetArray);
326
+ return COMPACT_LOOP_EXCEEDED;
307
327
  // LCOV_EXCL_STOP
308
328
  }
309
329
  H3Index tempIndex =
310
330
  hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
311
331
  if (tempIndex == parent) {
312
332
  int count = H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
313
- if (count > 7) {
333
+ int limitCount = 7;
334
+ if (H3_EXPORT(h3IsPentagon)(
335
+ tempIndex & H3_RESERVED_MASK_NEGATIVE)) {
336
+ limitCount--;
337
+ }
338
+ // One is added to count for this check to match one
339
+ // being added to count later in this function when
340
+ // checking for all children being present.
341
+ if (count + 1 > limitCount) {
314
342
  // Only possible on duplicate input
315
- free(remainingHexes);
316
- free(hashSetArray);
317
- return -2;
343
+ H3_MEMORY(free)(remainingHexes);
344
+ H3_MEMORY(free)(hashSetArray);
345
+ return COMPACT_DUPLICATE;
318
346
  }
319
347
  H3_SET_RESERVED_BITS(parent, count);
320
- hashSetArray[loc] = H3_INVALID_INDEX;
348
+ hashSetArray[loc] = H3_NULL;
321
349
  } else {
322
350
  loc = (loc + 1) % numRemainingHexes;
323
351
  }
@@ -337,7 +365,12 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
337
365
  break;
338
366
  }
339
367
  H3Index* compactableHexes =
340
- malloc(maxCompactableCount * sizeof(H3Index));
368
+ H3_MEMORY(calloc)(maxCompactableCount, sizeof(H3Index));
369
+ if (!compactableHexes) {
370
+ H3_MEMORY(free)(remainingHexes);
371
+ H3_MEMORY(free)(hashSetArray);
372
+ return COMPACT_ALLOC_FAILED;
373
+ }
341
374
  for (int i = 0; i < numRemainingHexes; i++) {
342
375
  if (hashSetArray[i] == 0) continue;
343
376
  int count = H3_GET_RESERVED_BITS(hashSetArray[i]) + 1;
@@ -363,7 +396,7 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
363
396
  int uncompactableCount = 0;
364
397
  for (int i = 0; i < numRemainingHexes; i++) {
365
398
  H3Index currIndex = remainingHexes[i];
366
- if (currIndex != H3_INVALID_INDEX) {
399
+ if (currIndex != H3_NULL) {
367
400
  H3Index parent = H3_EXPORT(h3ToParent)(currIndex, parentRes);
368
401
  // Modulus hash the parent into the temp array
369
402
  // to determine if this index was included in
@@ -376,10 +409,10 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
376
409
  // LCOV_EXCL_START
377
410
  // This case should not be possible because at most one
378
411
  // index is placed into hashSetArray per input hexagon.
379
- free(compactableHexes);
380
- free(remainingHexes);
381
- free(hashSetArray);
382
- return -1; // Only possible on duplicate input
412
+ H3_MEMORY(free)(compactableHexes);
413
+ H3_MEMORY(free)(remainingHexes);
414
+ H3_MEMORY(free)(hashSetArray);
415
+ return COMPACT_LOOP_EXCEEDED;
383
416
  // LCOV_EXCL_STOP
384
417
  }
385
418
  H3Index tempIndex =
@@ -407,11 +440,11 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
407
440
  memcpy(remainingHexes, compactableHexes,
408
441
  compactableCount * sizeof(H3Index));
409
442
  numRemainingHexes = compactableCount;
410
- free(compactableHexes);
443
+ H3_MEMORY(free)(compactableHexes);
411
444
  }
412
- free(remainingHexes);
413
- free(hashSetArray);
414
- return 0;
445
+ H3_MEMORY(free)(remainingHexes);
446
+ H3_MEMORY(free)(hashSetArray);
447
+ return COMPACT_SUCCESS;
415
448
  }
416
449
 
417
450
  /**
@@ -603,7 +636,7 @@ H3Index _h3Rotate60cw(H3Index h) {
603
636
  * Convert an FaceIJK address to the corresponding H3Index.
604
637
  * @param fijk The FaceIJK address.
605
638
  * @param res The cell resolution.
606
- * @return The encoded H3Index (or 0 on failure).
639
+ * @return The encoded H3Index (or H3_NULL on failure).
607
640
  */
608
641
  H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
609
642
  // initialize the index
@@ -616,7 +649,7 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
616
649
  if (fijk->coord.i > MAX_FACE_COORD || fijk->coord.j > MAX_FACE_COORD ||
617
650
  fijk->coord.k > MAX_FACE_COORD) {
618
651
  // out of range input
619
- return H3_INVALID_INDEX;
652
+ return H3_NULL;
620
653
  }
621
654
 
622
655
  H3_SET_BASE_CELL(h, _faceIjkToBaseCell(fijk));
@@ -660,7 +693,7 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
660
693
  if (fijkBC.coord.i > MAX_FACE_COORD || fijkBC.coord.j > MAX_FACE_COORD ||
661
694
  fijkBC.coord.k > MAX_FACE_COORD) {
662
695
  // out of range input
663
- return H3_INVALID_INDEX;
696
+ return H3_NULL;
664
697
  }
665
698
 
666
699
  // lookup the correct base cell
@@ -699,14 +732,14 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
699
732
  *
700
733
  * @param g The spherical coordinates to encode.
701
734
  * @param res The desired H3 resolution for the encoding.
702
- * @return The encoded H3Index (or 0 on failure).
735
+ * @return The encoded H3Index (or H3_NULL on failure).
703
736
  */
704
737
  H3Index H3_EXPORT(geoToH3)(const GeoCoord* g, int res) {
705
738
  if (res < 0 || res > MAX_H3_RES) {
706
- return H3_INVALID_INDEX;
739
+ return H3_NULL;
707
740
  }
708
741
  if (!isfinite(g->lat) || !isfinite(g->lon)) {
709
- return H3_INVALID_INDEX;
742
+ return H3_NULL;
710
743
  }
711
744
 
712
745
  FaceIJK fijk;
@@ -816,8 +849,13 @@ void H3_EXPORT(h3ToGeo)(H3Index h3, GeoCoord* g) {
816
849
  void H3_EXPORT(h3ToGeoBoundary)(H3Index h3, GeoBoundary* gb) {
817
850
  FaceIJK fijk;
818
851
  _h3ToFaceIjk(h3, &fijk);
819
- _faceIjkToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3),
820
- H3_EXPORT(h3IsPentagon)(h3), gb);
852
+ if (H3_EXPORT(h3IsPentagon)(h3)) {
853
+ _faceIjkPentToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3), 0,
854
+ NUM_PENT_VERTS, gb);
855
+ } else {
856
+ _faceIjkToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3), 0, NUM_HEX_VERTS,
857
+ gb);
858
+ }
821
859
  }
822
860
 
823
861
  /**
@@ -19,11 +19,13 @@
19
19
 
20
20
  #include <inttypes.h>
21
21
  #include <stdbool.h>
22
+
22
23
  #include "algos.h"
23
24
  #include "constants.h"
24
25
  #include "coordijk.h"
25
26
  #include "geoCoord.h"
26
27
  #include "h3Index.h"
28
+ #include "vertex.h"
27
29
 
28
30
  /**
29
31
  * Returns whether or not the provided H3Indexes are neighbors.
@@ -96,25 +98,30 @@ int H3_EXPORT(h3IndexesAreNeighbors)(H3Index origin, H3Index destination) {
96
98
  * destination
97
99
  * @param origin The origin H3 hexagon index
98
100
  * @param destination The destination H3 hexagon index
99
- * @return The unidirectional edge H3Index, or 0 on failure.
101
+ * @return The unidirectional edge H3Index, or H3_NULL on failure.
100
102
  */
101
103
  H3Index H3_EXPORT(getH3UnidirectionalEdge)(H3Index origin,
102
104
  H3Index destination) {
103
105
  // Short-circuit and return an invalid index value if they are not neighbors
104
106
  if (H3_EXPORT(h3IndexesAreNeighbors)(origin, destination) == 0) {
105
- return H3_INVALID_INDEX;
107
+ return H3_NULL;
106
108
  }
107
109
 
108
110
  // Otherwise, determine the IJK direction from the origin to the destination
109
111
  H3Index output = origin;
110
112
  H3_SET_MODE(output, H3_UNIEDGE_MODE);
111
113
 
114
+ bool isPentagon = H3_EXPORT(h3IsPentagon)(origin);
115
+
112
116
  // Checks each neighbor, in order, to determine which direction the
113
117
  // destination neighbor is located. Skips CENTER_DIGIT since that
114
118
  // would be this index.
115
119
  H3Index neighbor;
116
- for (Direction direction = K_AXES_DIGIT; direction < NUM_DIGITS;
117
- direction++) {
120
+ // Excluding from branch coverage as we never hit the end condition
121
+ // LCOV_EXCL_BR_START
122
+ for (Direction direction = isPentagon ? J_AXES_DIGIT : K_AXES_DIGIT;
123
+ direction < NUM_DIGITS; direction++) {
124
+ // LCOV_EXCL_BR_STOP
118
125
  int rotations = 0;
119
126
  neighbor = h3NeighborRotations(origin, direction, &rotations);
120
127
  if (neighbor == destination) {
@@ -123,18 +130,18 @@ H3Index H3_EXPORT(getH3UnidirectionalEdge)(H3Index origin,
123
130
  }
124
131
  }
125
132
 
126
- // This should be impossible, return an invalid H3Index in this case;
127
- return H3_INVALID_INDEX; // LCOV_EXCL_LINE
133
+ // This should be impossible, return H3_NULL in this case;
134
+ return H3_NULL; // LCOV_EXCL_LINE
128
135
  }
129
136
 
130
137
  /**
131
138
  * Returns the origin hexagon from the unidirectional edge H3Index
132
139
  * @param edge The edge H3 index
133
- * @return The origin H3 hexagon index
140
+ * @return The origin H3 hexagon index, or H3_NULL on failure
134
141
  */
135
142
  H3Index H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(H3Index edge) {
136
143
  if (H3_GET_MODE(edge) != H3_UNIEDGE_MODE) {
137
- return H3_INVALID_INDEX;
144
+ return H3_NULL;
138
145
  }
139
146
  H3Index origin = edge;
140
147
  H3_SET_MODE(origin, H3_HEXAGON_MODE);
@@ -145,11 +152,11 @@ H3Index H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(H3Index edge) {
145
152
  /**
146
153
  * Returns the destination hexagon from the unidirectional edge H3Index
147
154
  * @param edge The edge H3 index
148
- * @return The destination H3 hexagon index
155
+ * @return The destination H3 hexagon index, or H3_NULL on failure
149
156
  */
150
157
  H3Index H3_EXPORT(getDestinationH3IndexFromUnidirectionalEdge)(H3Index edge) {
151
158
  if (H3_GET_MODE(edge) != H3_UNIEDGE_MODE) {
152
- return H3_INVALID_INDEX;
159
+ return H3_NULL;
153
160
  }
154
161
  Direction direction = H3_GET_RESERVED_BITS(edge);
155
162
  int rotations = 0;
@@ -211,7 +218,7 @@ void H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(H3Index origin,
211
218
  // which is zeroed.
212
219
  for (int i = 0; i < 6; i++) {
213
220
  if (isPentagon && i == 0) {
214
- edges[i] = H3_INVALID_INDEX;
221
+ edges[i] = H3_NULL;
215
222
  } else {
216
223
  edges[i] = origin;
217
224
  H3_SET_MODE(edges[i], H3_UNIEDGE_MODE);
@@ -220,59 +227,37 @@ void H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(H3Index origin,
220
227
  }
221
228
  }
222
229
 
223
- /**
224
- * Whether the given coordinate has a matching vertex in the given geo boundary.
225
- * @param vertex Coordinate to check
226
- * @param boundary Geo boundary to look in
227
- * @return Whether a match was found
228
- */
229
- static bool _hasMatchingVertex(const GeoCoord* vertex,
230
- const GeoBoundary* boundary) {
231
- for (int i = 0; i < boundary->numVerts; i++) {
232
- if (geoAlmostEqualThreshold(vertex, &boundary->verts[i], 0.000001)) {
233
- return true;
234
- }
235
- }
236
- return false;
237
- }
238
-
239
230
  /**
240
231
  * Provides the coordinates defining the unidirectional edge.
241
232
  * @param edge The unidirectional edge H3Index
242
233
  * @param gb The geoboundary object to store the edge coordinates.
243
234
  */
244
235
  void H3_EXPORT(getH3UnidirectionalEdgeBoundary)(H3Index edge, GeoBoundary* gb) {
245
- // TODO: More efficient solution :)
246
- GeoBoundary origin = {0};
247
- GeoBoundary destination = {0};
248
- GeoCoord postponedVertex = {0};
249
- bool hasPostponedVertex = false;
250
-
251
- H3_EXPORT(h3ToGeoBoundary)
252
- (H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(edge), &origin);
253
- H3_EXPORT(h3ToGeoBoundary)
254
- (H3_EXPORT(getDestinationH3IndexFromUnidirectionalEdge)(edge),
255
- &destination);
236
+ // Get the origin and neighbor direction from the edge
237
+ Direction direction = H3_GET_RESERVED_BITS(edge);
238
+ H3Index origin = H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(edge);
256
239
 
257
- int k = 0;
258
- for (int i = 0; i < origin.numVerts; i++) {
259
- if (_hasMatchingVertex(&origin.verts[i], &destination)) {
260
- // If we are on vertex 0, we need to handle the case where it's the
261
- // end of the edge, not the beginning.
262
- if (i == 0 &&
263
- !_hasMatchingVertex(&origin.verts[i + 1], &destination)) {
264
- postponedVertex = origin.verts[i];
265
- hasPostponedVertex = true;
266
- } else {
267
- gb->verts[k] = origin.verts[i];
268
- k++;
269
- }
270
- }
240
+ // Get the start vertex for the edge
241
+ int startVertex = vertexNumForDirection(origin, direction);
242
+ if (startVertex == INVALID_VERTEX_NUM) {
243
+ // This is not actually an edge (i.e. no valid direction),
244
+ // so return no vertices.
245
+ gb->numVerts = 0;
246
+ return;
271
247
  }
272
- // If we postponed adding the last vertex, add it now
273
- if (hasPostponedVertex) {
274
- gb->verts[k] = postponedVertex;
275
- k++;
248
+
249
+ // Get the geo boundary for the appropriate vertexes of the origin. Note
250
+ // that while there are always 2 topological vertexes per edge, the
251
+ // resulting edge boundary may have an additional distortion vertex if it
252
+ // crosses an edge of the icosahedron.
253
+ FaceIJK fijk;
254
+ _h3ToFaceIjk(origin, &fijk);
255
+ int res = H3_GET_RESOLUTION(origin);
256
+ int isPentagon = H3_EXPORT(h3IsPentagon)(origin);
257
+
258
+ if (isPentagon) {
259
+ _faceIjkPentToGeoBoundary(&fijk, res, startVertex, 2, gb);
260
+ } else {
261
+ _faceIjkToGeoBoundary(&fijk, res, startVertex, 2, gb);
276
262
  }
277
- gb->numVerts = k;
278
263
  }