-
Notifications
You must be signed in to change notification settings - Fork 60
/
h3_iterators.c
324 lines (254 loc) · 10.8 KB
/
h3_iterators.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
/*
* Copyright 2021 Uber Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/** @file IterCellsChildren.c
* @brief Iterator structs and functions for the children of a cell,
* or cells at a given resolution.
*/
#include "h3_iterators.h"
#include "h3_h3Index.h"
// extract the `res` digit (0--7) of the current cell
static int _getResDigit(IterCellsChildren *it, int res) {
return H3_GET_INDEX_DIGIT(it->h, res);
}
// increment the digit (0--7) at location `res`
// H3_PER_DIGIT_OFFSET == 3
static void _incrementResDigit(IterCellsChildren *it, int res) {
H3Index val = 1;
val <<= H3_PER_DIGIT_OFFSET * (MAX_H3_RES - res);
it->h += val;
}
/**
* Create a fully nulled-out child iterator for when an iterator is exhausted.
* This helps minimize the chance that a user will depend on the iterator
* internal state after it's exhausted, like the child resolution, for
* example.
*/
static IterCellsChildren _null_iter() {
return (IterCellsChildren){
.h = H3_NULL, ._parentRes = -1, ._skipDigit = -1};
}
/**
## Logic for iterating through the children of a cell
We'll describe the logic for ....
- normal (non pentagon iteration)
- pentagon iteration. define "pentagon digit"
### Cell Index Component Diagrams
The lower 56 bits of an H3 Cell Index describe the following index components:
- the cell resolution (4 bits)
- the base cell number (7 bits)
- the child cell digit for each resolution from 1 to 15 (3*15 = 45 bits)
These are the bits we'll be focused on when iterating through child cells.
To help describe the iteration logic, we'll use diagrams displaying the
(decimal) values for each component like:
child digit for resolution 2
/
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 | ... |
|-----|-------------|---|---|---|---|---|---|-----|
| 9 | 17 | 5 | 3 | 0 | 6 | 2 | 1 | ... |
### Iteration through children of a hexagon (but not a pentagon)
Iteration through the children of a *hexagon* (but not a pentagon)
simply involves iterating through all the children values (0--6)
for each child digit (up to the child's resolution).
For example, suppose a resolution 3 hexagon index has the following
components:
parent resolution
/
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 | ... |
|-----|-------------|---|---|---|---|---|---|-----|
| 3 | 17 | 3 | 5 | 1 | 7 | 7 | 7 | ... |
The iteration through all children of resolution 6 would look like:
parent res child res
/ /
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | ... |
|-----|-------------|---|---|---|---|---|---|---|---|-----|
| 6 | 17 | 3 | 5 | 1 | 0 | 0 | 0 | 7 | 7 | ... |
| 6 | 17 | 3 | 5 | 1 | 0 | 0 | 1 | 7 | 7 | ... |
| ... | | | | | | | | | | |
| 6 | 17 | 3 | 5 | 1 | 0 | 0 | 6 | 7 | 7 | ... |
| 6 | 17 | 3 | 5 | 1 | 0 | 1 | 0 | 7 | 7 | ... |
| 6 | 17 | 3 | 5 | 1 | 0 | 1 | 1 | 7 | 7 | ... |
| ... | | | | | | | | | | |
| 6 | 17 | 3 | 5 | 1 | 6 | 6 | 6 | 7 | 7 | ... |
### Step sequence on a *pentagon* cell
Pentagon cells have a base cell number (e.g., 97) corresponding to a
resolution 0 pentagon, and have all zeros from digit 1 to the digit
corresponding to the cell's resolution.
(We'll drop the ellipses from now on, knowing that digits should contain
7's beyond the cell resolution.)
parent res child res
/ /
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
|-----|-------------|---|---|---|---|---|---|
| 6 | 97 | 0 | 0 | 0 | 0 | 0 | 0 |
Iteration through children of a *pentagon* is almost the same
as *hexagon* iteration, except that we skip the *first* 1 value
that appears in the "skip digit". This corresponds to the fact
that a pentagon only has 6 children, which are denoted with
the numbers {0,2,3,4,5,6}.
The skip digit starts at the child resolution position.
When iterating through children more than one resolution below
the parent, we move the skip digit to the left
(up to the next coarser resolution) each time we skip the 1 value
in that digit.
Iteration would start like:
parent res child res
/ /
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
|-----|-------------|---|---|---|---|---|---|
| 6 | 97 | 0 | 0 | 0 | 0 | 0 | 0 |
\
skip digit
Noticing we skip the 1 value and move the skip digit,
the next iterate would be:
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
|-----|-------------|---|---|---|---|---|---|
| 6 | 97 | 0 | 0 | 0 | 0 | 0 | 2 |
\
skip digit
Iteration continues normally until we get to:
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
|-----|-------------|---|---|---|---|---|---|
| 6 | 97 | 0 | 0 | 0 | 0 | 0 | 6 |
\
skip digit
which is followed by (skipping the 1):
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
|-----|-------------|---|---|---|---|---|---|
| 6 | 97 | 0 | 0 | 0 | 0 | 2 | 0 |
\
skip digit
For the next iterate, we won't skip the `1` in the previous digit
because it is no longer the skip digit:
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
|-----|-------------|---|---|---|---|---|---|
| 6 | 97 | 0 | 0 | 0 | 0 | 2 | 1 |
\
skip digit
Iteration continues normally until we're right before the next skip
digit:
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
|-----|-------------|---|---|---|---|---|---|
| 6 | 97 | 0 | 0 | 0 | 0 | 6 | 6 |
\
skip digit
Which is followed by
| res | base cell # | 1 | 2 | 3 | 4 | 5 | 6 |
|-----|-------------|---|---|---|---|---|---|
| 6 | 97 | 0 | 0 | 0 | 2 | 0 | 0 |
\
skip digit
and so on.
*/
/**
* Initialize a IterCellsChildren struct representing the sequence giving
* the children of cell `h` at resolution `childRes`.
*
* At any point in the iteration, starting once
* the struct is initialized, IterCellsChildren.h gives the current child.
*
* Also, IterCellsChildren.h == H3_NULL when all the children have been iterated
* through, or if the input to `iterInitParent` was invalid.
*/
IterCellsChildren iterInitParent(H3Index h, int childRes) {
IterCellsChildren it;
it._parentRes = H3_GET_RESOLUTION(h);
if (childRes < it._parentRes || childRes > MAX_H3_RES || h == H3_NULL) {
return _null_iter();
}
it.h = _zeroIndexDigits(h, it._parentRes + 1, childRes);
H3_SET_RESOLUTION(it.h, childRes);
if (H3_EXPORT(isPentagon)(it.h)) {
// The skip digit skips `1` for pentagons.
// The "_skipDigit" moves to the left as we count up from the
// child resolution to the parent resolution.
it._skipDigit = childRes;
} else {
// if not a pentagon, we can ignore "skip digit" logic
it._skipDigit = -1;
}
return it;
}
/**
* Step a IterCellsChildren to the next child cell.
* When the iteration is over, IterCellsChildren.h will be H3_NULL.
* Handles iterating through hexagon and pentagon cells.
*/
void iterStepChild(IterCellsChildren *it) {
// once h == H3_NULL, the iterator returns an infinite sequence of H3_NULL
if (it->h == H3_NULL) return;
int childRes = H3_GET_RESOLUTION(it->h);
_incrementResDigit(it, childRes);
for (int i = childRes; i >= it->_parentRes; i--) {
if (i == it->_parentRes) {
// if we're modifying the parent resolution digit, then we're done
*it = _null_iter();
return;
}
// PENTAGON_SKIPPED_DIGIT == 1
if (i == it->_skipDigit &&
_getResDigit(it, i) == PENTAGON_SKIPPED_DIGIT) {
// Then we are iterating through the children of a pentagon cell.
// All children of a pentagon have the property that the first
// nonzero digit between the parent and child resolutions is
// not 1.
// I.e., we never see a sequence like 00001.
// Thus, we skip the `1` in this digit.
_incrementResDigit(it, i);
it->_skipDigit -= 1;
return;
}
// INVALID_DIGIT == 7
if (_getResDigit(it, i) == INVALID_DIGIT) {
_incrementResDigit(
it, i); // zeros out it[i] and increments it[i-1] by 1
} else {
break;
}
}
}
// create iterator for children of base cell at given resolution
IterCellsChildren iterInitBaseCellNum(int baseCellNum, int childRes) {
if (baseCellNum < 0 || baseCellNum >= NUM_BASE_CELLS || childRes < 0 ||
childRes > MAX_H3_RES) {
return _null_iter();
}
H3Index baseCell;
setH3Index(&baseCell, 0, baseCellNum, 0);
return iterInitParent(baseCell, childRes);
}
// create iterator for all cells at given resolution
IterCellsResolution iterInitRes(int res) {
IterCellsChildren itC = iterInitBaseCellNum(0, res);
IterCellsResolution itR = {
.h = itC.h, ._baseCellNum = 0, ._res = res, ._itC = itC};
return itR;
}
void iterStepRes(IterCellsResolution *itR) {
// reached the end of over iterator; emits H3_NULL from now on
if (itR->h == H3_NULL) return;
// step child iterator
iterStepChild(&(itR->_itC));
// If the child iterator is exhausted and there are still
// base cells remaining, we initialize the next base cell child iterator
if ((itR->_itC.h == H3_NULL) && (itR->_baseCellNum + 1 < NUM_BASE_CELLS)) {
itR->_baseCellNum += 1;
itR->_itC = iterInitBaseCellNum(itR->_baseCellNum, itR->_res);
}
// This overall iterator reflects the next cell in the child iterator.
// Note: This sets itR->h = H3_NULL if the base cells were
// exhausted in the check above.
itR->h = itR->_itC.h;
}