h3 3.6.0 → 3.7.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (175) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ruby_ci.yml +30 -0
  3. data/.rubocop.yml +1 -1
  4. data/.ruby-version +1 -0
  5. data/CHANGELOG.md +39 -0
  6. data/Gemfile.lock +6 -24
  7. data/LICENSE.md +1 -1
  8. data/README.md +2 -3
  9. data/ext/h3/src/.github/workflows/test-linux.yml +118 -0
  10. data/ext/h3/src/.github/workflows/test-macos.yml +42 -0
  11. data/ext/h3/src/.github/workflows/test-website.yml +32 -0
  12. data/ext/h3/src/.github/workflows/test-windows.yml +44 -0
  13. data/ext/h3/src/.gitignore +5 -0
  14. data/ext/h3/src/.travis.yml +20 -42
  15. data/ext/h3/src/CHANGELOG.md +57 -0
  16. data/ext/h3/src/CMakeLists.txt +135 -33
  17. data/ext/h3/src/CONTRIBUTING.md +1 -1
  18. data/ext/h3/src/README.md +61 -11
  19. data/ext/h3/src/RELEASE.md +3 -1
  20. data/ext/h3/src/VERSION +1 -1
  21. data/ext/h3/src/dev-docs/RFCs/rfc-template.md +21 -0
  22. data/ext/h3/src/dev-docs/RFCs/v4.0.0/error-handling-rfc.md +21 -0
  23. data/ext/h3/src/dev-docs/RFCs/v4.0.0/names_for_concepts_types_functions.md +276 -0
  24. data/ext/h3/src/dev-docs/RFCs/v4.0.0/overrideable-allocators-rfc.md +141 -0
  25. data/ext/h3/src/dev-docs/RFCs/v4.0.0/polyfill-modes-rfc.md +21 -0
  26. data/ext/h3/src/dev-docs/RFCs/v4.0.0/vertex-mode-rfc.md +50 -0
  27. data/ext/h3/src/dev-docs/build_windows.md +6 -1
  28. data/ext/h3/src/dev-docs/creating_bindings.md +3 -3
  29. data/ext/h3/src/dev-docs/custom_alloc.md +27 -0
  30. data/ext/h3/src/docs/{overview/mainpage.md → README.md} +2 -3
  31. data/ext/h3/src/docs/api/misc.md +76 -0
  32. data/ext/h3/src/docs/community/applications.md +1 -0
  33. data/ext/h3/src/docs/community/bindings.md +10 -0
  34. data/ext/h3/src/docs/community/tutorials.md +8 -3
  35. data/ext/h3/src/docs/core-library/coordsystems.md +5 -4
  36. data/ext/h3/src/docs/core-library/filters.md +8 -9
  37. data/ext/h3/src/docs/core-library/geoToH3desc.md +2 -3
  38. data/ext/h3/src/docs/core-library/h3ToGeoBoundaryDesc.md +4 -5
  39. data/ext/h3/src/docs/core-library/h3ToGeoDesc.md +3 -4
  40. data/ext/h3/src/docs/core-library/h3indexing.md +26 -17
  41. data/ext/h3/src/docs/core-library/overview.md +2 -3
  42. data/ext/h3/src/docs/core-library/restable.md +1 -2
  43. data/ext/h3/src/docs/core-library/usage.md +1 -2
  44. data/ext/h3/src/docs/table-of-contents.json +47 -0
  45. data/ext/h3/src/docs/{overview/usecases.md → usecases.md} +6 -11
  46. data/ext/h3/src/scripts/binding_functions.sh +1 -1
  47. data/ext/h3/src/scripts/coverage.sh.in +1 -1
  48. data/ext/h3/src/scripts/update_version.sh +2 -2
  49. data/ext/h3/src/src/apps/applib/include/args.h +1 -0
  50. data/ext/h3/src/src/apps/applib/include/test.h +1 -0
  51. data/ext/h3/src/src/apps/applib/include/utility.h +7 -1
  52. data/ext/h3/src/src/apps/applib/lib/args.c +2 -0
  53. data/ext/h3/src/src/apps/applib/lib/kml.c +2 -0
  54. data/ext/h3/src/src/apps/applib/lib/test.c +1 -0
  55. data/ext/h3/src/src/apps/applib/lib/utility.c +133 -2
  56. data/ext/h3/src/src/apps/benchmarks/benchmarkH3Api.c +1 -1
  57. data/ext/h3/src/{website/html.config.js → src/apps/benchmarks/benchmarkH3UniEdge.c} +15 -12
  58. data/ext/h3/src/src/apps/filters/h3ToComponents.c +1 -0
  59. data/ext/h3/src/src/apps/filters/h3ToGeo.c +1 -0
  60. data/ext/h3/src/src/apps/filters/h3ToGeoBoundary.c +1 -0
  61. data/ext/h3/src/src/apps/filters/h3ToLocalIj.c +1 -0
  62. data/ext/h3/src/src/apps/filters/hexRange.c +1 -0
  63. data/ext/h3/src/src/apps/filters/kRing.c +1 -0
  64. data/ext/h3/src/src/apps/filters/localIjToH3.c +1 -0
  65. data/ext/h3/src/src/apps/miscapps/generateFaceCenterPoint.c +1 -0
  66. data/ext/h3/src/src/apps/miscapps/generateNumHexagons.c +1 -0
  67. data/ext/h3/src/src/apps/miscapps/generatePentagonDirectionFaces.c +67 -0
  68. data/ext/h3/src/src/apps/miscapps/h3ToGeoBoundaryHier.c +1 -0
  69. data/ext/h3/src/src/apps/miscapps/h3ToGeoHier.c +1 -0
  70. data/ext/h3/src/src/apps/miscapps/h3ToHier.c +1 -0
  71. data/ext/h3/src/src/apps/testapps/mkRandGeo.c +1 -0
  72. data/ext/h3/src/src/apps/testapps/mkRandGeoBoundary.c +1 -0
  73. data/ext/h3/src/src/apps/testapps/testBBox.c +1 -0
  74. data/ext/h3/src/src/apps/testapps/testBaseCells.c +15 -1
  75. data/ext/h3/src/src/apps/testapps/testCompact.c +109 -2
  76. data/ext/h3/src/src/apps/testapps/testCoordIj.c +1 -0
  77. data/ext/h3/src/src/apps/testapps/testGeoCoord.c +47 -8
  78. data/ext/h3/src/src/apps/testapps/testGeoToH3.c +1 -0
  79. data/ext/h3/src/src/apps/testapps/testH3Api.c +1 -0
  80. data/ext/h3/src/src/apps/testapps/testH3CellArea.c +47 -0
  81. data/ext/h3/src/src/apps/testapps/testH3CellAreaExhaustive.c +180 -0
  82. data/ext/h3/src/src/apps/testapps/testH3Distance.c +1 -0
  83. data/ext/h3/src/src/apps/testapps/testH3DistanceExhaustive.c +1 -0
  84. data/ext/h3/src/src/apps/testapps/testH3GetFaces.c +1 -0
  85. data/ext/h3/src/src/apps/testapps/testH3Index.c +33 -3
  86. data/ext/h3/src/src/apps/testapps/testH3Line.c +1 -0
  87. data/ext/h3/src/src/apps/testapps/testH3LineExhaustive.c +1 -0
  88. data/ext/h3/src/src/apps/testapps/testH3Memory.c +175 -0
  89. data/ext/h3/src/src/apps/testapps/testH3NeighborRotations.c +1 -0
  90. data/ext/h3/src/src/apps/testapps/testH3SetToLinkedGeo.c +1 -0
  91. data/ext/h3/src/src/apps/testapps/testH3SetToVertexGraph.c +1 -0
  92. data/ext/h3/src/src/apps/testapps/testH3ToCenterChild.c +1 -0
  93. data/ext/h3/src/src/apps/testapps/testH3ToChildren.c +1 -0
  94. data/ext/h3/src/src/apps/testapps/testH3ToGeo.c +1 -0
  95. data/ext/h3/src/src/apps/testapps/testH3ToGeoBoundary.c +1 -0
  96. data/ext/h3/src/src/apps/testapps/testH3ToLocalIj.c +12 -6
  97. data/ext/h3/src/src/apps/testapps/testH3ToLocalIjExhaustive.c +1 -0
  98. data/ext/h3/src/src/apps/testapps/testH3ToParent.c +1 -0
  99. data/ext/h3/src/src/apps/testapps/testH3UniEdge.c +45 -16
  100. data/ext/h3/src/src/apps/testapps/testH3UniEdgeExhaustive.c +111 -0
  101. data/ext/h3/src/src/apps/testapps/testHexRanges.c +1 -0
  102. data/ext/h3/src/src/apps/testapps/testHexRing.c +1 -0
  103. data/ext/h3/src/src/apps/testapps/testKRing.c +19 -0
  104. data/ext/h3/src/src/apps/testapps/testLinkedGeo.c +1 -0
  105. data/ext/h3/src/src/apps/testapps/testMaxH3ToChildrenSize.c +1 -0
  106. data/ext/h3/src/src/apps/testapps/testPentagonIndexes.c +1 -0
  107. data/ext/h3/src/src/apps/testapps/testPolyfill.c +72 -9
  108. data/ext/h3/src/src/apps/testapps/testPolyfillReported.c +157 -0
  109. data/ext/h3/src/src/apps/testapps/testPolygon.c +27 -1
  110. data/ext/h3/src/src/apps/testapps/testVec2d.c +1 -0
  111. data/ext/h3/src/src/apps/testapps/testVec3d.c +1 -0
  112. data/ext/h3/src/src/apps/testapps/testVertex.c +66 -0
  113. data/ext/h3/src/src/apps/testapps/testVertexGraph.c +1 -0
  114. data/ext/h3/src/src/h3lib/include/algos.h +8 -0
  115. data/ext/h3/src/src/h3lib/include/alloc.h +40 -0
  116. data/ext/h3/src/src/h3lib/include/baseCells.h +4 -0
  117. data/ext/h3/src/src/h3lib/include/bbox.h +4 -1
  118. data/ext/h3/src/src/h3lib/include/faceijk.h +3 -2
  119. data/ext/h3/src/src/h3lib/include/geoCoord.h +2 -3
  120. data/ext/h3/src/src/h3lib/include/h3Index.h +37 -4
  121. data/ext/h3/src/src/h3lib/include/h3api.h.in +65 -17
  122. data/ext/h3/src/src/h3lib/include/linkedGeo.h +1 -0
  123. data/ext/h3/src/src/h3lib/include/polygon.h +1 -0
  124. data/ext/h3/src/src/h3lib/include/polygonAlgos.h +1 -0
  125. data/ext/h3/src/src/h3lib/include/vertex.h +44 -0
  126. data/ext/h3/src/src/h3lib/include/vertexGraph.h +1 -0
  127. data/ext/h3/src/src/h3lib/lib/algos.c +304 -76
  128. data/ext/h3/src/src/h3lib/lib/baseCells.c +26 -4
  129. data/ext/h3/src/src/h3lib/lib/bbox.c +56 -27
  130. data/ext/h3/src/src/h3lib/lib/coordijk.c +2 -0
  131. data/ext/h3/src/src/h3lib/lib/faceijk.c +32 -21
  132. data/ext/h3/src/src/h3lib/lib/geoCoord.c +162 -44
  133. data/ext/h3/src/src/h3lib/lib/h3Index.c +83 -42
  134. data/ext/h3/src/src/h3lib/lib/h3UniEdge.c +42 -57
  135. data/ext/h3/src/src/h3lib/lib/linkedGeo.c +20 -15
  136. data/ext/h3/src/src/h3lib/lib/localij.c +1 -1
  137. data/ext/h3/src/src/h3lib/lib/polygon.c +2 -0
  138. data/ext/h3/src/src/h3lib/lib/vec2d.c +1 -0
  139. data/ext/h3/src/src/h3lib/lib/vec3d.c +1 -0
  140. data/ext/h3/src/src/h3lib/lib/vertex.c +134 -0
  141. data/ext/h3/src/src/h3lib/lib/vertexGraph.c +8 -5
  142. data/ext/h3/src/website/.eslintignore +2 -0
  143. data/ext/h3/src/website/.gitignore +57 -0
  144. data/ext/h3/src/website/.nvmrc +1 -0
  145. data/ext/h3/src/website/README.md +8 -6
  146. data/ext/h3/src/website/gatsby-config.js +83 -0
  147. data/ext/h3/src/website/package.json +20 -12
  148. data/ext/h3/src/website/scripts/build-to-gh-pages.sh +7 -5
  149. data/ext/h3/src/website/src/.gitkeep +0 -0
  150. data/ext/h3/src/website/templates/documentation.jsx +129 -0
  151. data/ext/h3/src/website/yarn.lock +13723 -0
  152. data/h3.gemspec +2 -2
  153. data/lib/h3/bindings/base.rb +14 -4
  154. data/lib/h3/bindings/private.rb +12 -9
  155. data/lib/h3/hierarchy.rb +0 -18
  156. data/lib/h3/indexing.rb +0 -18
  157. data/lib/h3/inspection.rb +3 -59
  158. data/lib/h3/miscellaneous.rb +119 -14
  159. data/lib/h3/regions.rb +3 -0
  160. data/lib/h3/traversal.rb +0 -18
  161. data/lib/h3/unidirectional_edges.rb +5 -60
  162. data/lib/h3/version.rb +1 -1
  163. data/spec/geo_json_spec.rb +8 -0
  164. data/spec/miscellaneous_spec.rb +117 -0
  165. data/spec/{region_spec.rb → regions_spec.rb} +1 -1
  166. data/spec/spec_helper.rb +2 -2
  167. metadata +44 -36
  168. data/.travis.yml +0 -11
  169. data/ext/h3/src/.ycm_extra_conf.py +0 -92
  170. data/ext/h3/src/appveyor.yml +0 -50
  171. data/ext/h3/src/website/src/config.js +0 -46
  172. data/ext/h3/src/website/src/mdRoutes.js +0 -151
  173. data/ext/h3/src/website/src/styles/_variables.scss +0 -16
  174. data/ext/h3/src/website/src/styles/index.scss +0 -3
  175. 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
  }
