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