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
@@ -1,5 +1,5 @@
1
1
  /*
2
- * Copyright 2016-2019 Uber Technologies, Inc.
2
+ * Copyright 2016-2020 Uber Technologies, Inc.
3
3
  *
4
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
5
  * you may not use this file except in compliance with the License.
@@ -150,7 +150,7 @@ typedef struct {
150
150
  * Functions for geoToH3
151
151
  * @{
152
152
  */
153
- /** @brief find the H3 index of the resolution res cell containing the lat/lon g
153
+ /** @brief find the H3 index of the resolution res cell containing the lat/lng
154
154
  */
155
155
  H3Index H3_EXPORT(geoToH3)(const GeoCoord *g, int res);
156
156
  /** @} */
@@ -183,8 +183,7 @@ int H3_EXPORT(hexRange)(H3Index origin, int k, H3Index *out);
183
183
  /** @} */
184
184
 
185
185
  /** @brief hexagons neighbors in all directions, assuming no pentagons,
186
- * reporting
187
- * distance from origin */
186
+ * reporting distance from origin */
188
187
  int H3_EXPORT(hexRangeDistances)(H3Index origin, int k, H3Index *out,
189
188
  int *distances);
190
189
 
@@ -252,33 +251,77 @@ double H3_EXPORT(degsToRads)(double degrees);
252
251
  double H3_EXPORT(radsToDegs)(double radians);
253
252
  /** @} */
254
253
 
254
+ /** @defgroup pointDist pointDist
255
+ * Functions for pointDist
256
+ * @{
257
+ */
258
+ /** @brief "great circle distance" between pairs of GeoCoord points in radians*/
259
+ double H3_EXPORT(pointDistRads)(const GeoCoord *a, const GeoCoord *b);
260
+
261
+ /** @brief "great circle distance" between pairs of GeoCoord points in
262
+ * kilometers*/
263
+ double H3_EXPORT(pointDistKm)(const GeoCoord *a, const GeoCoord *b);
264
+
265
+ /** @brief "great circle distance" between pairs of GeoCoord points in meters*/
266
+ double H3_EXPORT(pointDistM)(const GeoCoord *a, const GeoCoord *b);
267
+ /** @} */
268
+
255
269
  /** @defgroup hexArea hexArea
256
270
  * Functions for hexArea
257
271
  * @{
258
272
  */
259
- /** @brief hexagon area in square kilometers */
273
+ /** @brief average hexagon area in square kilometers (excludes pentagons) */
260
274
  double H3_EXPORT(hexAreaKm2)(int res);
261
275
 
262
- /** @brief hexagon area in square meters */
276
+ /** @brief average hexagon area in square meters (excludes pentagons) */
263
277
  double H3_EXPORT(hexAreaM2)(int res);
264
278
  /** @} */
265
279
 
280
+ /** @defgroup cellArea cellArea
281
+ * Functions for cellArea
282
+ * @{
283
+ */
284
+ /** @brief exact area for a specific cell (hexagon or pentagon) in radians^2 */
285
+ double H3_EXPORT(cellAreaRads2)(H3Index h);
286
+
287
+ /** @brief exact area for a specific cell (hexagon or pentagon) in kilometers^2
288
+ */
289
+ double H3_EXPORT(cellAreaKm2)(H3Index h);
290
+
291
+ /** @brief exact area for a specific cell (hexagon or pentagon) in meters^2 */
292
+ double H3_EXPORT(cellAreaM2)(H3Index h);
293
+ /** @} */
294
+
266
295
  /** @defgroup edgeLength edgeLength
267
296
  * Functions for edgeLength
268
297
  * @{
269
298
  */
270
- /** @brief hexagon edge length in kilometers */
299
+ /** @brief average hexagon edge length in kilometers (excludes pentagons) */
271
300
  double H3_EXPORT(edgeLengthKm)(int res);
272
301
 
273
- /** @brief hexagon edge length in meters */
302
+ /** @brief average hexagon edge length in meters (excludes pentagons) */
274
303
  double H3_EXPORT(edgeLengthM)(int res);
275
304
  /** @} */
276
305
 
306
+ /** @defgroup exactEdgeLength exactEdgeLength
307
+ * Functions for exactEdgeLength
308
+ * @{
309
+ */
310
+ /** @brief exact length for a specific unidirectional edge in radians*/
311
+ double H3_EXPORT(exactEdgeLengthRads)(H3Index edge);
312
+
313
+ /** @brief exact length for a specific unidirectional edge in kilometers*/
314
+ double H3_EXPORT(exactEdgeLengthKm)(H3Index edge);
315
+
316
+ /** @brief exact length for a specific unidirectional edge in meters*/
317
+ double H3_EXPORT(exactEdgeLengthM)(H3Index edge);
318
+ /** @} */
319
+
277
320
  /** @defgroup numHexagons numHexagons
278
321
  * Functions for numHexagons
279
322
  * @{
280
323
  */
