h3 3.5.0 → 3.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/CHANGELOG.md +45 -0
- data/Gemfile.lock +9 -7
- data/README.md +8 -8
- data/ext/h3/src/.github/workflows/test-linux.yml +118 -0
- data/ext/h3/src/.github/workflows/test-macos.yml +42 -0
- data/ext/h3/src/.github/workflows/test-website.yml +32 -0
- data/ext/h3/src/.github/workflows/test-windows.yml +44 -0
- data/ext/h3/src/.gitignore +5 -0
- data/ext/h3/src/.travis.yml +21 -32
- data/ext/h3/src/CHANGELOG.md +60 -0
- data/ext/h3/src/CMakeLists.txt +150 -33
- data/ext/h3/src/CONTRIBUTING.md +1 -1
- data/ext/h3/src/README.md +65 -16
- data/ext/h3/src/RELEASE.md +3 -1
- data/ext/h3/src/VERSION +1 -1
- data/ext/h3/src/dev-docs/RFCs/rfc-template.md +21 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/error-handling-rfc.md +21 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/names_for_concepts_types_functions.md +276 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/overrideable-allocators-rfc.md +141 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/polyfill-modes-rfc.md +21 -0
- data/ext/h3/src/dev-docs/RFCs/v4.0.0/vertex-mode-rfc.md +50 -0
- data/ext/h3/src/dev-docs/build_windows.md +6 -1
- data/ext/h3/src/dev-docs/creating_bindings.md +3 -3
- data/ext/h3/src/dev-docs/custom_alloc.md +27 -0
- data/ext/h3/src/docs/{overview/mainpage.md → README.md} +2 -3
- data/ext/h3/src/docs/api/hierarchy.md +8 -0
- data/ext/h3/src/docs/api/misc.md +94 -0
- data/ext/h3/src/docs/community/applications.md +1 -0
- data/ext/h3/src/docs/community/bindings.md +10 -0
- data/ext/h3/src/docs/community/tutorials.md +8 -3
- data/ext/h3/src/docs/core-library/coordsystems.md +5 -4
- data/ext/h3/src/docs/core-library/filters.md +8 -9
- data/ext/h3/src/docs/core-library/geoToH3desc.md +2 -3
- data/ext/h3/src/docs/core-library/h3ToGeoBoundaryDesc.md +4 -5
- data/ext/h3/src/docs/core-library/h3ToGeoDesc.md +3 -4
- data/ext/h3/src/docs/core-library/h3indexing.md +26 -17
- data/ext/h3/src/docs/core-library/overview.md +2 -3
- data/ext/h3/src/docs/core-library/restable.md +1 -2
- data/ext/h3/src/docs/core-library/usage.md +1 -2
- data/ext/h3/src/docs/table-of-contents.json +47 -0
- data/ext/h3/src/docs/{overview/usecases.md → usecases.md} +6 -11
- data/ext/h3/src/scripts/binding_functions.sh +1 -1
- data/ext/h3/src/scripts/coverage.sh.in +8 -4
- data/ext/h3/src/scripts/update_version.sh +2 -2
- data/ext/h3/src/src/apps/applib/include/args.h +1 -0
- data/ext/h3/src/src/apps/applib/include/test.h +1 -0
- data/ext/h3/src/src/apps/applib/include/utility.h +7 -1
- data/ext/h3/src/src/apps/applib/lib/args.c +2 -0
- data/ext/h3/src/src/apps/applib/lib/kml.c +2 -0
- data/ext/h3/src/src/apps/applib/lib/test.c +1 -0
- data/ext/h3/src/src/apps/applib/lib/utility.c +133 -2
- data/ext/h3/src/src/apps/benchmarks/benchmarkH3Api.c +1 -1
- data/ext/h3/src/{website/html.config.js → src/apps/benchmarks/benchmarkH3UniEdge.c} +15 -12
- data/ext/h3/src/src/apps/filters/h3ToComponents.c +1 -0
- data/ext/h3/src/src/apps/filters/h3ToGeo.c +1 -0
- data/ext/h3/src/src/apps/filters/h3ToGeoBoundary.c +1 -0
- data/ext/h3/src/src/apps/filters/h3ToLocalIj.c +1 -0
- data/ext/h3/src/src/apps/filters/hexRange.c +1 -0
- data/ext/h3/src/src/apps/filters/kRing.c +1 -0
- data/ext/h3/src/src/apps/filters/localIjToH3.c +1 -0
- data/ext/h3/src/src/apps/miscapps/generateBaseCellNeighbors.c +2 -2
- data/ext/h3/src/src/apps/miscapps/generateFaceCenterPoint.c +1 -0
- data/ext/h3/src/src/apps/miscapps/generateNumHexagons.c +1 -2
- data/ext/h3/src/src/apps/miscapps/generatePentagonDirectionFaces.c +67 -0
- data/ext/h3/src/src/apps/miscapps/h3ToGeoBoundaryHier.c +1 -0
- data/ext/h3/src/src/apps/miscapps/h3ToGeoHier.c +1 -0
- data/ext/h3/src/src/apps/miscapps/h3ToHier.c +1 -0
- data/ext/h3/src/src/apps/testapps/mkRandGeo.c +1 -0
- data/ext/h3/src/src/apps/testapps/mkRandGeoBoundary.c +1 -0
- data/ext/h3/src/src/apps/testapps/testBBox.c +1 -0
- data/ext/h3/src/src/apps/testapps/testBaseCells.c +15 -1
- data/ext/h3/src/src/apps/testapps/testCompact.c +121 -2
- data/ext/h3/src/src/apps/testapps/testCoordIj.c +1 -0
- data/ext/h3/src/src/apps/testapps/testGeoCoord.c +47 -8
- data/ext/h3/src/src/apps/testapps/testGeoToH3.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3Api.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3CellArea.c +47 -0
- data/ext/h3/src/src/apps/testapps/testH3CellAreaExhaustive.c +180 -0
- data/ext/h3/src/src/apps/testapps/testH3Distance.c +2 -50
- data/ext/h3/src/src/apps/testapps/testH3DistanceExhaustive.c +84 -0
- data/ext/h3/src/src/apps/testapps/testH3GetFaces.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3Index.c +33 -3
- data/ext/h3/src/src/apps/testapps/testH3Line.c +2 -84
- data/ext/h3/src/src/apps/testapps/testH3LineExhaustive.c +115 -0
- data/ext/h3/src/src/apps/testapps/testH3Memory.c +175 -0
- data/ext/h3/src/src/apps/testapps/testH3NeighborRotations.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3SetToLinkedGeo.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3SetToVertexGraph.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToCenterChild.c +68 -0
- data/ext/h3/src/src/apps/testapps/testH3ToChildren.c +15 -2
- data/ext/h3/src/src/apps/testapps/testH3ToGeo.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToGeoBoundary.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3ToLocalIj.c +24 -236
- data/ext/h3/src/src/apps/testapps/testH3ToLocalIjExhaustive.c +265 -0
- data/ext/h3/src/src/apps/testapps/testH3ToParent.c +1 -0
- data/ext/h3/src/src/apps/testapps/testH3UniEdge.c +45 -16
- data/ext/h3/src/src/apps/testapps/testH3UniEdgeExhaustive.c +111 -0
- data/ext/h3/src/src/apps/testapps/testHexRanges.c +1 -0
- data/ext/h3/src/src/apps/testapps/testHexRing.c +1 -0
- data/ext/h3/src/src/apps/testapps/testKRing.c +1 -0
- data/ext/h3/src/src/apps/testapps/testLinkedGeo.c +1 -0
- data/ext/h3/src/src/apps/testapps/testMaxH3ToChildrenSize.c +1 -0
- data/ext/h3/src/src/apps/testapps/testPentagonIndexes.c +58 -0
- data/ext/h3/src/src/apps/testapps/testPolyfill.c +72 -9
- data/ext/h3/src/src/apps/testapps/testPolyfillReported.c +157 -0
- data/ext/h3/src/src/apps/testapps/testPolygon.c +27 -1
- data/ext/h3/src/src/apps/testapps/testVec2d.c +1 -0
- data/ext/h3/src/src/apps/testapps/testVec3d.c +1 -0
- data/ext/h3/src/src/apps/testapps/testVertex.c +66 -0
- data/ext/h3/src/src/apps/testapps/testVertexGraph.c +1 -0
- data/ext/h3/src/src/h3lib/include/algos.h +8 -0
- data/ext/h3/src/src/h3lib/include/alloc.h +40 -0
- data/ext/h3/src/src/h3lib/include/baseCells.h +4 -0
- data/ext/h3/src/src/h3lib/include/bbox.h +4 -1
- data/ext/h3/src/src/h3lib/include/constants.h +2 -0
- data/ext/h3/src/src/h3lib/include/faceijk.h +3 -2
- data/ext/h3/src/src/h3lib/include/geoCoord.h +2 -3
- data/ext/h3/src/src/h3lib/include/h3Index.h +37 -4
- data/ext/h3/src/src/h3lib/include/h3api.h.in +85 -17
- data/ext/h3/src/src/h3lib/include/linkedGeo.h +1 -0
- data/ext/h3/src/src/h3lib/include/polygon.h +1 -0
- data/ext/h3/src/src/h3lib/include/polygonAlgos.h +1 -0
- data/ext/h3/src/src/h3lib/include/vertex.h +44 -0
- data/ext/h3/src/src/h3lib/include/vertexGraph.h +1 -0
- data/ext/h3/src/src/h3lib/lib/algos.c +305 -80
- data/ext/h3/src/src/h3lib/lib/baseCells.c +26 -4
- data/ext/h3/src/src/h3lib/lib/bbox.c +56 -27
- data/ext/h3/src/src/h3lib/lib/coordijk.c +2 -0
- data/ext/h3/src/src/h3lib/lib/faceijk.c +35 -24
- data/ext/h3/src/src/h3lib/lib/geoCoord.c +162 -44
- data/ext/h3/src/src/h3lib/lib/h3Index.c +150 -46
- data/ext/h3/src/src/h3lib/lib/h3UniEdge.c +42 -57
- data/ext/h3/src/src/h3lib/lib/linkedGeo.c +20 -15
- data/ext/h3/src/src/h3lib/lib/localij.c +5 -5
- data/ext/h3/src/src/h3lib/lib/polygon.c +3 -2
- data/ext/h3/src/src/h3lib/lib/vec2d.c +1 -0
- data/ext/h3/src/src/h3lib/lib/vec3d.c +1 -0
- data/ext/h3/src/src/h3lib/lib/vertex.c +134 -0
- data/ext/h3/src/src/h3lib/lib/vertexGraph.c +8 -5
- data/ext/h3/src/website/.eslintignore +2 -0
- data/ext/h3/src/website/.gitignore +57 -0
- data/ext/h3/src/website/.nvmrc +1 -0
- data/ext/h3/src/website/README.md +8 -6
- data/ext/h3/src/website/gatsby-config.js +83 -0
- data/ext/h3/src/website/package.json +20 -12
- data/ext/h3/src/website/scripts/build-to-gh-pages.sh +7 -5
- data/ext/h3/src/website/src/.gitkeep +0 -0
- data/ext/h3/src/website/templates/documentation.jsx +129 -0
- data/ext/h3/src/website/yarn.lock +13723 -0
- data/h3.gemspec +1 -0
- data/lib/h3.rb +8 -23
- data/lib/h3/bindings/base.rb +15 -4
- data/lib/h3/bindings/private.rb +13 -9
- data/lib/h3/geo_json.rb +1 -1
- data/lib/h3/hierarchy.rb +24 -9
- data/lib/h3/indexing.rb +7 -7
- data/lib/h3/inspection.rb +22 -26
- data/lib/h3/miscellaneous.rb +157 -9
- data/lib/h3/regions.rb +3 -0
- data/lib/h3/traversal.rb +9 -9
- data/lib/h3/unidirectional_edges.rb +18 -18
- data/lib/h3/version.rb +1 -1
- data/spec/geo_json_spec.rb +8 -0
- data/spec/hierarchy_spec.rb +23 -13
- data/spec/indexing_spec.rb +15 -15
- data/spec/inspection_spec.rb +17 -17
- data/spec/miscellaneous_spec.rb +151 -6
- data/spec/{region_spec.rb → regions_spec.rb} +1 -1
- data/spec/traversal_spec.rb +6 -6
- data/spec/unidirectional_edges_spec.rb +18 -18
- metadata +55 -15
- data/ext/h3/src/.ycm_extra_conf.py +0 -92
- data/ext/h3/src/appveyor.yml +0 -50
- data/ext/h3/src/website/src/config.js +0 -46
- data/ext/h3/src/website/src/mdRoutes.js +0 -151
- data/ext/h3/src/website/src/styles/_variables.scss +0 -16
- data/ext/h3/src/website/src/styles/index.scss +0 -3
- data/ext/h3/src/website/static/index.html +0 -15
- data/lib/h3/bindings.rb +0 -12
@@ -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
|
39
|
-
*
|
40
|
-
*
|
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
|
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 =
|
51
|
-
// If failed, h will be unmodified and we should return
|
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
|
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
|
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
|
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++) {
|
@@ -145,6 +157,22 @@ H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes) {
|
|
145
157
|
return parentH;
|
146
158
|
}
|
147
159
|
|
160
|
+
/**
|
161
|
+
* Determines whether one resolution is a valid child resolution of another.
|
162
|
+
* Each resolution is considered a valid child resolution of itself.
|
163
|
+
*
|
164
|
+
* @param parentRes int resolution of the parent
|
165
|
+
* @param childRes int resolution of the child
|
166
|
+
*
|
167
|
+
* @return The validity of the child resolution
|
168
|
+
*/
|
169
|
+
static bool _isValidChildRes(int parentRes, int childRes) {
|
170
|
+
if (childRes < parentRes || childRes > MAX_H3_RES) {
|
171
|
+
return false;
|
172
|
+
}
|
173
|
+
return true;
|
174
|
+
}
|
175
|
+
|
148
176
|
/**
|
149
177
|
* maxH3ToChildrenSize returns the maximum number of children possible for a
|
150
178
|
* given child level.
|
@@ -157,7 +185,7 @@ H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes) {
|
|
157
185
|
*/
|
158
186
|
int H3_EXPORT(maxH3ToChildrenSize)(H3Index h, int childRes) {
|
159
187
|
int parentRes = H3_GET_RESOLUTION(h);
|
160
|
-
if (parentRes
|
188
|
+
if (!_isValidChildRes(parentRes, childRes)) {
|
161
189
|
return 0;
|
162
190
|
}
|
163
191
|
return _ipow(7, (childRes - parentRes));
|
@@ -191,7 +219,7 @@ H3Index makeDirectChild(H3Index h, int cellNumber) {
|
|
191
219
|
*/
|
192
220
|
void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
|
193
221
|
int parentRes = H3_GET_RESOLUTION(h);
|
194
|
-
if (parentRes
|
222
|
+
if (!_isValidChildRes(parentRes, childRes)) {
|
195
223
|
return;
|
196
224
|
} else if (parentRes == childRes) {
|
197
225
|
*children = h;
|
@@ -204,7 +232,7 @@ void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
|
|
204
232
|
if (isAPentagon && i == K_AXES_DIGIT) {
|
205
233
|
H3Index* nextChild = children + bufferChildStep;
|
206
234
|
while (children < nextChild) {
|
207
|
-
*children =
|
235
|
+
*children = H3_NULL;
|
208
236
|
children++;
|
209
237
|
}
|
210
238
|
} else {
|
@@ -214,6 +242,30 @@ void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
|
|
214
242
|
}
|
215
243
|
}
|
216
244
|
|
245
|
+
/**
|
246
|
+
* h3ToCenterChild produces the center child index for a given H3 index at
|
247
|
+
* the specified resolution
|
248
|
+
*
|
249
|
+
* @param h H3Index to find center child of
|
250
|
+
* @param childRes The resolution to switch to
|
251
|
+
*
|
252
|
+
* @return H3Index of the center child, or H3_NULL if you actually asked for a
|
253
|
+
* parent
|
254
|
+
*/
|
255
|
+
H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
|
256
|
+
int parentRes = H3_GET_RESOLUTION(h);
|
257
|
+
if (!_isValidChildRes(parentRes, childRes)) {
|
258
|
+
return H3_NULL;
|
259
|
+
} else if (childRes == parentRes) {
|
260
|
+
return h;
|
261
|
+
}
|
262
|
+
H3Index child = H3_SET_RESOLUTION(h, childRes);
|
263
|
+
for (int i = parentRes + 1; i <= childRes; i++) {
|
264
|
+
H3_SET_INDEX_DIGIT(child, i, 0);
|
265
|
+
}
|
266
|
+
return child;
|
267
|
+
}
|
268
|
+
|
217
269
|
/**
|
218
270
|
* compact takes a set of hexagons all at the same resolution and compresses
|
219
271
|
* them by pruning full child branches to the parent level. This is also done
|
@@ -227,17 +279,27 @@ void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
|
|
227
279
|
*/
|
228
280
|
int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
229
281
|
const int numHexes) {
|
282
|
+
if (numHexes == 0) {
|
283
|
+
return COMPACT_SUCCESS;
|
284
|
+
}
|
230
285
|
int res = H3_GET_RESOLUTION(h3Set[0]);
|
231
286
|
if (res == 0) {
|
232
287
|
// No compaction possible, just copy the set to output
|
233
288
|
for (int i = 0; i < numHexes; i++) {
|
234
289
|
compactedSet[i] = h3Set[i];
|
235
290
|
}
|
236
|
-
return
|
291
|
+
return COMPACT_SUCCESS;
|
292
|
+
}
|
293
|
+
H3Index* remainingHexes = H3_MEMORY(malloc)(numHexes * sizeof(H3Index));
|
294
|
+
if (!remainingHexes) {
|
295
|
+
return COMPACT_ALLOC_FAILED;
|
237
296
|
}
|
238
|
-
H3Index* remainingHexes = malloc(numHexes * sizeof(H3Index));
|
239
297
|
memcpy(remainingHexes, h3Set, numHexes * sizeof(H3Index));
|
240
|
-
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
|
+
}
|
241
303
|
H3Index* compactedSetOffset = compactedSet;
|
242
304
|
int numRemainingHexes = numHexes;
|
243
305
|
while (numRemainingHexes) {
|
@@ -254,28 +316,36 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
|
254
316
|
int loc = (int)(parent % numRemainingHexes);
|
255
317
|
int loopCount = 0;
|
256
318
|
while (hashSetArray[loc] != 0) {
|
257
|
-
if (loopCount > numRemainingHexes) {
|
319
|
+
if (loopCount > numRemainingHexes) { // LCOV_EXCL_BR_LINE
|
258
320
|
// LCOV_EXCL_START
|
259
321
|
// This case should not be possible because at most one
|
260
322
|
// index is placed into hashSetArray per
|
261
323
|
// numRemainingHexes.
|
262
|
-
free(remainingHexes);
|
263
|
-
free(hashSetArray);
|
264
|
-
return
|
324
|
+
H3_MEMORY(free)(remainingHexes);
|
325
|
+
H3_MEMORY(free)(hashSetArray);
|
326
|
+
return COMPACT_LOOP_EXCEEDED;
|
265
327
|
// LCOV_EXCL_STOP
|
266
328
|
}
|
267
329
|
H3Index tempIndex =
|
268
330
|
hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
|
269
331
|
if (tempIndex == parent) {
|
270
332
|
int count = H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
|
271
|
-
|
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) {
|
272
342
|
// Only possible on duplicate input
|
273
|
-
free(remainingHexes);
|
274
|
-
free(hashSetArray);
|
275
|
-
return
|
343
|
+
H3_MEMORY(free)(remainingHexes);
|
344
|
+
H3_MEMORY(free)(hashSetArray);
|
345
|
+
return COMPACT_DUPLICATE;
|
276
346
|
}
|
277
347
|
H3_SET_RESERVED_BITS(parent, count);
|
278
|
-
hashSetArray[loc] =
|
348
|
+
hashSetArray[loc] = H3_NULL;
|
279
349
|
} else {
|
280
350
|
loc = (loc + 1) % numRemainingHexes;
|
281
351
|
}
|
@@ -295,7 +365,12 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
|
295
365
|
break;
|
296
366
|
}
|
297
367
|
H3Index* compactableHexes =
|
298
|
-
|
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
|
+
}
|
299
374
|
for (int i = 0; i < numRemainingHexes; i++) {
|
300
375
|
if (hashSetArray[i] == 0) continue;
|
301
376
|
int count = H3_GET_RESERVED_BITS(hashSetArray[i]) + 1;
|
@@ -321,7 +396,7 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
|
321
396
|
int uncompactableCount = 0;
|
322
397
|
for (int i = 0; i < numRemainingHexes; i++) {
|
323
398
|
H3Index currIndex = remainingHexes[i];
|
324
|
-
if (currIndex !=
|
399
|
+
if (currIndex != H3_NULL) {
|
325
400
|
H3Index parent = H3_EXPORT(h3ToParent)(currIndex, parentRes);
|
326
401
|
// Modulus hash the parent into the temp array
|
327
402
|
// to determine if this index was included in
|
@@ -330,14 +405,14 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
|
330
405
|
int loopCount = 0;
|
331
406
|
bool isUncompactable = true;
|
332
407
|
do {
|
333
|
-
if (loopCount > numRemainingHexes) {
|
408
|
+
if (loopCount > numRemainingHexes) { // LCOV_EXCL_BR_LINE
|
334
409
|
// LCOV_EXCL_START
|
335
410
|
// This case should not be possible because at most one
|
336
411
|
// index is placed into hashSetArray per input hexagon.
|
337
|
-
free(compactableHexes);
|
338
|
-
free(remainingHexes);
|
339
|
-
free(hashSetArray);
|
340
|
-
return
|
412
|
+
H3_MEMORY(free)(compactableHexes);
|
413
|
+
H3_MEMORY(free)(remainingHexes);
|
414
|
+
H3_MEMORY(free)(hashSetArray);
|
415
|
+
return COMPACT_LOOP_EXCEEDED;
|
341
416
|
// LCOV_EXCL_STOP
|
342
417
|
}
|
343
418
|
H3Index tempIndex =
|
@@ -365,11 +440,11 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
|
365
440
|
memcpy(remainingHexes, compactableHexes,
|
366
441
|
compactableCount * sizeof(H3Index));
|
367
442
|
numRemainingHexes = compactableCount;
|
368
|
-
free(compactableHexes);
|
443
|
+
H3_MEMORY(free)(compactableHexes);
|
369
444
|
}
|
370
|
-
free(remainingHexes);
|
371
|
-
free(hashSetArray);
|
372
|
-
return
|
445
|
+
H3_MEMORY(free)(remainingHexes);
|
446
|
+
H3_MEMORY(free)(hashSetArray);
|
447
|
+
return COMPACT_SUCCESS;
|
373
448
|
}
|
374
449
|
|
375
450
|
/**
|
@@ -393,7 +468,7 @@ int H3_EXPORT(uncompact)(const H3Index* compactedSet, const int numHexes,
|
|
393
468
|
return -1;
|
394
469
|
}
|
395
470
|
int currentRes = H3_GET_RESOLUTION(compactedSet[i]);
|
396
|
-
if (currentRes
|
471
|
+
if (!_isValidChildRes(currentRes, res)) {
|
397
472
|
// Nonsensical. Abort.
|
398
473
|
return -2;
|
399
474
|
}
|
@@ -431,7 +506,7 @@ int H3_EXPORT(maxUncompactSize)(const H3Index* compactedSet, const int numHexes,
|
|
431
506
|
for (int i = 0; i < numHexes; i++) {
|
432
507
|
if (compactedSet[i] == 0) continue;
|
433
508
|
int currentRes = H3_GET_RESOLUTION(compactedSet[i]);
|
434
|
-
if (currentRes
|
509
|
+
if (!_isValidChildRes(currentRes, res)) {
|
435
510
|
// Nonsensical. Abort.
|
436
511
|
return -1;
|
437
512
|
}
|
@@ -561,7 +636,7 @@ H3Index _h3Rotate60cw(H3Index h) {
|
|
561
636
|
* Convert an FaceIJK address to the corresponding H3Index.
|
562
637
|
* @param fijk The FaceIJK address.
|
563
638
|
* @param res The cell resolution.
|
564
|
-
* @return The encoded H3Index (or
|
639
|
+
* @return The encoded H3Index (or H3_NULL on failure).
|
565
640
|
*/
|
566
641
|
H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
|
567
642
|
// initialize the index
|
@@ -574,7 +649,7 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
|
|
574
649
|
if (fijk->coord.i > MAX_FACE_COORD || fijk->coord.j > MAX_FACE_COORD ||
|
575
650
|
fijk->coord.k > MAX_FACE_COORD) {
|
576
651
|
// out of range input
|
577
|
-
return
|
652
|
+
return H3_NULL;
|
578
653
|
}
|
579
654
|
|
580
655
|
H3_SET_BASE_CELL(h, _faceIjkToBaseCell(fijk));
|
@@ -618,7 +693,7 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
|
|
618
693
|
if (fijkBC.coord.i > MAX_FACE_COORD || fijkBC.coord.j > MAX_FACE_COORD ||
|
619
694
|
fijkBC.coord.k > MAX_FACE_COORD) {
|
620
695
|
// out of range input
|
621
|
-
return
|
696
|
+
return H3_NULL;
|
622
697
|
}
|
623
698
|
|
624
699
|
// lookup the correct base cell
|
@@ -657,14 +732,14 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
|
|
657
732
|
*
|
658
733
|
* @param g The spherical coordinates to encode.
|
659
734
|
* @param res The desired H3 resolution for the encoding.
|
660
|
-
* @return The encoded H3Index (or
|
735
|
+
* @return The encoded H3Index (or H3_NULL on failure).
|
661
736
|
*/
|
662
737
|
H3Index H3_EXPORT(geoToH3)(const GeoCoord* g, int res) {
|
663
738
|
if (res < 0 || res > MAX_H3_RES) {
|
664
|
-
return
|
739
|
+
return H3_NULL;
|
665
740
|
}
|
666
741
|
if (!isfinite(g->lat) || !isfinite(g->lon)) {
|
667
|
-
return
|
742
|
+
return H3_NULL;
|
668
743
|
}
|
669
744
|
|
670
745
|
FaceIJK fijk;
|
@@ -774,8 +849,13 @@ void H3_EXPORT(h3ToGeo)(H3Index h3, GeoCoord* g) {
|
|
774
849
|
void H3_EXPORT(h3ToGeoBoundary)(H3Index h3, GeoBoundary* gb) {
|
775
850
|
FaceIJK fijk;
|
776
851
|
_h3ToFaceIjk(h3, &fijk);
|
777
|
-
|
778
|
-
|
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
|
+
}
|
779
859
|
}
|
780
860
|
|
781
861
|
/**
|
@@ -860,6 +940,30 @@ void H3_EXPORT(h3GetFaces)(H3Index h3, int* out) {
|
|
860
940
|
}
|
861
941
|
}
|
862
942
|
|
943
|
+
/**
|
944
|
+
* pentagonIndexCount returns the number of pentagons (same at any resolution)
|
945
|
+
*
|
946
|
+
* @return int count of pentagon indexes
|
947
|
+
*/
|
948
|
+
int H3_EXPORT(pentagonIndexCount)() { return NUM_PENTAGONS; }
|
949
|
+
|
950
|
+
/**
|
951
|
+
* Generates all pentagons at the specified resolution
|
952
|
+
*
|
953
|
+
* @param res The resolution to produce pentagons at.
|
954
|
+
* @param out Output array. Must be of size pentagonIndexCount().
|
955
|
+
*/
|
956
|
+
void H3_EXPORT(getPentagonIndexes)(int res, H3Index* out) {
|
957
|
+
int i = 0;
|
958
|
+
for (int bc = 0; bc < NUM_BASE_CELLS; bc++) {
|
959
|
+
if (_isBaseCellPentagon(bc)) {
|
960
|
+
H3Index pentagon;
|
961
|
+
setH3Index(&pentagon, res, bc, 0);
|
962
|
+
out[i++] = pentagon;
|
963
|
+
}
|
964
|
+
}
|
965
|
+
}
|
966
|
+
|
863
967
|
/**
|
864
968
|
* Returns whether or not a resolution is a Class III grid. Note that odd
|
865
969
|
* resolutions are Class III and even resolutions are Class II.
|
@@ -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
|
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
|
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
|
-
|
117
|
-
|
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
|
127
|
-
return
|
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
|
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
|
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] =
|
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
|
-
//
|
246
|
-
|
247
|
-
|
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
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
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
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
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
|
}
|