@@ -266,17 +279,27 @@ H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
266
279
  */
267
280
  int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
268
281
  const int numHexes) {
282
+ if (numHexes == 0) {
283
+ return COMPACT_SUCCESS;
284
+ }
269
285
  int res = H3_GET_RESOLUTION(h3Set[0]);
270
286
  if (res == 0) {
271
287
  // No compaction possible, just copy the set to output
272
288
  for (int i = 0; i < numHexes; i++) {
273
289
  compactedSet[i] = h3Set[i];
274
290
  }
275
- return 0;
291
+ return COMPACT_SUCCESS;
292
+ }
293
+ H3Index* remainingHexes = H3_MEMORY(malloc)(numHexes * sizeof(H3Index));
294
+ if (!remainingHexes) {
295
+ return COMPACT_ALLOC_FAILED;
276
296
  }
277
- H3Index* remainingHexes = malloc(numHexes * sizeof(H3Index));
278
297
  memcpy(remainingHexes, h3Set, numHexes * sizeof(H3Index));
279
- 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
+ }
280
303
  H3Index* compactedSetOffset = compactedSet;
281
304
  int numRemainingHexes = numHexes;
282
305
  while (numRemainingHexes) {
@@ -298,23 +321,31 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
298
321
  // This case should not be possible because at most one
299
322
  // index is placed into hashSetArray per
300
323
  // numRemainingHexes.
301
- free(remainingHexes);
302
- free(hashSetArray);
303
- return -1;
324
+ H3_MEMORY(free)(remainingHexes);
325
+ H3_MEMORY(free)(hashSetArray);
326
+ return COMPACT_LOOP_EXCEEDED;
304
327
  // LCOV_EXCL_STOP
305
328
  }
