h3 3.6.2 → 3.7.1

Sign up to get free protection for your applications and to get access to all the features.
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
  }