281
- /** @brief number of hexagons for a given resolution */
324
+ /** @brief number of cells (hexagons and pentagons) for a given resolution */
282
325
  int64_t H3_EXPORT(numHexagons)(int res);
283
326
  /** @} */
284
327
 
@@ -286,10 +329,10 @@ int64_t H3_EXPORT(numHexagons)(int res);
286
329
  * Functions for getRes0Indexes
287
330
  * @{
288
331
  */
289
- /** @brief returns the number of resolution 0 indexes */
332
+ /** @brief returns the number of resolution 0 cells (hexagons and pentagons) */
290
333
  int H3_EXPORT(res0IndexCount)();
291
334
 
292
- /** @brief provides all base cells */
335
+ /** @brief provides all base cells in H3Index format*/
293
336
  void H3_EXPORT(getRes0Indexes)(H3Index *out);
294
337
  /** @} */
295
338
 
@@ -308,7 +351,8 @@ void H3_EXPORT(getPentagonIndexes)(int res, H3Index *out);
308
351
  * Functions for h3GetResolution
309
352
  * @{
310
353
  */
311
- /** @brief returns the resolution of the provided hexagon */
354
+ /** @brief returns the resolution of the provided H3 index
355
+ * Works on both cells and unidirectional edges. */
312
356
  int H3_EXPORT(h3GetResolution)(H3Index h);
313
357
  /** @} */
314
358
 
@@ -316,7 +360,10 @@ int H3_EXPORT(h3GetResolution)(H3Index h);
316
360
  * Functions for h3GetBaseCell
317
361
  * @{
318
362
  */
319
- /** @brief returns the base cell of the provided hexagon */
363
+ /** @brief returns the base cell "number" (0 to 121) of the provided H3 cell
364
+ *
365
+ * Note: Technically works on H3 edges, but will return base cell of the
366
+ * origin cell. */
320
367
  int H3_EXPORT(h3GetBaseCell)(H3Index h);
321
368
  /** @} */
322
369
 
@@ -340,7 +387,9 @@ void H3_EXPORT(h3ToString)(H3Index h, char *str, size_t sz);
340
387
  * Functions for h3IsValid
341
388
  * @{
342
389
  */
343
- /** @brief confirms if an H3Index is valid */
390
+ /** @brief confirms if an H3Index is a valid cell (hexagon or pentagon)
391
+ * In particular, returns 0 (False) for H3 unidirectional edges or invalid data
392
+ */
344
393
  int H3_EXPORT(h3IsValid)(H3Index h);
345
394
  /** @} */
346
395
 
@@ -358,8 +407,7 @@ H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes);
358
407
  * @{
359
408
  */
360
409
  /** @brief determines the maximum number of children (or grandchildren, etc)
361
- * that
362
- * could be returned for the given hexagon */
410
+ * that could be returned for the given hexagon */
363
411
  int H3_EXPORT(maxH3ToChildrenSize)(H3Index h, int childRes);
364
412
 
365
413
  /** @brief provides the children (or grandchildren, etc) of the given hexagon */
@@ -410,7 +458,7 @@ int H3_EXPORT(h3IsResClassIII)(H3Index h);
410
458
  * Functions for h3IsPentagon
411
459
  * @{
412
460
  */
413
- /** @brief determines if a hexagon is actually a pentagon */
461
+ /** @brief determines if an H3 cell is a pentagon */
414
462
  int H3_EXPORT(h3IsPentagon)(H3Index h);
415
463
  /** @} */
416
464
 
@@ -21,6 +21,7 @@
21
21
  #define LINKED_GEO_H
22
22
 
23
23
  #include <stdlib.h>
24
+
24
25
  #include "bbox.h"
25
26
  #include "geoCoord.h"
26
27
  #include "h3api.h"
@@ -21,6 +21,7 @@
21
21
  #define POLYGON_H
22
22
 
23
23
  #include <stdbool.h>
24
+
24
25
  #include "bbox.h"
25
26
  #include "geoCoord.h"
26
27
  #include "h3api.h"
@@ -25,6 +25,7 @@
25
25
  #include <float.h>
26
26
  #include <math.h>
27
27
  #include <stdbool.h>
28
+
28
29
  #include "bbox.h"
29
30
  #include "constants.h"
30
31
  #include "geoCoord.h"
@@ -0,0 +1,44 @@
1
+ /*
2
+ * Copyright 2020 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 vertex.h
17
+ * @brief Functions for working with cell vertexes.
18
+ */
19
+
20
+ #ifndef H3VERTEX_H
21
+ #define H3VERTEX_H
22
+
23
+ #include "h3Index.h"
24
+ #include "faceijk.h"
25
+
26
+ /** @struct PentagonDirectionFaces
27
+ * @brief The faces in each axial direction of a given pentagon base cell
28
+ */
29
+ typedef struct {
30
+ int baseCell; ///< base cell number
31
+ int faces[NUM_PENT_VERTS]; ///< face numbers for each axial direction,
32
+ /// in order, starting with J
33
+ } PentagonDirectionFaces;
34
+
35
+ /** Invalid vertex number */
36
+ #define INVALID_VERTEX_NUM -1
37
+
38
+ /** Max number of faces a base cell's descendants may appear on */
39
+ #define MAX_BASE_CELL_FACES 5
40
+
41
+ int vertexRotations(H3Index cell);
42
+ int vertexNumForDirection(const H3Index origin, const Direction direction);
43
+
44
+ #endif
@@ -22,6 +22,7 @@
22
22
 
23
23
  #include <stdint.h>
24
24
  #include <stdlib.h>
25
+
25
26
  #include "geoCoord.h"
26
27
 
27
28
  /** @struct VertexNode
@@ -18,12 +18,15 @@
18
18
  */
19
19
 
20
20
  #include "algos.h"
21
+
21
22
  #include <assert.h>
22
23
  #include <float.h>
23
24
  #include <math.h>
24
25
  #include <stdbool.h>
25
26
  #include <stdlib.h>
26
27
  #include <string.h>
28
+
29
+ #include "alloc.h"
27
30
  #include "baseCells.h"
28
31
  #include "bbox.h"
29
32
  #include "faceijk.h"
@@ -41,6 +44,9 @@
41
44
  #define HEX_RANGE_SUCCESS 0
42
45
  #define HEX_RANGE_PENTAGON 1
43
46
  #define HEX_RANGE_K_SUBSEQUENCE 2
47
+ #define MAX_ONE_RING_SIZE 7
48
+ #define HEX_HASH_OVERFLOW -1
49
+ #define POLYFILL_BUFFER 12
44
50
 
45
51
  /**
46
52
  * Directions used for traversing a hexagonal ring counterclockwise around
@@ -150,74 +156,86 @@ static const Direction NEW_ADJUSTMENT_III[7][7] = {
150
156
  CENTER_DIGIT, IJ_AXES_DIGIT}};
151
157
 
152
158
  /**
153
- * Maximum number of indices that result from the kRing algorithm with the given
159
+ * Maximum number of cells that result from the kRing algorithm with the given
154
160
  * k. Formula source and proof: https://oeis.org/A003215
155
161
  *
156
- * @param k k value, k >= 0.
162
+ * @param k k value, k >= 0.
157
163
  */
158
164
  int H3_EXPORT(maxKringSize)(int k) { return 3 * k * (k + 1) + 1; }
159
165
 
160
166
  /**
161
- * k-rings produces indices within k distance of the origin index.
167
+ * Produce cells within grid distance k of the origin cell.
162
168
  *
163
- * k-ring 0 is defined as the origin index, k-ring 1 is defined as k-ring 0 and
164
- * all neighboring indices, and so on.
169
+ * k-ring 0 is defined as the origin cell, k-ring 1 is defined as k-ring 0 and
170
+ * all neighboring cells, and so on.
165
171
  *
166
172
  * Output is placed in the provided array in no particular order. Elements of
167
173
  * the output array may be left zero, as can happen when crossing a pentagon.
168
174
  *
169
- * @param origin Origin location.
170
- * @param k k >= 0
171
- * @param out Zero-filled array which must be of size maxKringSize(k).
175
+ * @param origin origin cell
176
+ * @param k k >= 0
177
+ * @param out zero-filled array which must be of size maxKringSize(k)
172
178
  */
173
179
  void H3_EXPORT(kRing)(H3Index origin, int k, H3Index* out) {
174
- int maxIdx = H3_EXPORT(maxKringSize)(k);
175
- int* distances = malloc(maxIdx * sizeof(int));
176
- H3_EXPORT(kRingDistances)(origin, k, out, distances);
177
- free(distances);
180
+ H3_EXPORT(kRingDistances)(origin, k, out, NULL);
178
181
  }
179
182
 
180
183
  /**
181
- * k-rings produces indices within k distance of the origin index.
184
+ * Produce cells and their distances from the given origin cell, up to
185
+ * distance k.
182
186
  *
183
- * k-ring 0 is defined as the origin index, k-ring 1 is defined as k-ring 0 and
184
- * all neighboring indices, and so on.
187
+ * k-ring 0 is defined as the origin cell, k-ring 1 is defined as k-ring 0 and
188
+ * all neighboring cells, and so on.
185
189
  *
186
190
  * Output is placed in the provided array in no particular order. Elements of
187
191
  * the output array may be left zero, as can happen when crossing a pentagon.
188
192
  *
189
- * @param origin Origin location.
190
- * @param k k >= 0
191
- * @param out Zero-filled array which must be of size maxKringSize(k).
192
- * @param distances Zero-filled array which must be of size maxKringSize(k).
193
+ * @param origin origin cell
194
+ * @param k k >= 0
195
+ * @param out zero-filled array which must be of size maxKringSize(k)
196
+ * @param distances NULL or a zero-filled array which must be of size
197
+ * maxKringSize(k)
193
198
  */
194
199
  void H3_EXPORT(kRingDistances)(H3Index origin, int k, H3Index* out,
195
200
  int* distances) {
196
- const int maxIdx = H3_EXPORT(maxKringSize)(k);
197
201
  // Optimistically try the faster hexRange algorithm first
198
202
  const bool failed = H3_EXPORT(hexRangeDistances)(origin, k, out, distances);
199
203
  if (failed) {
204
+ const int maxIdx = H3_EXPORT(maxKringSize)(k);
200
205
  // Fast algo failed, fall back to slower, correct algo
201
206
  // and also wipe out array because contents untrustworthy
202
- memset(out, 0, maxIdx * sizeof(out[0]));
203
- memset(distances, 0, maxIdx * sizeof(distances[0]));
204
- _kRingInternal(origin, k, out, distances, maxIdx, 0);
207
+ memset(out, 0, maxIdx * sizeof(H3Index));
208
+
209
+ if (distances == NULL) {
210
+ distances = H3_MEMORY(calloc)(maxIdx, sizeof(int));
211
+ if (!distances) {
212
+ // TODO: Return an error code when this is not void
213
+ return;
214
+ }
215
+ _kRingInternal(origin, k, out, distances, maxIdx, 0);
216
+ H3_MEMORY(free)(distances);
217
+ } else {
218
+ memset(distances, 0, maxIdx * sizeof(int));
219
+ _kRingInternal(origin, k, out, distances, maxIdx, 0);
220
+ }
205
221
  }
206
222
  }
207
223
 
208
224
  /**
209
225
  * Internal helper function called recursively for kRingDistances.
210
226
  *
211
- * Adds the origin index to the output set (treating it as a hash set)
227
+ * Adds the origin cell to the output set (treating it as a hash set)
212
228
  * and recurses to its neighbors, if needed.
213
229
  *
214
- * @param origin
215
- * @param k Maximum distance to move from the origin.
216
- * @param out Array treated as a hash set, elements being either H3Index or 0.
217
- * @param distances Scratch area, with elements paralleling the out array.
218
- * Elements indicate ijk distance from the origin index to the output index.
219
- * @param maxIdx Size of out and scratch arrays (must be maxKringSize(k))
220
- * @param curK Current distance from the origin.
230
+ * @param origin Origin cell
231
+ * @param k Maximum distance to move from the origin
232
+ * @param out Array treated as a hash set, elements being either
233
+ * H3Index or 0.
234
+ * @param distances Scratch area, with elements paralleling the out array.
235
+ * Elements indicate ijk distance from the origin cell to
236
+ * the output cell
237
+ * @param maxIdx Size of out and scratch arrays (must be maxKringSize(k))
238
+ * @param curK Current distance from the origin
221
239
  */
222
240
  void _kRingInternal(H3Index origin, int k, H3Index* out, int* distances,
223
241
  int maxIdx, int curK) {
@@ -260,7 +278,7 @@ void _kRingInternal(H3Index origin, int k, H3Index* out, int* distances,
260
278
  * @param rotations Number of ccw rotations to perform to reorient the
261
279
  * translation vector. Will be modified to the new number of
262
280
  * rotations to perform (such as when crossing a face edge.)
263
- * @return H3Index of the specified neighbor or 0 if deleted k-subsequence
281
+ * @return H3Index of the specified neighbor or H3_NULL if deleted k-subsequence
264
282
  * distortion is encountered.
265
283
  */
266
284
  H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
@@ -345,7 +363,7 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
345
363
  // base cell.
346
364
  if (oldLeadingDigit == CENTER_DIGIT) {
347
365
  // Undefined: the k direction is deleted from here
348
- return H3_INVALID_INDEX;
366
+ return H3_NULL;
349
367
  } else if (oldLeadingDigit == JK_AXES_DIGIT) {
350
368
  // Rotate out of the deleted k subsequence
351
369
  // We also need an additional change to the direction we're
@@ -360,7 +378,7 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
360
378
  *rotations = *rotations + 5;
361
379
  } else {
362
380
  // Should never occur
363
- return H3_INVALID_INDEX; // LCOV_EXCL_LINE
381
+ return H3_NULL; // LCOV_EXCL_LINE
364
382
  }
365
383
  }
366
384
  }
@@ -410,7 +428,7 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
410
428
  * @return 0 if no pentagon or pentagonal distortion area was encountered.
411
429
  */
412
430
  int H3_EXPORT(hexRange)(H3Index origin, int k, H3Index* out) {
413
- return H3_EXPORT(hexRangeDistances)(origin, k, out, 0);
431
+ return H3_EXPORT(hexRangeDistances)(origin, k, out, NULL);
414
432
  }
415
433
 
416
434
  /**
@@ -623,9 +641,8 @@ int H3_EXPORT(hexRing)(H3Index origin, int k, H3Index* out) {
623
641
  * maxPolyfillSize returns the number of hexagons to allocate space for when
624
642
  * performing a polyfill on the given GeoJSON-like data structure.
625
643
  *
626
- * Currently a laughably padded response, being a k-ring that wholly contains
627
- * a bounding box of the GeoJSON, but still less wasted memory than initializing
628
- * a Python application? ;)
644
+ * The size is the maximum of either the number of points in the geofence or the
645
+ * number of hexagons in the bounding box of the geofence.
629
646
  *
630
647
  * @param geoPolygon A GeoJSON-like data structure indicating the poly to fill
631
648
  * @param res Hexagon resolution (0-15)
@@ -634,12 +651,23 @@ int H3_EXPORT(hexRing)(H3Index origin, int k, H3Index* out) {
634
651
  int H3_EXPORT(maxPolyfillSize)(const GeoPolygon* geoPolygon, int res) {
635
652
  // Get the bounding box for the GeoJSON-like struct
636
653
  BBox bbox;
637
- bboxFromGeofence(&geoPolygon->geofence, &bbox);
638
- int minK = bboxHexRadius(&bbox, res);
639
-
640
- // The total number of hexagons to allocate can now be determined by
641
- // the k-ring hex allocation helper function.
642
- return H3_EXPORT(maxKringSize)(minK);
654
+ const Geofence geofence = geoPolygon->geofence;
655
+ bboxFromGeofence(&geofence, &bbox);
656
+ int numHexagons = bboxHexEstimate(&bbox, res);
657
+ // This algorithm assumes that the number of vertices is usually less than
658
+ // the number of hexagons, but when it's wrong, this will keep it from
659
+ // failing
660
+ int totalVerts = geofence.numVerts;
661
+ for (int i = 0; i < geoPolygon->numHoles; i++) {
662
+ totalVerts += geoPolygon->holes[i].numVerts;
663
+ }
664
+ if (numHexagons < totalVerts) numHexagons = totalVerts;
665
+ // When the polygon is very small, near an icosahedron edge and is an odd
666
+ // resolution, the line tracing needs an extra buffer than the estimator
667
+ // function provides (but beefing that up to cover causes most situations to
668
+ // overallocate memory)
669
+ numHexagons += POLYFILL_BUFFER;
670
+ return numHexagons;
643
671
  }
644
672
 
645
673
  /**
@@ -647,15 +675,109 @@ int H3_EXPORT(maxPolyfillSize)(const GeoPolygon* geoPolygon, int res) {
647
675
  * zeroed memory, and fills it with the hexagons that are contained by
648
676
  * the GeoJSON-like data structure.
649
677
  *
650
- * The current implementation is very primitive and slow, but correct,
651
- * performing a point-in-poly operation on every hexagon in a k-ring defined
652
- * around the given geofence.
678
+ * This implementation traces the GeoJSON geofence(s) in cartesian space with
679
+ * hexagons, tests them and their neighbors to be contained by the geofence(s),
680
+ * and then any newly found hexagons are used to test again until no new
681
+ * hexagons are found.
653
682
  *
654
683
  * @param geoPolygon The geofence and holes defining the relevant area
655
684
  * @param res The Hexagon resolution (0-15)
656
685
  * @param out The slab of zeroed memory to write to. Assumed to be big enough.
657
686
  */
658
687
  void H3_EXPORT(polyfill)(const GeoPolygon* geoPolygon, int res, H3Index* out) {
688
+ // TODO: Eliminate this wrapper with the H3 4.0.0 release
689
+ int failure = _polyfillInternal(geoPolygon, res, out);
690
+ // The polyfill algorithm can theoretically fail if the allocated memory is
691
+ // not large enough for the polygon, but this should be impossible given the
692
+ // conservative overestimation of the number of hexagons possible.
693
+ // LCOV_EXCL_START
694
+ if (failure) {
695
+ int numHexagons = H3_EXPORT(maxPolyfillSize)(geoPolygon, res);
696
+ for (int i = 0; i < numHexagons; i++) out[i] = H3_NULL;
697
+ }
698
+ // LCOV_EXCL_STOP
699
+ }
700
+
701
+ /**
702
+ * _getEdgeHexagons takes a given geofence ring (either the main geofence or
703
+ * one of the holes) and traces it with hexagons and updates the search and
704
+ * found memory blocks. This is used for determining the initial hexagon set
705
+ * for the polyfill algorithm to execute on.
706
+ *
707
+ * @param geofence The geofence (or hole) to be traced
708
+ * @param numHexagons The maximum number of hexagons possible for the geofence
709
+ * (also the bounds of the search and found arrays)
710
+ * @param res The hexagon resolution (0-15)
711
+ * @param numSearchHexes The number of hexagons found so far to be searched
712
+ * @param search The block of memory containing the hexagons to search from
713
+ * @param found The block of memory containing the hexagons found from the
714
+ * search
715
+ *
716
+ * @return An error code if the hash function cannot insert a found hexagon
717
+ * into the found array.
718
+ */
719
+ int _getEdgeHexagons(const Geofence* geofence, int numHexagons, int res,
720
+ int* numSearchHexes, H3Index* search, H3Index* found) {
721
+ for (int i = 0; i < geofence->numVerts; i++) {
722
+ GeoCoord origin = geofence->verts[i];
723
+ GeoCoord destination = i == geofence->numVerts - 1
724
+ ? geofence->verts[0]
725
+ : geofence->verts[i + 1];
726
+ const int numHexesEstimate =
727
+ lineHexEstimate(&origin, &destination, res);
728
+ for (int j = 0; j < numHexesEstimate; j++) {
729
+ GeoCoord interpolate;
730
+ interpolate.lat =
731
+ (origin.lat * (numHexesEstimate - j) / numHexesEstimate) +
732
+ (destination.lat * j / numHexesEstimate);
733
+ interpolate.lon =
734
+ (origin.lon * (numHexesEstimate - j) / numHexesEstimate) +
735
+ (destination.lon * j / numHexesEstimate);
736
+ H3Index pointHex = H3_EXPORT(geoToH3)(&interpolate, res);
737
+ // A simple hash to store the hexagon, or move to another place if
738
+ // needed
739
+ int loc = (int)(pointHex % numHexagons);
740
+ int loopCount = 0;
741
+ while (found[loc] != 0) {
742
+ // If this conditional is reached, the `found` memory block is
743
+ // too small for the given polygon. This should not happen.
744
+ if (loopCount > numHexagons)
745
+ return HEX_HASH_OVERFLOW; // LCOV_EXCL_LINE
746
+ if (found[loc] == pointHex)
747
+ break; // At least two points of the geofence index to the
748
+ // same cell
749
+ loc = (loc + 1) % numHexagons;
750
+ loopCount++;
751
+ }
752
+ if (found[loc] == pointHex)
753
+ continue; // Skip this hex, already exists in the found hash
754
+ // Otherwise, set it in the found hash for now
755
+ found[loc] = pointHex;
756
+
757
+ search[*numSearchHexes] = pointHex;
758
+ (*numSearchHexes)++;
759
+ }
760
+ }
761
+ return 0;
762
+ }
763
+
764
+ /**
765
+ * _polyfillInternal traces the provided geoPolygon data structure with hexagons
766
+ * and then iteratively searches through these hexagons and their immediate
767
+ * neighbors to see if they are contained within the polygon or not. Those that
768
+ * are found are added to the out array as well as the found array. Once all
769
+ * hexagons to search are checked, the found hexagons become the new search
770
+ * array and the found array is wiped and the process repeats until no new
771
+ * hexagons can be found.
772
+ *
773
+ * @param geoPolygon The geofence and holes defining the relevant area
774
+ * @param res The Hexagon resolution (0-15)
775
+ * @param out The slab of zeroed memory to write to. Assumed to be big enough.
776
+ *
777
+ * @return An error code if any of the hash operations fails to insert a hexagon
778
+ * into an array of memory.
779
+ */
780
+ int _polyfillInternal(const GeoPolygon* geoPolygon, int res, H3Index* out) {
659
781
  // One of the goals of the polyfill algorithm is that two adjacent polygons
660
782
  // with zero overlap have zero overlapping hexagons. That the hexagons are
661
783
  // uniquely assigned. There are a few approaches to take here, such as
@@ -674,39 +796,142 @@ void H3_EXPORT(polyfill)(const GeoPolygon* geoPolygon, int res, H3Index* out) {
674
796
  // This first part is identical to the maxPolyfillSize above.
675
797
 
676
798
  // Get the bounding boxes for the polygon and any holes
677
- BBox* bboxes = malloc((geoPolygon->numHoles + 1) * sizeof(BBox));
799
+ BBox* bboxes = H3_MEMORY(malloc)((geoPolygon->numHoles + 1) * sizeof(BBox));
678
800
  assert(bboxes != NULL);
679
801
  bboxesFromGeoPolygon(geoPolygon, bboxes);
680
- int minK = bboxHexRadius(&bboxes[0], res);
681
- int numHexagons = H3_EXPORT(maxKringSize)(minK);
682
-
683
- // Get the center hex
684
- GeoCoord center;
685
- bboxCenter(&bboxes[0], &center);
686
- H3Index centerH3 = H3_EXPORT(geoToH3)(&center, res);
687
-
688
- // From here on it works differently, first we get all potential
689
- // hexagons inserted into the available memory
690
- H3_EXPORT(kRing)(centerH3, minK, out);
691
-
692
- // Next we iterate through each hexagon, and test its center point to see if
693
- // it's contained in the GeoJSON-like struct
694
- for (int i = 0; i < numHexagons; i++) {
695
- // Skip records that are already zeroed
696
- if (out[i] == 0) {
697
- continue;
802
+
803
+ // Get the estimated number of hexagons and allocate some temporary memory
804
+ // for the hexagons
805
+ int numHexagons = H3_EXPORT(maxPolyfillSize)(geoPolygon, res);
806
+ H3Index* search = H3_MEMORY(calloc)(numHexagons, sizeof(H3Index));
807
+ H3Index* found = H3_MEMORY(calloc)(numHexagons, sizeof(H3Index));
808
+
809
+ // Some metadata for tracking the state of the search and found memory
810
+ // blocks
811
+ int numSearchHexes = 0;
812
+ int numFoundHexes = 0;
813
+
814
+ // 1. Trace the hexagons along the polygon defining the outer geofence and
815
+ // add them to the search hash. The hexagon containing the geofence point
816
+ // may or may not be contained by the geofence (as the hexagon's center
817
+ // point may be outside of the boundary.)
818
+ const Geofence geofence = geoPolygon->geofence;
819
+ int failure = _getEdgeHexagons(&geofence, numHexagons, res, &numSearchHexes,
820
+ search, found);
821
+ // If this branch is reached, we have exceeded the maximum number of
822
+ // hexagons possible and need to clean up the allocated memory.
823
+ // LCOV_EXCL_START
824
+ if (failure) {
825
+ H3_MEMORY(free)(search);
826
+ H3_MEMORY(free)(found);
827
+ H3_MEMORY(free)(bboxes);
828
+ return failure;
829
+ }
830
+ // LCOV_EXCL_STOP
831
+
832
+ // 2. Iterate over all holes, trace the polygons defining the holes with
833
+ // hexagons and add to only the search hash. We're going to temporarily use
834
+ // the `found` hash to use for dedupe purposes and then re-zero it once
835
+ // we're done here, otherwise we'd have to scan the whole set on each insert
836
+ // to make sure there's no duplicates, which is very inefficient.
837
+ for (int i = 0; i < geoPolygon->numHoles; i++) {
838
+ Geofence* hole = &(geoPolygon->holes[i]);
839
+ failure = _getEdgeHexagons(hole, numHexagons, res, &numSearchHexes,
840
+ search, found);
841
+ // If this branch is reached, we have exceeded the maximum number of
842
+ // hexagons possible and need to clean up the allocated memory.
843
+ // LCOV_EXCL_START
844
+ if (failure) {
845
+ H3_MEMORY(free)(search);
846
+ H3_MEMORY(free)(found);
847
+ H3_MEMORY(free)(bboxes);
848
+ return failure;
698
849
  }
699
- // Check if hexagon is inside of polygon
700
- GeoCoord hexCenter;
701
- H3_EXPORT(h3ToGeo)(out[i], &hexCenter);
702
- hexCenter.lat = constrainLat(hexCenter.lat);
703
- hexCenter.lon = constrainLng(hexCenter.lon);
704
- // And remove from list if not
705
- if (!pointInsidePolygon(geoPolygon, bboxes, &hexCenter)) {
706
- out[i] = H3_INVALID_INDEX;
850
+ // LCOV_EXCL_STOP
851
+ }
852
+
853
+ // 3. Re-zero the found hash so it can be used in the main loop below
854
+ for (int i = 0; i < numHexagons; i++) found[i] = 0;
855
+
856
+ // 4. Begin main loop. While the search hash is not empty do the following
857
+ while (numSearchHexes > 0) {
858
+ // Iterate through all hexagons in the current search hash, then loop
859
+ // through all neighbors and test Point-in-Poly, if point-in-poly
860
+ // succeeds, add to out and found hashes if not already there.
861
+ int currentSearchNum = 0;
862
+ int i = 0;
863
+ while (currentSearchNum < numSearchHexes) {
864
+ H3Index ring[MAX_ONE_RING_SIZE] = {0};
865
+ H3Index searchHex = search[i];
866
+ H3_EXPORT(kRing)(searchHex, 1, ring);
867
+ for (int j = 0; j < MAX_ONE_RING_SIZE; j++) {
868
+ if (ring[j] == H3_NULL) {
869
+ continue; // Skip if this was a pentagon and only had 5
870
+ // neighbors
871
+ }
872
+
873
+ H3Index hex = ring[j];
874
+
875
+ // A simple hash to store the hexagon, or move to another place
876
+ // if needed. This MUST be done before the point-in-poly check
877
+ // since that's far more expensive
878
+ int loc = (int)(hex % numHexagons);
879
+ int loopCount = 0;
880
+ while (out[loc] != 0) {
881
+ // If this branch is reached, we have exceeded the maximum
882
+ // number of hexagons possible and need to clean up the
883
+ // allocated memory.
884
+ // LCOV_EXCL_START
885
+ if (loopCount > numHexagons) {
886
+ H3_MEMORY(free)(search);
887
+ H3_MEMORY(free)(found);
888
+ H3_MEMORY(free)(bboxes);
889
+ return -1;
890
+ }
891
+ // LCOV_EXCL_STOP
892
+ if (out[loc] == hex) break; // Skip duplicates found
893
+ loc = (loc + 1) % numHexagons;
894
+ loopCount++;
895
+ }
896
+ if (out[loc] == hex) {
897
+ continue; // Skip this hex, already exists in the out hash
898
+ }
899
+
900
+ // Check if the hexagon is in the polygon or not
901
+ GeoCoord hexCenter;
902
+ H3_EXPORT(h3ToGeo)(hex, &hexCenter);
903
+
904
+ // If not, skip
905
+ if (!pointInsidePolygon(geoPolygon, bboxes, &hexCenter)) {
906
+ continue;
907
+ }
908
+
909
+ // Otherwise set it in the output array
910
+ out[loc] = hex;
911
+
912
+ // Set the hexagon in the found hash
913
+ found[numFoundHexes] = hex;
914
+ numFoundHexes++;
915
+ }
916
+ currentSearchNum++;
917
+ i++;
707
918
  }
919
+
920
+ // Swap the search and found pointers, copy the found hex count to the
921
+ // search hex count, and zero everything related to the found memory.
922
+ H3Index* temp = search;
923
+ search = found;
924
+ found = temp;
925
+ for (int j = 0; j < numSearchHexes; j++) found[j] = 0;
926
+ numSearchHexes = numFoundHexes;
927
+ numFoundHexes = 0;
928
+ // Repeat until no new hexagons are found
708
929
  }
709
- free(bboxes);
930
+ // The out memory structure should be complete, end it here
931
+ H3_MEMORY(free)(bboxes);
932
+ H3_MEMORY(free)(search);
933
+ H3_MEMORY(free)(found);
934
+ return 0;
710
935
  }
711
936
 
712
937
  /**