306
329
  H3Index tempIndex =
307
330
  hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
308
331
  if (tempIndex == parent) {
309
332
  int count = H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
310
- 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) {
311
342
  // Only possible on duplicate input
312
- free(remainingHexes);
313
- free(hashSetArray);
314
- return -2;
343
+ H3_MEMORY(free)(remainingHexes);
344
+ H3_MEMORY(free)(hashSetArray);
345
+ return COMPACT_DUPLICATE;
315
346
  }
316
347
  H3_SET_RESERVED_BITS(parent, count);
317
- hashSetArray[loc] = H3_INVALID_INDEX;
348
+ hashSetArray[loc] = H3_NULL;
318
349
  } else {
319
350
  loc = (loc + 1) % numRemainingHexes;
320
351
  }
@@ -334,7 +365,12 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
334
365
  break;
335
366
  }
336
367
  H3Index* compactableHexes =
337
- 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
+ }
338
374
  for (int i = 0; i < numRemainingHexes; i++) {
339
375
  if (hashSetArray[i] == 0) continue;
340
376
  int count = H3_GET_RESERVED_BITS(hashSetArray[i]) + 1;
@@ -360,7 +396,7 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
360
396
  int uncompactableCount = 0;
361
397
  for (int i = 0; i < numRemainingHexes; i++) {
362
398
  H3Index currIndex = remainingHexes[i];
363
- if (currIndex != H3_INVALID_INDEX) {
399
+ if (currIndex != H3_NULL) {
364
400
  H3Index parent = H3_EXPORT(h3ToParent)(currIndex, parentRes);
365
401
  // Modulus hash the parent into the temp array
366
402
  // to determine if this index was included in
@@ -373,10 +409,10 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
373
409
  // LCOV_EXCL_START
374
410
  // This case should not be possible because at most one
375
411
  // index is placed into hashSetArray per input hexagon.
376
- free(compactableHexes);
377
- free(remainingHexes);
378
- free(hashSetArray);
379
- 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;
380
416
  // LCOV_EXCL_STOP
381
417
  }
382
418
  H3Index tempIndex =
@@ -404,11 +440,11 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
404
440
  memcpy(remainingHexes, compactableHexes,
405
441
  compactableCount * sizeof(H3Index));
406
442
  numRemainingHexes = compactableCount;
407
- free(compactableHexes);
443
+ H3_MEMORY(free)(compactableHexes);
408
444
  }
409
- free(remainingHexes);
410
- free(hashSetArray);
411
- return 0;
445
+ H3_MEMORY(free)(remainingHexes);
446
+ H3_MEMORY(free)(hashSetArray);
447
+ return COMPACT_SUCCESS;
412
448
  }
413
449
 
414
450
  /**
@@ -600,7 +636,7 @@ H3Index _h3Rotate60cw(H3Index h) {
600
636
  * Convert an FaceIJK address to the corresponding H3Index.
601
637
  * @param fijk The FaceIJK address.
602
638
  * @param res The cell resolution.
603
- * @return The encoded H3Index (or 0 on failure).
639
+ * @return The encoded H3Index (or H3_NULL on failure).
604
640
  */
605
641
  H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
606
642
  // initialize the index
@@ -613,7 +649,7 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
613
649
  if (fijk->coord.i > MAX_FACE_COORD || fijk->coord.j > MAX_FACE_COORD ||
614
650
  fijk->coord.k > MAX_FACE_COORD) {
615
651
  // out of range input
616
- return H3_INVALID_INDEX;
652
+ return H3_NULL;
617
653
  }
618
654
 
619
655
  H3_SET_BASE_CELL(h, _faceIjkToBaseCell(fijk));
@@ -657,7 +693,7 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
657
693
  if (fijkBC.coord.i > MAX_FACE_COORD || fijkBC.coord.j > MAX_FACE_COORD ||
658
694
  fijkBC.coord.k > MAX_FACE_COORD) {
659
695
  // out of range input
660
- return H3_INVALID_INDEX;
696
+ return H3_NULL;
661
697
  }
662
698
 
663
699
  // lookup the correct base cell
@@ -696,14 +732,14 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
696
732
  *
697
733
  * @param g The spherical coordinates to encode.
698
734
  * @param res The desired H3 resolution for the encoding.
699
- * @return The encoded H3Index (or 0 on failure).
735
+ * @return The encoded H3Index (or H3_NULL on failure).
700
736
  */
701
737
  H3Index H3_EXPORT(geoToH3)(const GeoCoord* g, int res) {
702
738
  if (res < 0 || res > MAX_H3_RES) {
703
- return H3_INVALID_INDEX;
739
+ return H3_NULL;
704
740
  }
705
741
  if (!isfinite(g->lat) || !isfinite(g->lon)) {
706
- return H3_INVALID_INDEX;
742
+ return H3_NULL;
707
743
  }
708
744
 
709
745
  FaceIJK fijk;
@@ -813,8 +849,13 @@ void H3_EXPORT(h3ToGeo)(H3Index h3, GeoCoord* g) {
813
849
  void H3_EXPORT(h3ToGeoBoundary)(H3Index h3, GeoBoundary* gb) {
814
850
  FaceIJK fijk;
815
851
  _h3ToFaceIjk(h3, &fijk);
816
- _faceIjkToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3),
817
- 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
+ }
818
859
  }
819
860
 
820
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
  }