h3 3.5.1 → 3.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +3 -3
- data/ext/h3/src/.travis.yml +15 -4
- data/ext/h3/src/CHANGELOG.md +7 -0
- data/ext/h3/src/CMakeLists.txt +15 -0
- data/ext/h3/src/README.md +5 -6
- data/ext/h3/src/VERSION +1 -1
- data/ext/h3/src/docs/api/hierarchy.md +8 -0
- data/ext/h3/src/docs/api/misc.md +18 -0
- data/ext/h3/src/scripts/coverage.sh.in +7 -3
- data/ext/h3/src/src/apps/miscapps/generateBaseCellNeighbors.c +2 -2
- data/ext/h3/src/src/apps/miscapps/generateNumHexagons.c +0 -2
- data/ext/h3/src/src/apps/testapps/testCompact.c +12 -0
- data/ext/h3/src/src/apps/testapps/testH3Distance.c +1 -50
- data/ext/h3/src/src/apps/testapps/testH3DistanceExhaustive.c +83 -0
- data/ext/h3/src/src/apps/testapps/testH3Line.c +1 -84
- data/ext/h3/src/src/apps/testapps/testH3LineExhaustive.c +114 -0
- data/ext/h3/src/src/apps/testapps/testH3ToCenterChild.c +67 -0
- data/ext/h3/src/src/apps/testapps/testH3ToChildren.c +14 -2
- data/ext/h3/src/src/apps/testapps/testH3ToLocalIj.c +12 -230
- data/ext/h3/src/src/apps/testapps/testH3ToLocalIjExhaustive.c +264 -0
- data/ext/h3/src/src/apps/testapps/testPentagonIndexes.c +57 -0
- data/ext/h3/src/src/h3lib/include/constants.h +2 -0
- data/ext/h3/src/src/h3lib/include/h3api.h.in +20 -0
- data/ext/h3/src/src/h3lib/lib/algos.c +5 -5
- data/ext/h3/src/src/h3lib/lib/faceijk.c +3 -3
- data/ext/h3/src/src/h3lib/lib/h3Index.c +69 -6
- data/ext/h3/src/src/h3lib/lib/localij.c +4 -4
- data/ext/h3/src/src/h3lib/lib/polygon.c +1 -2
- data/h3.gemspec +1 -1
- data/lib/h3/bindings/private.rb +1 -0
- data/lib/h3/hierarchy.rb +15 -0
- data/lib/h3/miscellaneous.rb +25 -0
- data/lib/h3/version.rb +1 -1
- data/spec/hierarchy_spec.rb +10 -0
- data/spec/miscellaneous_spec.rb +28 -0
- metadata +9 -4
@@ -0,0 +1,264 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2019 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
|
17
|
+
* @brief tests H3 index to local IJ and IJK+ grid functions using
|
18
|
+
* tests over a large number of indexes.
|
19
|
+
*
|
20
|
+
* usage: `testH3ToLocalIjExhaustive`
|
21
|
+
*/
|
22
|
+
|
23
|
+
#include <h3api.h>
|
24
|
+
#include <stdio.h>
|
25
|
+
#include <stdlib.h>
|
26
|
+
#include <string.h>
|
27
|
+
#include "algos.h"
|
28
|
+
#include "baseCells.h"
|
29
|
+
#include "constants.h"
|
30
|
+
#include "h3Index.h"
|
31
|
+
#include "h3api.h"
|
32
|
+
#include "localij.h"
|
33
|
+
#include "test.h"
|
34
|
+
#include "utility.h"
|
35
|
+
|
36
|
+
static const int MAX_DISTANCES[] = {1, 2, 5, 12, 19, 26};
|
37
|
+
|
38
|
+
// The same traversal constants from algos.c (for hexRange) here reused as local
|
39
|
+
// IJ vectors.
|
40
|
+
static const CoordIJ DIRECTIONS[6] = {{0, 1}, {-1, 0}, {-1, -1},
|
41
|
+
{0, -1}, {1, 0}, {1, 1}};
|
42
|
+
|
43
|
+
static const CoordIJ NEXT_RING_DIRECTION = {1, 0};
|
44
|
+
|
45
|
+
/**
|
46
|
+
* Test that the local coordinates for an index map to itself.
|
47
|
+
*/
|
48
|
+
void localIjToH3_identity_assertions(H3Index h3) {
|
49
|
+
CoordIJ ij;
|
50
|
+
t_assert(H3_EXPORT(experimentalH3ToLocalIj)(h3, h3, &ij) == 0,
|
51
|
+
"able to setup localIjToH3 test");
|
52
|
+
|
53
|
+
H3Index retrieved;
|
54
|
+
t_assert(H3_EXPORT(experimentalLocalIjToH3)(h3, &ij, &retrieved) == 0,
|
55
|
+
"got an index back from localIjTOh3");
|
56
|
+
t_assert(h3 == retrieved, "round trip through local IJ space works");
|
57
|
+
}
|
58
|
+
|
59
|
+
/**
|
60
|
+
* Test that coordinates for an index match some simple rules about index
|
61
|
+
* digits, when using the index as its own origin. That is, that the IJ
|
62
|
+
* coordinates are in the coordinate space of the origin's base cell.
|
63
|
+
*/
|
64
|
+
void h3ToLocalIj_coordinates_assertions(H3Index h3) {
|
65
|
+
int r = H3_GET_RESOLUTION(h3);
|
66
|
+
|
67
|
+
CoordIJ ij;
|
68
|
+
t_assert(H3_EXPORT(experimentalH3ToLocalIj)(h3, h3, &ij) == 0,
|
69
|
+
"get ij for origin");
|
70
|
+
CoordIJK ijk;
|
71
|
+
ijToIjk(&ij, &ijk);
|
72
|
+
if (r == 0) {
|
73
|
+
t_assert(_ijkMatches(&ijk, &UNIT_VECS[0]) == 1, "res 0 cell at 0,0,0");
|
74
|
+
} else if (r == 1) {
|
75
|
+
t_assert(_ijkMatches(&ijk, &UNIT_VECS[H3_GET_INDEX_DIGIT(h3, 1)]) == 1,
|
76
|
+
"res 1 cell at expected coordinates");
|
77
|
+
} else if (r == 2) {
|
78
|
+
CoordIJK expected = UNIT_VECS[H3_GET_INDEX_DIGIT(h3, 1)];
|
79
|
+
_downAp7r(&expected);
|
80
|
+
_neighbor(&expected, H3_GET_INDEX_DIGIT(h3, 2));
|
81
|
+
t_assert(_ijkMatches(&ijk, &expected) == 1,
|
82
|
+
"res 2 cell at expected coordinates");
|
83
|
+
} else {
|
84
|
+
t_assert(0, "resolution supported by test function (coordinates)");
|
85
|
+
}
|
86
|
+
}
|
87
|
+
|
88
|
+
/**
|
89
|
+
* Test the the immediate neighbors of an index are at the expected locations in
|
90
|
+
* the local IJ coordinate space.
|
91
|
+
*/
|
92
|
+
void h3ToLocalIj_neighbors_assertions(H3Index h3) {
|
93
|
+
CoordIJ origin = {0};
|
94
|
+
t_assert(H3_EXPORT(experimentalH3ToLocalIj)(h3, h3, &origin) == 0,
|
95
|
+
"got ij for origin");
|
96
|
+
CoordIJK originIjk;
|
97
|
+
ijToIjk(&origin, &originIjk);
|
98
|
+
|
99
|
+
for (Direction d = K_AXES_DIGIT; d < INVALID_DIGIT; d++) {
|
100
|
+
if (d == K_AXES_DIGIT && H3_EXPORT(h3IsPentagon)(h3)) {
|
101
|
+
continue;
|
102
|
+
}
|
103
|
+
|
104
|
+
int rotations = 0;
|
105
|
+
H3Index offset = h3NeighborRotations(h3, d, &rotations);
|
106
|
+
|
107
|
+
CoordIJ ij = {0};
|
108
|
+
t_assert(H3_EXPORT(experimentalH3ToLocalIj)(h3, offset, &ij) == 0,
|
109
|
+
"got ij for destination");
|
110
|
+
CoordIJK ijk;
|
111
|
+
ijToIjk(&ij, &ijk);
|
112
|
+
CoordIJK invertedIjk = {0};
|
113
|
+
_neighbor(&invertedIjk, d);
|
114
|
+
for (int i = 0; i < 3; i++) {
|
115
|
+
_ijkRotate60ccw(&invertedIjk);
|
116
|
+
}
|
117
|
+
_ijkAdd(&invertedIjk, &ijk, &ijk);
|
118
|
+
_ijkNormalize(&ijk);
|
119
|
+
|
120
|
+
t_assert(_ijkMatches(&ijk, &originIjk), "back to origin");
|
121
|
+
}
|
122
|
+
}
|
123
|
+
|
124
|
+
/**
|
125
|
+
* Test that the neighbors (k-ring), if they can be found in the local IJ
|
126
|
+
* coordinate space, can be converted back to indexes.
|
127
|
+
*/
|
128
|
+
void localIjToH3_kRing_assertions(H3Index h3) {
|
129
|
+
int r = H3_GET_RESOLUTION(h3);
|
130
|
+
t_assert(r <= 5, "resolution supported by test function (kRing)");
|
131
|
+
int maxK = MAX_DISTANCES[r];
|
132
|
+
|
133
|
+
int sz = H3_EXPORT(maxKringSize)(maxK);
|
134
|
+
H3Index *neighbors = calloc(sz, sizeof(H3Index));
|
135
|
+
int *distances = calloc(sz, sizeof(int));
|
136
|
+
|
137
|
+
H3_EXPORT(kRingDistances)(h3, maxK, neighbors, distances);
|
138
|
+
|
139
|
+
for (int i = 0; i < sz; i++) {
|
140
|
+
if (neighbors[i] == 0) {
|
141
|
+
continue;
|
142
|
+
}
|
143
|
+
|
144
|
+
CoordIJ ij;
|
145
|
+
// Don't consider indexes which we can't unfold in the first place
|
146
|
+
if (H3_EXPORT(experimentalH3ToLocalIj)(h3, neighbors[i], &ij) == 0) {
|
147
|
+
H3Index retrieved;
|
148
|
+
t_assert(
|
149
|
+
H3_EXPORT(experimentalLocalIjToH3)(h3, &ij, &retrieved) == 0,
|
150
|
+
"retrieved index for unfolded coordinates");
|
151
|
+
t_assert(retrieved == neighbors[i],
|
152
|
+
"round trip neighboring index matches expected");
|
153
|
+
}
|
154
|
+
}
|
155
|
+
|
156
|
+
free(distances);
|
157
|
+
free(neighbors);
|
158
|
+
}
|
159
|
+
|
160
|
+
void localIjToH3_traverse_assertions(H3Index h3) {
|
161
|
+
int r = H3_GET_RESOLUTION(h3);
|
162
|
+
t_assert(r <= 5, "resolution supported by test function (traverse)");
|
163
|
+
int k = MAX_DISTANCES[r];
|
164
|
+
|
165
|
+
CoordIJ ij;
|
166
|
+
t_assert(H3_EXPORT(experimentalH3ToLocalIj)(h3, h3, &ij) == 0,
|
167
|
+
"Got origin coordinates");
|
168
|
+
|
169
|
+
// This logic is from hexRangeDistances.
|
170
|
+
// 0 < ring <= k, current ring
|
171
|
+
int ring = 1;
|
172
|
+
// 0 <= direction < 6, current side of the ring
|
173
|
+
int direction = 0;
|
174
|
+
// 0 <= i < ring, current position on the side of the ring
|
175
|
+
int i = 0;
|
176
|
+
|
177
|
+
while (ring <= k) {
|
178
|
+
if (direction == 0 && i == 0) {
|
179
|
+
ij.i += NEXT_RING_DIRECTION.i;
|
180
|
+
ij.j += NEXT_RING_DIRECTION.j;
|
181
|
+
}
|
182
|
+
|
183
|
+
ij.i += DIRECTIONS[direction].i;
|
184
|
+
ij.j += DIRECTIONS[direction].j;
|
185
|
+
|
186
|
+
H3Index testH3;
|
187
|
+
|
188
|
+
int failed = H3_EXPORT(experimentalLocalIjToH3)(h3, &ij, &testH3);
|
189
|
+
if (!failed) {
|
190
|
+
t_assert(H3_EXPORT(h3IsValid)(testH3),
|
191
|
+
"test coordinates result in valid index");
|
192
|
+
|
193
|
+
CoordIJ expectedIj;
|
194
|
+
int reverseFailed =
|
195
|
+
H3_EXPORT(experimentalH3ToLocalIj)(h3, testH3, &expectedIj);
|
196
|
+
// If it doesn't give a coordinate for this origin,index pair that's
|
197
|
+
// OK.
|
198
|
+
if (!reverseFailed) {
|
199
|
+
if (expectedIj.i != ij.i || expectedIj.j != ij.j) {
|
200
|
+
// Multiple coordinates for the same index can happen due to
|
201
|
+
// pentagon distortion. In that case, the other coordinates
|
202
|
+
// should also belong to the same index.
|
203
|
+
H3Index testTestH3;
|
204
|
+
t_assert(H3_EXPORT(experimentalLocalIjToH3)(
|
205
|
+
h3, &expectedIj, &testTestH3) == 0,
|
206
|
+
"converted coordinates again");
|
207
|
+
t_assert(testH3 == testTestH3,
|
208
|
+
"index has normalizable coordinates in "
|
209
|
+
"local IJ");
|
210
|
+
}
|
211
|
+
}
|
212
|
+
}
|
213
|
+
|
214
|
+
i++;
|
215
|
+
// Check if end of this side of the k-ring
|
216
|
+
if (i == ring) {
|
217
|
+
i = 0;
|
218
|
+
direction++;
|
219
|
+
// Check if end of this ring.
|
220
|
+
if (direction == 6) {
|
221
|
+
direction = 0;
|
222
|
+
ring++;
|
223
|
+
}
|
224
|
+
}
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
SUITE(h3ToLocalIj) {
|
229
|
+
TEST(localIjToH3_identity) {
|
230
|
+
iterateAllIndexesAtRes(0, localIjToH3_identity_assertions);
|
231
|
+
iterateAllIndexesAtRes(1, localIjToH3_identity_assertions);
|
232
|
+
iterateAllIndexesAtRes(2, localIjToH3_identity_assertions);
|
233
|
+
}
|
234
|
+
|
235
|
+
TEST(h3ToLocalIj_coordinates) {
|
236
|
+
iterateAllIndexesAtRes(0, h3ToLocalIj_coordinates_assertions);
|
237
|
+
iterateAllIndexesAtRes(1, h3ToLocalIj_coordinates_assertions);
|
238
|
+
iterateAllIndexesAtRes(2, h3ToLocalIj_coordinates_assertions);
|
239
|
+
}
|
240
|
+
|
241
|
+
TEST(h3ToLocalIj_neighbors) {
|
242
|
+
iterateAllIndexesAtRes(0, h3ToLocalIj_neighbors_assertions);
|
243
|
+
iterateAllIndexesAtRes(1, h3ToLocalIj_neighbors_assertions);
|
244
|
+
iterateAllIndexesAtRes(2, h3ToLocalIj_neighbors_assertions);
|
245
|
+
}
|
246
|
+
|
247
|
+
TEST(localIjToH3_kRing) {
|
248
|
+
iterateAllIndexesAtRes(0, localIjToH3_kRing_assertions);
|
249
|
+
iterateAllIndexesAtRes(1, localIjToH3_kRing_assertions);
|
250
|
+
iterateAllIndexesAtRes(2, localIjToH3_kRing_assertions);
|
251
|
+
// Don't iterate all of res 3, to save time
|
252
|
+
iterateAllIndexesAtResPartial(3, localIjToH3_kRing_assertions, 27);
|
253
|
+
// Further resolutions aren't tested to save time.
|
254
|
+
}
|
255
|
+
|
256
|
+
TEST(localIjToH3_traverse) {
|
257
|
+
iterateAllIndexesAtRes(0, localIjToH3_traverse_assertions);
|
258
|
+
iterateAllIndexesAtRes(1, localIjToH3_traverse_assertions);
|
259
|
+
iterateAllIndexesAtRes(2, localIjToH3_traverse_assertions);
|
260
|
+
// Don't iterate all of res 3, to save time
|
261
|
+
iterateAllIndexesAtResPartial(3, localIjToH3_traverse_assertions, 27);
|
262
|
+
// Further resolutions aren't tested to save time.
|
263
|
+
}
|
264
|
+
}
|
@@ -0,0 +1,57 @@
|
|
1
|
+
/*
|
2
|
+
* Copyright 2019 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
|
+
|
17
|
+
#include <stdlib.h>
|
18
|
+
#include "h3api.h"
|
19
|
+
#include "test.h"
|
20
|
+
|
21
|
+
#define PADDED_COUNT 16
|
22
|
+
|
23
|
+
SUITE(getPentagonIndexes) {
|
24
|
+
TEST(propertyTests) {
|
25
|
+
int expectedCount = H3_EXPORT(pentagonIndexCount)();
|
26
|
+
|
27
|
+
for (int res = 0; res <= 15; res++) {
|
28
|
+
H3Index h3Indexes[PADDED_COUNT] = {0};
|
29
|
+
H3_EXPORT(getPentagonIndexes)(res, h3Indexes);
|
30
|
+
|
31
|
+
int numFound = 0;
|
32
|
+
|
33
|
+
for (int i = 0; i < PADDED_COUNT; i++) {
|
34
|
+
H3Index h3Index = h3Indexes[i];
|
35
|
+
if (h3Index) {
|
36
|
+
numFound++;
|
37
|
+
t_assert(H3_EXPORT(h3IsValid(h3Index)),
|
38
|
+
"index should be valid");
|
39
|
+
t_assert(H3_EXPORT(h3IsPentagon(h3Index)),
|
40
|
+
"index should be pentagon");
|
41
|
+
t_assert(H3_EXPORT(h3GetResolution(h3Index)) == res,
|
42
|
+
"index should have correct resolution");
|
43
|
+
|
44
|
+
// verify uniqueness
|
45
|
+
for (int j = i + 1; j < PADDED_COUNT; j++) {
|
46
|
+
if (h3Indexes[j] == h3Index) {
|
47
|
+
t_assert(false, "index should be seen only once");
|
48
|
+
}
|
49
|
+
}
|
50
|
+
}
|
51
|
+
}
|
52
|
+
|
53
|
+
t_assert(numFound == expectedCount,
|
54
|
+
"there should be exactly 12 pentagons");
|
55
|
+
}
|
56
|
+
}
|
57
|
+
}
|
@@ -293,6 +293,17 @@ int H3_EXPORT(res0IndexCount)();
|
|
293
293
|
void H3_EXPORT(getRes0Indexes)(H3Index *out);
|
294
294
|
/** @} */
|
295
295
|
|
296
|
+
/** @defgroup getPentagonIndexes getPentagonIndexes
|
297
|
+
* Functions for getPentagonIndexes
|
298
|
+
* @{
|
299
|
+
*/
|
300
|
+
/** @brief returns the number of pentagons per resolution */
|
301
|
+
int H3_EXPORT(pentagonIndexCount)();
|
302
|
+
|
303
|
+
/** @brief generates all pentagons at the specified resolution */
|
304
|
+
void H3_EXPORT(getPentagonIndexes)(int res, H3Index *out);
|
305
|
+
/** @} */
|
306
|
+
|
296
307
|
/** @defgroup h3GetResolution h3GetResolution
|
297
308
|
* Functions for h3GetResolution
|
298
309
|
* @{
|
@@ -355,6 +366,15 @@ int H3_EXPORT(maxH3ToChildrenSize)(H3Index h, int childRes);
|
|
355
366
|
void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index *children);
|
356
367
|
/** @} */
|
357
368
|
|
369
|
+
/** @defgroup h3ToCenterChild h3ToCenterChild
|
370
|
+
* Functions for h3ToCenterChild
|
371
|
+
* @{
|
372
|
+
*/
|
373
|
+
/** @brief returns the center child of the given hexagon at the specified
|
374
|
+
* resolution */
|
375
|
+
H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes);
|
376
|
+
/** @} */
|
377
|
+
|
358
378
|
/** @defgroup compact compact
|
359
379
|
* Functions for compact
|
360
380
|
* @{
|
@@ -1,5 +1,5 @@
|
|
1
1
|
/*
|
2
|
-
* Copyright 2016-
|
2
|
+
* Copyright 2016-2019 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.
|
@@ -469,7 +469,7 @@ int H3_EXPORT(hexRangeDistances)(H3Index origin, int k, H3Index* out,
|
|
469
469
|
// the end of this ring.
|
470
470
|
origin =
|
471
471
|
h3NeighborRotations(origin, NEXT_RING_DIRECTION, &rotations);
|
472
|
-
if (origin == 0) {
|
472
|
+
if (origin == 0) { // LCOV_EXCL_BR_LINE
|
473
473
|
// Should not be possible because `origin` would have to be a
|
474
474
|
// pentagon
|
475
475
|
return HEX_RANGE_K_SUBSEQUENCE; // LCOV_EXCL_LINE
|
@@ -482,7 +482,7 @@ int H3_EXPORT(hexRangeDistances)(H3Index origin, int k, H3Index* out,
|
|
482
482
|
}
|
483
483
|
|
484
484
|
origin = h3NeighborRotations(origin, DIRECTIONS[direction], &rotations);
|
485
|
-
if (origin == 0) {
|
485
|
+
if (origin == 0) { // LCOV_EXCL_BR_LINE
|
486
486
|
// Should not be possible because `origin` would have to be a
|
487
487
|
// pentagon
|
488
488
|
return HEX_RANGE_K_SUBSEQUENCE; // LCOV_EXCL_LINE
|
@@ -569,7 +569,7 @@ int H3_EXPORT(hexRing)(H3Index origin, int k, H3Index* out) {
|
|
569
569
|
|
570
570
|
for (int ring = 0; ring < k; ring++) {
|
571
571
|
origin = h3NeighborRotations(origin, NEXT_RING_DIRECTION, &rotations);
|
572
|
-
if (origin == 0) {
|
572
|
+
if (origin == 0) { // LCOV_EXCL_BR_LINE
|
573
573
|
// Should not be possible because `origin` would have to be a
|
574
574
|
// pentagon
|
575
575
|
return HEX_RANGE_K_SUBSEQUENCE; // LCOV_EXCL_LINE
|
@@ -589,7 +589,7 @@ int H3_EXPORT(hexRing)(H3Index origin, int k, H3Index* out) {
|
|
589
589
|
for (int pos = 0; pos < k; pos++) {
|
590
590
|
origin =
|
591
591
|
h3NeighborRotations(origin, DIRECTIONS[direction], &rotations);
|
592
|
-
if (origin == 0) {
|
592
|
+
if (origin == 0) { // LCOV_EXCL_BR_LINE
|
593
593
|
// Should not be possible because `origin` would have to be a
|
594
594
|
// pentagon
|
595
595
|
return HEX_RANGE_K_SUBSEQUENCE; // LCOV_EXCL_LINE
|
@@ -684,14 +684,14 @@ void _faceIjkToGeoBoundary(const FaceIJK* h, int res, int isPentagon,
|
|
684
684
|
// edge-crossing vertices as needed
|
685
685
|
g->numVerts = 0;
|
686
686
|
int lastFace = -1;
|
687
|
-
|
687
|
+
Overage lastOverage = NO_OVERAGE;
|
688
688
|
for (int vert = 0; vert < NUM_HEX_VERTS + 1; vert++) {
|
689
689
|
int v = vert % NUM_HEX_VERTS;
|
690
690
|
|
691
691
|
FaceIJK fijk = fijkVerts[v];
|
692
692
|
|
693
693
|
int pentLeading4 = 0;
|
694
|
-
|
694
|
+
Overage overage = _adjustOverageClassII(&fijk, adjRes, pentLeading4, 1);
|
695
695
|
|
696
696
|
/*
|
697
697
|
Check for edge-crossing. Each face of the underlying icosahedron is a
|
@@ -703,7 +703,7 @@ void _faceIjkToGeoBoundary(const FaceIJK* h, int res, int isPentagon,
|
|
703
703
|
edge, with no edge line intersections.
|
704
704
|
*/
|
705
705
|
if (isResClassIII(res) && vert > 0 && fijk.face != lastFace &&
|
706
|
-
lastOverage !=
|
706
|
+
lastOverage != FACE_EDGE) {
|
707
707
|
// find hex2d of the two vertexes on original face
|
708
708
|
int lastV = (v + 5) % NUM_HEX_VERTS;
|
709
709
|
Vec2d orig2d0;
|
@@ -145,6 +145,22 @@ H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes) {
|
|
145
145
|
return parentH;
|
146
146
|
}
|
147
147
|
|
148
|
+
/**
|
149
|
+
* Determines whether one resolution is a valid child resolution of another.
|
150
|
+
* Each resolution is considered a valid child resolution of itself.
|
151
|
+
*
|
152
|
+
* @param parentRes int resolution of the parent
|
153
|
+
* @param childRes int resolution of the child
|
154
|
+
*
|
155
|
+
* @return The validity of the child resolution
|
156
|
+
*/
|
157
|
+
static bool _isValidChildRes(int parentRes, int childRes) {
|
158
|
+
if (childRes < parentRes || childRes > MAX_H3_RES) {
|
159
|
+
return false;
|
160
|
+
}
|
161
|
+
return true;
|
162
|
+
}
|
163
|
+
|
148
164
|
/**
|
149
165
|
* maxH3ToChildrenSize returns the maximum number of children possible for a
|
150
166
|
* given child level.
|
@@ -157,7 +173,7 @@ H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes) {
|
|
157
173
|
*/
|
158
174
|
int H3_EXPORT(maxH3ToChildrenSize)(H3Index h, int childRes) {
|
159
175
|
int parentRes = H3_GET_RESOLUTION(h);
|
160
|
-
if (parentRes
|
176
|
+
if (!_isValidChildRes(parentRes, childRes)) {
|
161
177
|
return 0;
|
162
178
|
}
|
163
179
|
return _ipow(7, (childRes - parentRes));
|
@@ -191,7 +207,7 @@ H3Index makeDirectChild(H3Index h, int cellNumber) {
|
|
191
207
|
*/
|
192
208
|
void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
|
193
209
|
int parentRes = H3_GET_RESOLUTION(h);
|
194
|
-
if (parentRes
|
210
|
+
if (!_isValidChildRes(parentRes, childRes)) {
|
195
211
|
return;
|
196
212
|
} else if (parentRes == childRes) {
|
197
213
|
*children = h;
|
@@ -214,6 +230,29 @@ void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
|
|
214
230
|
}
|
215
231
|
}
|
216
232
|
|
233
|
+
/**
|
234
|
+
* h3ToCenterChild produces the center child index for a given H3 index at
|
235
|
+
* the specified resolution
|
236
|
+
*
|
237
|
+
* @param h H3Index to find center child of
|
238
|
+
* @param childRes The resolution to switch to
|
239
|
+
*
|
240
|
+
* @return H3Index of the center child, or 0 if you actually asked for a parent
|
241
|
+
*/
|
242
|
+
H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
|
243
|
+
int parentRes = H3_GET_RESOLUTION(h);
|
244
|
+
if (!_isValidChildRes(parentRes, childRes)) {
|
245
|
+
return H3_INVALID_INDEX;
|
246
|
+
} else if (childRes == parentRes) {
|
247
|
+
return h;
|
248
|
+
}
|
249
|
+
H3Index child = H3_SET_RESOLUTION(h, childRes);
|
250
|
+
for (int i = parentRes + 1; i <= childRes; i++) {
|
251
|
+
H3_SET_INDEX_DIGIT(child, i, 0);
|
252
|
+
}
|
253
|
+
return child;
|
254
|
+
}
|
255
|
+
|
217
256
|
/**
|
218
257
|
* compact takes a set of hexagons all at the same resolution and compresses
|
219
258
|
* them by pruning full child branches to the parent level. This is also done
|
@@ -254,7 +293,7 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
|
254
293
|
int loc = (int)(parent % numRemainingHexes);
|
255
294
|
int loopCount = 0;
|
256
295
|
while (hashSetArray[loc] != 0) {
|
257
|
-
if (loopCount > numRemainingHexes) {
|
296
|
+
if (loopCount > numRemainingHexes) { // LCOV_EXCL_BR_LINE
|
258
297
|
// LCOV_EXCL_START
|
259
298
|
// This case should not be possible because at most one
|
260
299
|
// index is placed into hashSetArray per
|
@@ -330,7 +369,7 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
|
|
330
369
|
int loopCount = 0;
|
331
370
|
bool isUncompactable = true;
|
332
371
|
do {
|
333
|
-
if (loopCount > numRemainingHexes) {
|
372
|
+
if (loopCount > numRemainingHexes) { // LCOV_EXCL_BR_LINE
|
334
373
|
// LCOV_EXCL_START
|
335
374
|
// This case should not be possible because at most one
|
336
375
|
// index is placed into hashSetArray per input hexagon.
|
@@ -393,7 +432,7 @@ int H3_EXPORT(uncompact)(const H3Index* compactedSet, const int numHexes,
|
|
393
432
|
return -1;
|
394
433
|
}
|
395
434
|
int currentRes = H3_GET_RESOLUTION(compactedSet[i]);
|
396
|
-
if (currentRes
|
435
|
+
if (!_isValidChildRes(currentRes, res)) {
|
397
436
|
// Nonsensical. Abort.
|
398
437
|
return -2;
|
399
438
|
}
|
@@ -431,7 +470,7 @@ int H3_EXPORT(maxUncompactSize)(const H3Index* compactedSet, const int numHexes,
|
|
431
470
|
for (int i = 0; i < numHexes; i++) {
|
432
471
|
if (compactedSet[i] == 0) continue;
|
433
472
|
int currentRes = H3_GET_RESOLUTION(compactedSet[i]);
|
434
|
-
if (currentRes
|
473
|
+
if (!_isValidChildRes(currentRes, res)) {
|
435
474
|
// Nonsensical. Abort.
|
436
475
|
return -1;
|
437
476
|
}
|
@@ -860,6 +899,30 @@ void H3_EXPORT(h3GetFaces)(H3Index h3, int* out) {
|
|
860
899
|
}
|
861
900
|
}
|
862
901
|
|
902
|
+
/**
|
903
|
+
* pentagonIndexCount returns the number of pentagons (same at any resolution)
|
904
|
+
*
|
905
|
+
* @return int count of pentagon indexes
|
906
|
+
*/
|
907
|
+
int H3_EXPORT(pentagonIndexCount)() { return NUM_PENTAGONS; }
|
908
|
+
|
909
|
+
/**
|
910
|
+
* Generates all pentagons at the specified resolution
|
911
|
+
*
|
912
|
+
* @param res The resolution to produce pentagons at.
|
913
|
+
* @param out Output array. Must be of size pentagonIndexCount().
|
914
|
+
*/
|
915
|
+
void H3_EXPORT(getPentagonIndexes)(int res, H3Index* out) {
|
916
|
+
int i = 0;
|
917
|
+
for (int bc = 0; bc < NUM_BASE_CELLS; bc++) {
|
918
|
+
if (_isBaseCellPentagon(bc)) {
|
919
|
+
H3Index pentagon;
|
920
|
+
setH3Index(&pentagon, res, bc, 0);
|
921
|
+
out[i++] = pentagon;
|
922
|
+
}
|
923
|
+
}
|
924
|
+
}
|
925
|
+
|
863
926
|
/**
|
864
927
|
* Returns whether or not a resolution is a Class III grid. Note that odd
|
865
928
|
* resolutions are Class III and even resolutions are Class II.
|