h3 3.5.1 → 3.6.0
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.
- 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.
|