Coverage Report

Created: 2025-11-11 06:21

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/h3/src/h3lib/lib/h3Index.c
Line
Count
Source
1
/*
2
 * Copyright 2016-2021, 2024 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 h3Index.c
17
 * @brief   H3Index utility functions
18
 *          (see h3api.h for the main library entry functions)
19
 */
20
#include "h3Index.h"
21
22
#include <inttypes.h>
23
#include <math.h>
24
#include <stdlib.h>
25
#include <string.h>
26
27
#include "alloc.h"
28
#include "baseCells.h"
29
#include "directedEdge.h"
30
#include "faceijk.h"
31
#include "h3Assert.h"
32
#include "iterators.h"
33
#include "mathExtensions.h"
34
#include "vertex.h"
35
36
// TODO: https://github.com/uber/h3/issues/984
37
static const bool isBaseCellPentagonArr[128] = {
38
    [4] = 1,  [14] = 1, [24] = 1, [38] = 1, [49] = 1,  [58] = 1,
39
    [63] = 1, [72] = 1, [83] = 1, [97] = 1, [107] = 1, [117] = 1};
40
41
/** @var H3ErrorDescriptions
42
 *  @brief An array of strings describing each of the H3ErrorCodes enum values
43
 */
44
static char *H3ErrorDescriptions[] = {
45
    /* E_SUCCESS */ "Success",
46
    /* E_FAILED */
47
    "The operation failed but a more specific error is not available",
48
    /* E_DOMAIN */ "Argument was outside of acceptable range",
49
    /* E_LATLNG_DOMAIN */
50
    "Latitude or longitude arguments were outside of acceptable range",
51
    /* E_RES_DOMAIN */ "Resolution argument was outside of acceptable range",
52
    /* E_CELL_INVALID */ "Cell argument was not valid",
53
    /* E_DIR_EDGE_INVALID */ "Directed edge argument was not valid",
54
    /* E_UNDIR_EDGE_INVALID */ "Undirected edge argument was not valid",
55
    /* E_VERTEX_INVALID */ "Vertex argument was not valid",
56
    /* E_PENTAGON */ "Pentagon distortion was encountered",
57
    /* E_DUPLICATE_INPUT */ "Duplicate input",
58
    /* E_NOT_NEIGHBORS */ "Cell arguments were not neighbors",
59
    /* E_RES_MISMATCH */ "Cell arguments had incompatible resolutions",
60
    /* E_MEMORY_ALLOC */ "Memory allocation failed",
61
    /* E_MEMORY_BOUNDS */ "Bounds of provided memory were insufficient",
62
    /* E_OPTION_INVALID */ "Mode or flags argument was not valid",
63
    /* E_INDEX_INVALID */ "Index argument was not valid",
64
    /* E_BASE_CELL_DOMAIN */ "Base cell number was outside of acceptable range",
65
    /* E_DIGIT_DOMAIN */ "Child digits invalid",
66
    /* E_DELETED_DIGIT */ "Deleted subsequence indicates invalid index"};
67
68
/**
69
 * Returns the string describing the H3Error. This string is internally
70
 * allocated and should not be `free`d.
71
 * @param err The H3 error.
72
 * @return The string describing the H3Error
73
 */
74
0
const char *H3_EXPORT(describeH3Error)(H3Error err) {
75
    // err is always non-negative because it is an unsigned integer
76
0
    if (err < H3_ERROR_END) {
77
0
        return H3ErrorDescriptions[err];
78
0
    }
79
0
    return "Invalid error code";
80
0
}
81
82
/**
83
 * Returns the H3 resolution of an H3 index.
84
 * @param h The H3 index.
85
 * @return The resolution of the H3 index argument.
86
 */
87
0
int H3_EXPORT(getResolution)(H3Index h) { return H3_GET_RESOLUTION(h); }
88
89
/**
90
 * Returns the H3 base cell "number" of an H3 cell (hexagon or pentagon).
91
 *
92
 * Note: Technically works on H3 edges, but will return base cell of the
93
 * origin cell.
94
 *
95
 * @param h The H3 cell.
96
 * @return The base cell "number" of the H3 cell argument.
97
 */
98
5.95k
int H3_EXPORT(getBaseCellNumber)(H3Index h) { return H3_GET_BASE_CELL(h); }
99
100
/**
101
 * Returns the index digit at `res`, which starts with 1 for resolution
102
 * 1, up to and including resolution 15.
103
 *
104
 * 0 is not a valid value for `res` because resolution 0 is specified by
105
 * the base cell number, not an indexing digit.
106
 *
107
 * `res` may exceed the actual resolution of the index, in which case
108
 * the actual digit stored in the index is returned. For valid cell indexes
109
 * this will be 7.
110
 *
111
 * @param h The H3 index (e.g. cell).
112
 * @param res Which indexing digit to retrieve, starting with 1.
113
 * @param out Receives the value of the indexing digit.
114
 * @return 0 (E_SUCCESS) on success, or another value otherwise.
115
 */
116
0
H3Error H3_EXPORT(getIndexDigit)(H3Index h, int res, int *out) {
117
0
    if (res < 1 || res > MAX_H3_RES) {
118
0
        return E_RES_DOMAIN;
119
0
    }
120
0
    *out = H3_GET_INDEX_DIGIT(h, res);
121
0
    return E_SUCCESS;
122
0
}
123
124
/**
125
 * Create a cell from its components (resolution, base cell, children digits).
126
 * Only allows for constructing valid H3 cells.
127
 *
128
 * @param res  0--15
129
 * @param baseCellNumber  0--121
130
 * @param digits  Array of child digits (0--6) of length `res`.
131
 *                NULL allowed for `res=0`.
132
 * @param out  Created cell
133
 * @return 0 (E_SUCCESS) on success, otherwise some H3Error
134
 **/
135
H3Error H3_EXPORT(constructCell)(int res, int baseCellNumber, const int *digits,
136
0
                                 H3Index *out) {
137
0
    if (res < 0 || res > MAX_H3_RES) {
138
0
        return E_RES_DOMAIN;
139
0
    }
140
0
    if (baseCellNumber < 0 || baseCellNumber >= NUM_BASE_CELLS) {
141
0
        return E_BASE_CELL_DOMAIN;
142
0
    }
143
144
0
    H3Index h = H3_INIT;
145
0
    H3_SET_MODE(h, H3_CELL_MODE);
146
0
    H3_SET_RESOLUTION(h, res);
147
0
    H3_SET_BASE_CELL(h, baseCellNumber);
148
149
0
    bool isPentagon = isBaseCellPentagonArr[baseCellNumber];
150
151
0
    for (int r = 1; r <= res; r++) {
152
0
        int d = digits[r - 1];
153
0
        if (d < CENTER_DIGIT || d >= INVALID_DIGIT) {  // (d < 0 || d >= 7)
154
0
            return E_DIGIT_DOMAIN;
155
0
        }
156
0
        if (isPentagon) {
157
            // check for deleted subsequences of pentagons
158
0
            if (d == CENTER_DIGIT) {  // d == 0
159
                // do nothing; still a pentagon
160
0
            } else if (d == K_AXES_DIGIT) {  // d == 1
161
0
                return E_DELETED_DIGIT;
162
0
            } else {
163
0
                isPentagon = false;
164
0
            }
165
0
        }
166
0
        H3_SET_INDEX_DIGIT(h, r, d);
167
0
    }
168
169
0
    *out = h;
170
171
0
    return E_SUCCESS;
172
0
}
173
174
/**
175
 * Converts a string representation of an H3 index into an H3 index.
176
 * @param str The string representation of an H3 index.
177
 * @param out Output: The H3 index corresponding to the string argument
178
 */
179
0
H3Error H3_EXPORT(stringToH3)(const char *str, H3Index *out) {
180
0
    H3Index h = H3_NULL;
181
    // If failed, h will be unmodified and we should return H3_NULL anyways.
182
0
    int read = sscanf(str, "%" PRIx64, &h);
183
0
    if (read != 1) {
184
0
        return E_FAILED;
185
0
    }
186
0
    *out = h;
187
0
    return E_SUCCESS;
188
0
}
189
190
/**
191
 * Converts an H3 index into a string representation.
192
 * @param h The H3 index to convert.
193
 * @param str The string representation of the H3 index.
194
 * @param sz Size of the buffer `str`
195
 */
196
0
H3Error H3_EXPORT(h3ToString)(H3Index h, char *str, size_t sz) {
197
    // An unsigned 64 bit integer will be expressed in at most
198
    // 16 digits plus 1 for the null terminator.
199
0
    if (sz < 17) {
200
        // Buffer is potentially not large enough.
201
0
        return E_MEMORY_BOUNDS;
202
0
    }
203
0
    sprintf(str, "%" PRIx64, h);
204
0
    return E_SUCCESS;
205
0
}
206
207
/*
208
The top 8 bits of any cell should be a specific constant:
209
210
- The 1 high bit should be `0`
211
- The 4 mode bits should be `0001` (H3_CELL_MODE)
212
- The 3 reserved bits should be `000`
213
214
In total, the top 8 bits should be `0_0001_000`
215
*/
216
238
static inline bool _hasGoodTopBits(H3Index h) {
217
238
    h >>= (64 - 8);
218
238
    return h == 0b00001000;
219
238
}
220
221
/* Check that no digit from 1 to `res` is 7 (INVALID_DIGIT).
222
223
MHI = 0b100100100100100100100100100100100100100100100;
224
MLO = MHI >> 2;
225
226
|  d  | d & MHI |  ~d | ~d - MLO | d & MHI & (~d - MLO) |  result |
227
|-----|---------|-----|----------|----------------------|---------|
228
| 000 |     000 |     |          |                  000 | OK      |
229
| 001 |     000 |     |          |                  000 | OK      |
230
| 010 |     000 |     |          |                  000 | OK      |
231
| 011 |     000 |     |          |                  000 | OK      |
232
| 100 |     100 | 011 | 010      |                  000 | OK      |
233
| 101 |     100 | 010 | 001      |                  000 | OK      |
234
| 110 |     100 | 001 | 000      |                  000 | OK      |
235
| 111 |     100 | 000 | 111*     |                  100 | invalid |
236
237
  *: carry happened
238
239
240
Note: only care about identifying the *lowest* 7.
241
242
Examples with multiple digits:
243
244
|    d    | d & MHI |    ~d   | ~d - MLO | d & MHI & (~d - MLO) |  result |
245
|---------|---------|---------|----------|----------------------|---------|
246
| 111.111 | 100.100 | 000.000 | 110.111* |              100.100 | invalid |
247
| 110.111 | 100.100 | 001.000 | 111.111* |              100.100 | invalid |
248
| 110.110 | 100.100 | 001.001 | 000.000  |              000.000 | OK      |
249
250
  *: carry happened
251
252
In the second example with 110.111, we "misidentify" the 110 as a 7, due
253
to a carry from the lower bits. But this is OK because we correctly
254
identify the lowest (only, in this example) 7 just before it.
255
256
We only have to worry about carries affecting higher bits in the case of
257
a 7; all other digits (0--6) don't cause a carry when computing ~d - MLO.
258
So even though a 7 can affect the results of higher bits, this is OK
259
because we will always correctly identify the lowest 7.
260
261
For further notes, see the discussion here:
262
https://github.com/uber/h3/pull/496#discussion_r795851046
263
*/
264
230
static inline bool _hasAny7UptoRes(H3Index h, int res) {
265
230
    const uint64_t MHI = 0b100100100100100100100100100100100100100100100;
266
230
    const uint64_t MLO = MHI >> 2;
267
268
230
    int shift = 3 * (15 - res);
269
230
    h >>= shift;
270
230
    h <<= shift;
271
230
    h = (h & MHI & (~h - MLO));
272
273
230
    return h != 0;
274
230
}
275
276
/* Check that all unused digits after `res` are set to 7 (INVALID_DIGIT).
277
278
Bit shift to avoid looping through digits.
279
*/
280
199
static inline bool _hasAll7AfterRes(H3Index h, int res) {
281
    // NOTE: res check is needed because we can't shift by 64
282
199
    if (res < 15) {
283
110
        int shift = 19 + 3 * res;
284
285
110
        h = ~h;
286
110
        h <<= shift;
287
110
        h >>= shift;
288
289
110
        return h == 0;
290
110
    }
291
89
    return true;
292
199
}
293
294
/*
295
Get index of first nonzero bit of an H3Index.
296
297
When available, use compiler intrinsics, which should be fast.
298
If not available, fall back to a loop.
299
*/
300
77
static inline int _firstOneIndex(H3Index h) {
301
77
#if defined(__GNUC__) || defined(__clang__)
302
77
    return 63 - __builtin_clzll(h);
303
#elif defined(_MSC_VER) && defined(_M_X64)  // doesn't work on win32
304
    unsigned long index;
305
    _BitScanReverse64(&index, h);
306
    return (int)index;
307
#else
308
    // Portable fallback
309
    int pos = 63 - 19;
310
    H3Index m = 1;
311
    while ((h & (m << pos)) == 0) pos--;
312
    return pos;
313
#endif
314
77
}
315
316
/*
317
One final validation just for cells whose base cell (res 0)
318
is a pentagon.
319
320
Pentagon cells start with a sequence of 0's (CENTER_DIGIT's).
321
The first nonzero digit can't be a 1 (i.e., "deleted subsequence",
322
PENTAGON_SKIPPED_DIGIT, or K_AXES_DIGIT).
323
324
We can check that (in the lower 45 = 15*3 bits) the position of the
325
first 1 bit isn't divisible by 3.
326
*/
327
133
static inline bool _hasDeletedSubsequence(H3Index h, int base_cell) {
328
133
    if (isBaseCellPentagonArr[base_cell]) {
329
79
        h <<= 19;
330
79
        h >>= 19;
331
332
79
        if (h == 0) return false;  // all zeros: res 15 pentagon
333
77
        return _firstOneIndex(h) % 3 == 0;
334
79
    }
335
54
    return false;
336
133
}
337
338
/**
339
 * Returns whether or not an H3 index is a valid cell (hexagon or pentagon).
340
 * @param h The H3 index to validate.
341
 * @return 1 if the H3 index if valid, and 0 if it is not.
342
 */
343
238
int H3_EXPORT(isValidCell)(H3Index h) {
344
    /*
345
    Look for bit patterns that would disqualify an H3Index from
346
    being valid. If identified, exit early.
347
348
    For reference the H3 index bit layout:
349
350
    |   Region   | # bits |
351
    |------------|--------|
352
    | High       |      1 |
353
    | Mode       |      4 |
354
    | Reserved   |      3 |
355
    | Resolution |      4 |
356
    | Base Cell  |      7 |
357
    | Digit 1    |      3 |
358
    | Digit 2    |      3 |
359
    | ...        |    ... |
360
    | Digit 15   |      3 |
361
362
    Speed benefits come from using bit manipulation instead of loops,
363
    whenever possible.
364
    */
365
238
    if (!_hasGoodTopBits(h)) return false;
366
367
    // No need to check resolution; any 4 bits give a valid resolution.
368
231
    const int res = H3_GET_RESOLUTION(h);
369
370
    // Get base cell number and check that it is valid.
371
231
    const int bc = H3_GET_BASE_CELL(h);
372
231
    if (bc >= NUM_BASE_CELLS) return false;
373
374
230
    if (_hasAny7UptoRes(h, res)) return false;
375
199
    if (!_hasAll7AfterRes(h, res)) return false;
376
133
    if (_hasDeletedSubsequence(h, bc)) return false;
377
378
    // If no disqualifications were identified, the index is a valid H3 cell.
379
126
    return true;
380
133
}
381
382
/**
383
 * Returns whether or not an H3 index is valid for any mode (cell, directed
384
 * edge, or vertex).
385
 * @param h The H3 index to validate.
386
 * @return 1 if the H3 index is valid for any supported type, 0 otherwise.
387
 */
388
0
int H3_EXPORT(isValidIndex)(H3Index h) {
389
0
    return H3_EXPORT(isValidCell)(h) || H3_EXPORT(isValidDirectedEdge)(h) ||
390
0
           H3_EXPORT(isValidVertex)(h);
391
0
}
392
393
/**
394
 * Initializes an H3 index.
395
 * @param hp The H3 index to initialize.
396
 * @param res The H3 resolution to initialize the index to.
397
 * @param baseCell The H3 base cell to initialize the index to.
398
 * @param initDigit The H3 digit (0-7) to initialize all of the index digits to.
399
 */
400
0
void setH3Index(H3Index *hp, int res, int baseCell, Direction initDigit) {
401
0
    H3Index h = H3_INIT;
402
0
    H3_SET_MODE(h, H3_CELL_MODE);
403
0
    H3_SET_RESOLUTION(h, res);
404
0
    H3_SET_BASE_CELL(h, baseCell);
405
0
    for (int r = 1; r <= res; r++) H3_SET_INDEX_DIGIT(h, r, initDigit);
406
0
    *hp = h;
407
0
}
408
409
/**
410
 * cellToParent produces the parent index for a given H3 index
411
 *
412
 * @param h H3Index to find parent of
413
 * @param parentRes The resolution to switch to (parent, grandparent, etc)
414
 * @param out Output: H3Index of the parent
415
 */
416
0
H3Error H3_EXPORT(cellToParent)(H3Index h, int parentRes, H3Index *out) {
417
0
    int childRes = H3_GET_RESOLUTION(h);
418
0
    if (parentRes < 0 || parentRes > MAX_H3_RES) {
419
0
        return E_RES_DOMAIN;
420
0
    } else if (parentRes > childRes) {
421
0
        return E_RES_MISMATCH;
422
0
    } else if (parentRes == childRes) {
423
0
        *out = h;
424
0
        return E_SUCCESS;
425
0
    }
426
0
    H3Index parentH = H3_SET_RESOLUTION(h, parentRes);
427
0
    for (int i = parentRes + 1; i <= childRes; i++) {
428
0
        H3_SET_INDEX_DIGIT(parentH, i, H3_DIGIT_MASK);
429
0
    }
430
0
    *out = parentH;
431
0
    return E_SUCCESS;
432
0
}
433
434
/**
435
 * Determines whether one resolution is a valid child resolution for a cell.
436
 * Each resolution is considered a valid child resolution of itself.
437
 *
438
 * @param h         h3Index  parent cell
439
 * @param childRes  int      resolution of the child
440
 *
441
 * @return The validity of the child resolution
442
 */
443
0
static bool _hasChildAtRes(H3Index h, int childRes) {
444
0
    int parentRes = H3_GET_RESOLUTION(h);
445
0
    if (childRes < parentRes || childRes > MAX_H3_RES) {
446
0
        return false;
447
0
    }
448
0
    return true;
449
0
}
450
451
/**
452
 * cellToChildrenSize returns the exact number of children for a cell at a
453
 * given child resolution.
454
 *
455
 * @param h         H3Index to find the number of children of
456
 * @param childRes  The child resolution you're interested in
457
 * @param out      Output: exact number of children (handles hexagons and
458
 * pentagons correctly)
459
 */
460
0
H3Error H3_EXPORT(cellToChildrenSize)(H3Index h, int childRes, int64_t *out) {
461
0
    if (!_hasChildAtRes(h, childRes)) return E_RES_DOMAIN;
462
463
0
    int n = childRes - H3_GET_RESOLUTION(h);
464
465
0
    if (H3_EXPORT(isPentagon)(h)) {
466
0
        *out = 1 + 5 * (_ipow(7, n) - 1) / 6;
467
0
    } else {
468
0
        *out = _ipow(7, n);
469
0
    }
470
0
    return E_SUCCESS;
471
0
}
472
473
/**
474
 * makeDirectChild takes an index and immediately returns the immediate child
475
 * index based on the specified cell number. Bit operations only, could generate
476
 * invalid indexes if not careful (deleted cell under a pentagon).
477
 *
478
 * @param h H3Index to find the direct child of
479
 * @param cellNumber int id of the direct child (0-6)
480
 *
481
 * @return The new H3Index for the child
482
 */
483
0
H3Index makeDirectChild(H3Index h, int cellNumber) {
484
0
    int childRes = H3_GET_RESOLUTION(h) + 1;
485
0
    H3Index childH = H3_SET_RESOLUTION(h, childRes);
486
0
    H3_SET_INDEX_DIGIT(childH, childRes, cellNumber);
487
0
    return childH;
488
0
}
489
490
/**
491
 * cellToChildren takes the given hexagon id and generates all of the children
492
 * at the specified resolution storing them into the provided memory pointer.
493
 * It's assumed that cellToChildrenSize was used to determine the allocation.
494
 *
495
 * @param h H3Index to find the children of
496
 * @param childRes int the child level to produce
497
 * @param children H3Index* the memory to store the resulting addresses in
498
 */
499
0
H3Error H3_EXPORT(cellToChildren)(H3Index h, int childRes, H3Index *children) {
500
0
    int64_t i = 0;
501
0
    for (IterCellsChildren iter = iterInitParent(h, childRes); iter.h;
502
0
         iterStepChild(&iter)) {
503
0
        children[i] = iter.h;
504
0
        i++;
505
0
    }
506
0
    return E_SUCCESS;
507
0
}
508
509
/**
510
 * Zero out index digits from start to end, inclusive.
511
 * No-op if start > end.
512
 */
513
0
H3Index _zeroIndexDigits(H3Index h, int start, int end) {
514
0
    if (start > end) return h;
515
516
0
    H3Index m = 0;
517
518
0
    m = ~m;
519
0
    m <<= H3_PER_DIGIT_OFFSET * (end - start + 1);
520
0
    m = ~m;
521
0
    m <<= H3_PER_DIGIT_OFFSET * (MAX_H3_RES - end);
522
0
    m = ~m;
523
524
0
    return h & m;
525
0
}
526
527
/**
528
 * cellToCenterChild produces the center child index for a given H3 index at
529
 * the specified resolution
530
 *
531
 * @param h H3Index to find center child of
532
 * @param childRes The resolution to switch to
533
 * @param child H3Index of the center child
534
 * @return 0 (E_SUCCESS) on success
535
 */
536
0
H3Error H3_EXPORT(cellToCenterChild)(H3Index h, int childRes, H3Index *child) {
537
0
    if (!_hasChildAtRes(h, childRes)) return E_RES_DOMAIN;
538
539
0
    h = _zeroIndexDigits(h, H3_GET_RESOLUTION(h) + 1, childRes);
540
0
    H3_SET_RESOLUTION(h, childRes);
541
0
    *child = h;
542
0
    return E_SUCCESS;
543
0
}
544
545
/**
546
 * compactCells takes a set of hexagons all at the same resolution and
547
 * compresses them by pruning full child branches to the parent level. This is
548
 * also done for all parents recursively to get the minimum number of hex
549
 * addresses that perfectly cover the defined space.
550
 * @param h3Set Set of hexagons
551
 * @param compactedSet The output array of compressed hexagons (preallocated)
552
 * @param numHexes The size of the input and output arrays (possible that no
553
 * contiguous regions exist in the set at all and no compression possible)
554
 * @return an error code on bad input data
555
 */
556
H3Error H3_EXPORT(compactCells)(const H3Index *h3Set, H3Index *compactedSet,
557
0
                                const int64_t numHexes) {
558
0
    if (numHexes == 0) {
559
0
        return E_SUCCESS;
560
0
    }
561
0
    int res = H3_GET_RESOLUTION(h3Set[0]);
562
0
    if (res == 0) {
563
        // No compaction possible, just copy the set to output
564
0
        for (int64_t i = 0; i < numHexes; i++) {
565
0
            compactedSet[i] = h3Set[i];
566
0
        }
567
0
        return E_SUCCESS;
568
0
    }
569
0
    H3Index *remainingHexes = H3_MEMORY(malloc)(numHexes * sizeof(H3Index));
570
0
    if (!remainingHexes) {
571
0
        return E_MEMORY_ALLOC;
572
0
    }
573
0
    memcpy(remainingHexes, h3Set, numHexes * sizeof(H3Index));
574
0
    H3Index *hashSetArray = H3_MEMORY(calloc)(numHexes, sizeof(H3Index));
575
0
    if (!hashSetArray) {
576
0
        H3_MEMORY(free)(remainingHexes);
577
0
        return E_MEMORY_ALLOC;
578
0
    }
579
0
    H3Index *compactedSetOffset = compactedSet;
580
0
    int64_t numRemainingHexes = numHexes;
581
0
    while (numRemainingHexes) {
582
0
        res = H3_GET_RESOLUTION(remainingHexes[0]);
583
0
        int parentRes = res - 1;
584
585
        // If parentRes is less than zero, we've compacted all the way up to the
586
        // base cells. Time to process the remaining cells.
587
0
        if (parentRes >= 0) {
588
            // Put the parents of the hexagons into the temp array
589
            // via a hashing mechanism, and use the reserved bits
590
            // to track how many times a parent is duplicated
591
0
            for (int64_t i = 0; i < numRemainingHexes; i++) {
592
0
                H3Index currIndex = remainingHexes[i];
593
                // TODO: This case is coverable (reachable by fuzzer)
594
0
                if (currIndex != 0) {
595
                    // If the reserved bits were set by the caller, the
596
                    // algorithm below may encounter undefined behavior
597
                    // because it expects to have set the reserved bits
598
                    // itself.
599
0
                    if (H3_GET_RESERVED_BITS(currIndex) != 0) {
600
0
                        H3_MEMORY(free)(remainingHexes);
601
0
                        H3_MEMORY(free)(hashSetArray);
602
0
                        return E_CELL_INVALID;
603
0
                    }
604
605
0
                    H3Index parent;
606
0
                    H3Error parentError =
607
0
                        H3_EXPORT(cellToParent)(currIndex, parentRes, &parent);
608
                    // Should never be reachable as a result of the compact
609
                    // algorithm. Can happen if cellToParent errors e.g.
610
                    // because of incompatible resolutions.
611
0
                    if (parentError) {
612
0
                        H3_MEMORY(free)(remainingHexes);
613
0
                        H3_MEMORY(free)(hashSetArray);
614
0
                        return parentError;
615
0
                    }
616
                    // Modulus hash the parent into the temp array
617
0
                    int64_t loc = (int64_t)(parent % numRemainingHexes);
618
0
                    DEFENSEONLY(int64_t loopCount = 0);
619
0
                    while (hashSetArray[loc] != 0) {
620
0
                        if (NEVER(loopCount > numRemainingHexes)) {
621
                            // This case should not be possible because at
622
                            // most one index is placed into hashSetArray
623
                            // per numRemainingHexes.
624
0
                            H3_MEMORY(free)(remainingHexes);
625
0
                            H3_MEMORY(free)(hashSetArray);
626
0
                            return E_FAILED;
627
0
                        }
628
0
                        H3Index tempIndex =
629
0
                            hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
630
0
                        if (tempIndex == parent) {
631
0
                            int count =
632
0
                                H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
633
0
                            int limitCount = 7;
634
0
                            if (H3_EXPORT(isPentagon)(
635
0
                                    tempIndex & H3_RESERVED_MASK_NEGATIVE)) {
636
0
                                limitCount--;
637
0
                            }
638
                            // One is added to count for this check to match
639
                            // one being added to count later in this
640
                            // function when checking for all children being
641
                            // present.
642
0
                            if (count + 1 > limitCount) {
643
                                // Only possible on duplicate input
644
0
                                H3_MEMORY(free)(remainingHexes);
645
0
                                H3_MEMORY(free)(hashSetArray);
646
0
                                return E_DUPLICATE_INPUT;
647
0
                            }
648
0
                            H3_SET_RESERVED_BITS(parent, count);
649
0
                            hashSetArray[loc] = H3_NULL;
650
0
                        } else {
651
0
                            loc = (loc + 1) % numRemainingHexes;
652
0
                        }
653
0
                        DEFENSEONLY(loopCount++);
654
0
                    }
655
0
                    hashSetArray[loc] = parent;
656
0
                }
657
0
            }
658
0
        }
659
660
        // Determine which parent hexagons have a complete set
661
        // of children and put them in the compactableHexes array
662
0
        int64_t compactableCount = 0;
663
0
        int64_t maxCompactableCount =
664
0
            numRemainingHexes / 6;  // Somehow all pentagons; conservative
665
0
        if (maxCompactableCount == 0) {
666
0
            memcpy(compactedSetOffset, remainingHexes,
667
0
                   numRemainingHexes * sizeof(remainingHexes[0]));
668
0
            break;
669
0
        }
670
0
        H3Index *compactableHexes =
671
0
            H3_MEMORY(calloc)(maxCompactableCount, sizeof(H3Index));
672
0
        if (!compactableHexes) {
673
0
            H3_MEMORY(free)(remainingHexes);
674
0
            H3_MEMORY(free)(hashSetArray);
675
0
            return E_MEMORY_ALLOC;
676
0
        }
677
0
        for (int64_t i = 0; i < numRemainingHexes; i++) {
678
0
            if (hashSetArray[i] == 0) continue;
679
0
            int count = H3_GET_RESERVED_BITS(hashSetArray[i]) + 1;
680
            // Include the deleted direction for pentagons as implicitly "there"
681
0
            if (H3_EXPORT(isPentagon)(hashSetArray[i] &
682
0
                                      H3_RESERVED_MASK_NEGATIVE)) {
683
                // We need this later on, no need to recalculate
684
0
                H3_SET_RESERVED_BITS(hashSetArray[i], count);
685
                // Increment count after setting the reserved bits,
686
                // since count is already incremented above, so it
687
                // will be the expected value for a complete hexagon.
688
0
                count++;
689
0
            }
690
0
            if (count == 7) {
691
                // Bingo! Full set!
692
0
                compactableHexes[compactableCount] =
693
0
                    hashSetArray[i] & H3_RESERVED_MASK_NEGATIVE;
694
0
                compactableCount++;
695
0
            }
696
0
        }
697
        // Uncompactable hexes are immediately copied into the
698
        // output compactedSetOffset
699
0
        int64_t uncompactableCount = 0;
700
0
        for (int64_t i = 0; i < numRemainingHexes; i++) {
701
0
            H3Index currIndex = remainingHexes[i];
702
            // TODO: This case is coverable (reachable by fuzzer)
703
0
            if (currIndex != H3_NULL) {
704
0
                bool isUncompactable = true;
705
                // Resolution 0 cells always uncompactable, and trying to take
706
                // the res -1 parent of a cell is invalid.
707
0
                if (parentRes >= 0) {
708
0
                    H3Index parent;
709
0
                    H3Error parentError =
710
0
                        H3_EXPORT(cellToParent)(currIndex, parentRes, &parent);
711
0
                    if (NEVER(parentError)) {
712
0
                        H3_MEMORY(free)(compactableHexes);
713
0
                        H3_MEMORY(free)(remainingHexes);
714
0
                        H3_MEMORY(free)(hashSetArray);
715
0
                        return parentError;
716
0
                    }
717
                    // Modulus hash the parent into the temp array
718
                    // to determine if this index was included in
719
                    // the compactableHexes array
720
0
                    int64_t loc = (int64_t)(parent % numRemainingHexes);
721
0
                    DEFENSEONLY(int64_t loopCount = 0);
722
0
                    do {
723
0
                        if (NEVER(loopCount > numRemainingHexes)) {
724
                            // This case should not be possible because at most
725
                            // one index is placed into hashSetArray per input
726
                            // hexagon.
727
0
                            H3_MEMORY(free)(compactableHexes);
728
0
                            H3_MEMORY(free)(remainingHexes);
729
0
                            H3_MEMORY(free)(hashSetArray);
730
0
                            return E_FAILED;
731
0
                        }
732
0
                        H3Index tempIndex =
733
0
                            hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
734
0
                        if (tempIndex == parent) {
735
0
                            int count =
736
0
                                H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
737
0
                            if (count == 7) {
738
0
                                isUncompactable = false;
739
0
                            }
740
0
                            break;
741
0
                        } else {
742
0
                            loc = (loc + 1) % numRemainingHexes;
743
0
                        }
744
0
                        DEFENSEONLY(loopCount++;)
745
0
                    } while (hashSetArray[loc] != parent);
746
0
                }
747
0
                if (isUncompactable) {
748
0
                    compactedSetOffset[uncompactableCount] = remainingHexes[i];
749
0
                    uncompactableCount++;
750
0
                }
751
0
            }
752
0
        }
753
        // Set up for the next loop
754
0
        memset(hashSetArray, 0, numHexes * sizeof(H3Index));
755
0
        compactedSetOffset += uncompactableCount;
756
0
        memcpy(remainingHexes, compactableHexes,
757
0
               compactableCount * sizeof(H3Index));
758
0
        numRemainingHexes = compactableCount;
759
0
        H3_MEMORY(free)(compactableHexes);
760
0
    }
761
0
    H3_MEMORY(free)(remainingHexes);
762
0
    H3_MEMORY(free)(hashSetArray);
763
0
    return E_SUCCESS;
764
0
}
765
766
/**
767
 * uncompactCells takes a compressed set of cells and expands back to the
768
 * original set of cells.
769
 *
770
 * Skips elements that are H3_NULL (i.e., 0).
771
 *
772
 * @param   compactedSet  Set of compacted cells
773
 * @param   numCompacted  The number of cells in the input compacted set
774
 * @param   outSet      Output array for decompressed cells (preallocated)
775
 * @param   numOut      The size of the output array to bound check against
776
 * @param   res         The H3 resolution to decompress to
777
 * @return              An error code if output array is too small or any cell
778
 *                      is smaller than the output resolution.
779
 */
780
H3Error H3_EXPORT(uncompactCells)(const H3Index *compactedSet,
781
                                  const int64_t numCompacted, H3Index *outSet,
782
0
                                  const int64_t numOut, const int res) {
783
0
    int64_t i = 0;
784
785
0
    for (int64_t j = 0; j < numCompacted; j++) {
786
0
        if (!_hasChildAtRes(compactedSet[j], res)) return E_RES_MISMATCH;
787
788
0
        for (IterCellsChildren iter = iterInitParent(compactedSet[j], res);
789
0
             iter.h; i++, iterStepChild(&iter)) {
790
0
            if (i >= numOut) return E_MEMORY_BOUNDS;  // went too far; abort!
791
0
            outSet[i] = iter.h;
792
0
        }
793
0
    }
794
0
    return E_SUCCESS;
795
0
}
796
797
/**
798
 * uncompactCellsSize takes a compacted set of hexagons and provides
799
 * the exact size of the uncompacted set of hexagons.
800
 *
801
 * @param   compactedSet  Set of hexagons
802
 * @param   numCompacted  The number of hexes in the input set
803
 * @param   res           The hexagon resolution to decompress to
804
 * @param   out           The number of hexagons to allocate memory for
805
 * @returns E_SUCCESS on success, or another value on error
806
 */
807
H3Error H3_EXPORT(uncompactCellsSize)(const H3Index *compactedSet,
808
                                      const int64_t numCompacted, const int res,
809
0
                                      int64_t *out) {
810
0
    int64_t numOut = 0;
811
0
    for (int64_t i = 0; i < numCompacted; i++) {
812
0
        if (compactedSet[i] == H3_NULL) continue;
813
814
0
        int64_t childrenSize;
815
0
        H3Error childrenError =
816
0
            H3_EXPORT(cellToChildrenSize)(compactedSet[i], res, &childrenSize);
817
0
        if (childrenError) {
818
            // The parent res does not contain `res`.
819
0
            return E_RES_MISMATCH;
820
0
        }
821
0
        numOut += childrenSize;
822
0
    }
823
0
    *out = numOut;
824
0
    return E_SUCCESS;
825
0
}
826
827
/**
828
 * isResClassIII takes a hexagon ID and determines if it is in a
829
 * Class III resolution (rotated versus the icosahedron and subject
830
 * to shape distortion adding extra points on icosahedron edges, making
831
 * them not true hexagons).
832
 * @param h The H3Index to check.
833
 * @return Returns 1 if the hexagon is class III, otherwise 0.
834
 */
835
0
int H3_EXPORT(isResClassIII)(H3Index h) { return H3_GET_RESOLUTION(h) % 2; }
836
837
/**
838
 * isPentagon takes an H3Index and determines if it is actually a pentagon.
839
 * @param h The H3Index to check.
840
 * @return Returns 1 if it is a pentagon, otherwise 0.
841
 */
842
11.7k
int H3_EXPORT(isPentagon)(H3Index h) {
843
11.7k
    return _isBaseCellPentagon(H3_GET_BASE_CELL(h)) &&
844
5.04k
           !_h3LeadingNonZeroDigit(h);
845
11.7k
}
846
847
/**
848
 * Returns the highest resolution non-zero digit in an H3Index.
849
 * @param h The H3Index.
850
 * @return The highest resolution non-zero digit in the H3Index.
851
 */
852
24.0k
Direction _h3LeadingNonZeroDigit(H3Index h) {
853
71.4k
    for (int r = 1; r <= H3_GET_RESOLUTION(h); r++)
854
68.2k
        if (H3_GET_INDEX_DIGIT(h, r)) return H3_GET_INDEX_DIGIT(h, r);
855
856
    // if we're here it's all 0's
857
3.28k
    return CENTER_DIGIT;
858
24.0k
}
859
860
/**
861
 * Rotate an H3Index 60 degrees counter-clockwise about a pentagonal center.
862
 * @param h The H3Index.
863
 */
864
458
H3Index _h3RotatePent60ccw(H3Index h) {
865
    // rotate in place; skips any leading 1 digits (k-axis)
866
867
458
    int foundFirstNonZeroDigit = 0;
868
3.24k
    for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
869
        // rotate this digit
870
2.79k
        H3_SET_INDEX_DIGIT(h, r, _rotate60ccw(H3_GET_INDEX_DIGIT(h, r)));
871
872
        // look for the first non-zero digit so we
873
        // can adjust for deleted k-axes sequence
874
        // if necessary
875
2.79k
        if (!foundFirstNonZeroDigit && H3_GET_INDEX_DIGIT(h, r) != 0) {
876
357
            foundFirstNonZeroDigit = 1;
877
878
            // adjust for deleted k-axes sequence
879
357
            if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT)
880
153
                h = _h3Rotate60ccw(h);
881
357
        }
882
2.79k
    }
883
458
    return h;
884
458
}
885
886
/**
887
 * Rotate an H3Index 60 degrees clockwise about a pentagonal center.
888
 * @param h The H3Index.
889
 */
890
0
H3Index _h3RotatePent60cw(H3Index h) {
891
    // rotate in place; skips any leading 1 digits (k-axis)
892
893
0
    int foundFirstNonZeroDigit = 0;
894
0
    for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
895
        // rotate this digit
896
0
        H3_SET_INDEX_DIGIT(h, r, _rotate60cw(H3_GET_INDEX_DIGIT(h, r)));
897
898
        // look for the first non-zero digit so we
899
        // can adjust for deleted k-axes sequence
900
        // if necessary
901
0
        if (!foundFirstNonZeroDigit && H3_GET_INDEX_DIGIT(h, r) != 0) {
902
0
            foundFirstNonZeroDigit = 1;
903
904
            // adjust for deleted k-axes sequence
905
0
            if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT) h = _h3Rotate60cw(h);
906
0
        }
907
0
    }
908
0
    return h;
909
0
}
910
911
/**
912
 * Rotate an H3Index 60 degrees counter-clockwise.
913
 * @param h The H3Index.
914
 */
915
2.30k
H3Index _h3Rotate60ccw(H3Index h) {
916
13.2k
    for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
917
10.9k
        Direction oldDigit = H3_GET_INDEX_DIGIT(h, r);
918
10.9k
        H3_SET_INDEX_DIGIT(h, r, _rotate60ccw(oldDigit));
919
10.9k
    }
920
921
2.30k
    return h;
922
2.30k
}
923
924
/**
925
 * Rotate an H3Index 60 degrees clockwise.
926
 * @param h The H3Index.
927
 */
928
726
H3Index _h3Rotate60cw(H3Index h) {
929
8.32k
    for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
930
7.60k
        H3_SET_INDEX_DIGIT(h, r, _rotate60cw(H3_GET_INDEX_DIGIT(h, r)));
931
7.60k
    }
932
933
726
    return h;
934
726
}
935
936
/**
937
 * Convert an FaceIJK address to the corresponding H3Index.
938
 * @param fijk The FaceIJK address.
939
 * @param res The cell resolution.
940
 * @return The encoded H3Index (or H3_NULL on failure).
941
 */
942
0
H3Index _faceIjkToH3(const FaceIJK *fijk, int res) {
943
    // initialize the index
944
0
    H3Index h = H3_INIT;
945
0
    H3_SET_MODE(h, H3_CELL_MODE);
946
0
    H3_SET_RESOLUTION(h, res);
947
948
    // check for res 0/base cell
949
0
    if (res == 0) {
950
0
        if (fijk->coord.i > MAX_FACE_COORD || fijk->coord.j > MAX_FACE_COORD ||
951
0
            fijk->coord.k > MAX_FACE_COORD) {
952
            // out of range input
953
0
            return H3_NULL;
954
0
        }
955
956
0
        H3_SET_BASE_CELL(h, _faceIjkToBaseCell(fijk));
957
0
        return h;
958
0
    }
959
960
    // we need to find the correct base cell FaceIJK for this H3 index;
961
    // start with the passed in face and resolution res ijk coordinates
962
    // in that face's coordinate system
963
0
    FaceIJK fijkBC = *fijk;
964
965
    // build the H3Index from finest res up
966
    // adjust r for the fact that the res 0 base cell offsets the indexing
967
    // digits
968
0
    CoordIJK *ijk = &fijkBC.coord;
969
0
    for (int r = res - 1; r >= 0; r--) {
970
0
        CoordIJK lastIJK = *ijk;
971
0
        CoordIJK lastCenter;
972
0
        if (isResolutionClassIII(r + 1)) {
973
            // rotate ccw
974
0
            _upAp7(ijk);
975
0
            lastCenter = *ijk;
976
0
            _downAp7(&lastCenter);
977
0
        } else {
978
            // rotate cw
979
0
            _upAp7r(ijk);
980
0
            lastCenter = *ijk;
981
0
            _downAp7r(&lastCenter);
982
0
        }
983
984
0
        CoordIJK diff;
985
0
        _ijkSub(&lastIJK, &lastCenter, &diff);
986
0
        _ijkNormalize(&diff);
987
988
0
        H3_SET_INDEX_DIGIT(h, r + 1, _unitIjkToDigit(&diff));
989
0
    }
990
991
    // fijkBC should now hold the IJK of the base cell in the
992
    // coordinate system of the current face
993
994
0
    if (fijkBC.coord.i > MAX_FACE_COORD || fijkBC.coord.j > MAX_FACE_COORD ||
995
0
        fijkBC.coord.k > MAX_FACE_COORD) {
996
        // out of range input
997
0
        return H3_NULL;
998
0
    }
999
1000
    // lookup the correct base cell
1001
0
    int baseCell = _faceIjkToBaseCell(&fijkBC);
1002
0
    H3_SET_BASE_CELL(h, baseCell);
1003
1004
    // rotate if necessary to get canonical base cell orientation
1005
    // for this base cell
1006
0
    int numRots = _faceIjkToBaseCellCCWrot60(&fijkBC);
1007
0
    if (_isBaseCellPentagon(baseCell)) {
1008
        // force rotation out of missing k-axes sub-sequence
1009
0
        if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT) {
1010
            // check for a cw/ccw offset face; default is ccw
1011
0
            if (_baseCellIsCwOffset(baseCell, fijkBC.face)) {
1012
0
                h = _h3Rotate60cw(h);
1013
0
            } else {
1014
0
                h = _h3Rotate60ccw(h);
1015
0
            }
1016
0
        }
1017
1018
0
        for (int i = 0; i < numRots; i++) h = _h3RotatePent60ccw(h);
1019
0
    } else {
1020
0
        for (int i = 0; i < numRots; i++) {
1021
0
            h = _h3Rotate60ccw(h);
1022
0
        }
1023
0
    }
1024
1025
0
    return h;
1026
0
}
1027
1028
/**
1029
 * Encodes a coordinate on the sphere to the H3 index of the containing cell at
1030
 * the specified resolution.
1031
 *
1032
 * Returns 0 on invalid input.
1033
 *
1034
 * @param g The spherical coordinates to encode.
1035
 * @param res The desired H3 resolution for the encoding.
1036
 * @param out The encoded H3Index.
1037
 * @returns E_SUCCESS (0) on success, another value otherwise
1038
 */
1039
0
H3Error H3_EXPORT(latLngToCell)(const LatLng *g, int res, H3Index *out) {
1040
0
    if (res < 0 || res > MAX_H3_RES) {
1041
0
        return E_RES_DOMAIN;
1042
0
    }
1043
0
    if (!isfinite(g->lat) || !isfinite(g->lng)) {
1044
0
        return E_LATLNG_DOMAIN;
1045
0
    }
1046
1047
0
    FaceIJK fijk;
1048
0
    _geoToFaceIjk(g, res, &fijk);
1049
0
    *out = _faceIjkToH3(&fijk, res);
1050
0
    if (ALWAYS(*out)) {
1051
0
        return E_SUCCESS;
1052
0
    } else {
1053
0
        return E_FAILED;
1054
0
    }
1055
0
}
1056
1057
/**
1058
 * Convert an H3Index to the FaceIJK address on a specified icosahedral face.
1059
 * @param h The H3Index.
1060
 * @param fijk The FaceIJK address, initialized with the desired face
1061
 *        and normalized base cell coordinates.
1062
 * @return Returns 1 if the possibility of overage exists, otherwise 0.
1063
 */
1064
6.41k
int _h3ToFaceIjkWithInitializedFijk(H3Index h, FaceIJK *fijk) {
1065
6.41k
    CoordIJK *ijk = &fijk->coord;
1066
6.41k
    int res = H3_GET_RESOLUTION(h);
1067
1068
    // center base cell hierarchy is entirely on this face
1069
6.41k
    int possibleOverage = 1;
1070
6.41k
    if (!_isBaseCellPentagon(H3_GET_BASE_CELL(h)) &&
1071
3.75k
        (res == 0 ||
1072
3.06k
         (fijk->coord.i == 0 && fijk->coord.j == 0 && fijk->coord.k == 0)))
1073
867
        possibleOverage = 0;
1074
1075
66.0k
    for (int r = 1; r <= res; r++) {
1076
59.5k
        if (isResolutionClassIII(r)) {
1077
            // Class III == rotate ccw
1078
32.0k
            _downAp7(ijk);
1079
32.0k
        } else {
1080
            // Class II == rotate cw
1081
27.5k
            _downAp7r(ijk);
1082
27.5k
        }
1083
1084
59.5k
        _neighbor(ijk, H3_GET_INDEX_DIGIT(h, r));
1085
59.5k
    }
1086
1087
6.41k
    return possibleOverage;
1088
6.41k
}
1089
1090
/**
1091
 * Convert an H3Index to a FaceIJK address.
1092
 * @param h The H3Index.
1093
 * @param fijk The corresponding FaceIJK address.
1094
 */
1095
6.42k
H3Error _h3ToFaceIjk(H3Index h, FaceIJK *fijk) {
1096
6.42k
    int baseCell = H3_GET_BASE_CELL(h);
1097
6.42k
    if (NEVER(baseCell < 0) || baseCell >= NUM_BASE_CELLS) {
1098
        // Base cells less than zero can not be represented in an index
1099
        // To prevent reading uninitialized memory, we zero the output.
1100
18
        fijk->face = 0;
1101
18
        fijk->coord.i = fijk->coord.j = fijk->coord.k = 0;
1102
18
        return E_CELL_INVALID;
1103
18
    }
1104
    // adjust for the pentagonal missing sequence; all of sub-sequence 5 needs
1105
    // to be adjusted (and some of sub-sequence 4 below)
1106
6.41k
    if (_isBaseCellPentagon(baseCell) && _h3LeadingNonZeroDigit(h) == 5)
1107
584
        h = _h3Rotate60cw(h);
1108
1109
    // start with the "home" face and ijk+ coordinates for the base cell of c
1110
6.41k
    *fijk = baseCellData[baseCell].homeFijk;
1111
6.41k
    if (!_h3ToFaceIjkWithInitializedFijk(h, fijk))
1112
867
        return E_SUCCESS;  // no overage is possible; h lies on this face
1113
1114
    // if we're here we have the potential for an "overage"; i.e., it is
1115
    // possible that c lies on an adjacent face
1116
1117
5.54k
    CoordIJK origIJK = fijk->coord;
1118
1119
    // if we're in Class III, drop into the next finer Class II grid
1120
5.54k
    int res = H3_GET_RESOLUTION(h);
1121
5.54k
    if (isResolutionClassIII(res)) {
1122
        // Class III
1123
4.33k
        _downAp7r(&fijk->coord);
1124
4.33k
        res++;
1125
4.33k
    }
1126
1127
    // adjust for overage if needed
1128
    // a pentagon base cell with a leading 4 digit requires special handling
1129
5.54k
    int pentLeading4 =
1130
5.54k
        (_isBaseCellPentagon(baseCell) && _h3LeadingNonZeroDigit(h) == 4);
1131
5.54k
    if (_adjustOverageClassII(fijk, res, pentLeading4, 0) != NO_OVERAGE) {
1132
        // if the base cell is a pentagon we have the potential for secondary
1133
        // overages
1134
2.96k
        if (_isBaseCellPentagon(baseCell)) {
1135
3.61k
            while (_adjustOverageClassII(fijk, res, 0, 0) != NO_OVERAGE)
1136
1.53k
                continue;
1137
2.08k
        }
1138
1139
2.96k
        if (res != H3_GET_RESOLUTION(h)) _upAp7r(&fijk->coord);
1140
2.96k
    } else if (res != H3_GET_RESOLUTION(h)) {
1141
1.91k
        fijk->coord = origIJK;
1142
1.91k
    }
1143
5.54k
    return E_SUCCESS;
1144
6.41k
}
1145
1146
/**
1147
 * Determines the spherical coordinates of the center point of an H3 index.
1148
 *
1149
 * @param h3 The H3 index.
1150
 * @param g The spherical coordinates of the H3 cell center.
1151
 */
1152
0
H3Error H3_EXPORT(cellToLatLng)(H3Index h3, LatLng *g) {
1153
0
    FaceIJK fijk;
1154
0
    H3Error e = _h3ToFaceIjk(h3, &fijk);
1155
0
    if (e) {
1156
0
        return e;
1157
0
    }
1158
0
    _faceIjkToGeo(&fijk, H3_GET_RESOLUTION(h3), g);
1159
0
    return E_SUCCESS;
1160
0
}
1161
1162
/**
1163
 * Determines the cell boundary in spherical coordinates for an H3 index.
1164
 *
1165
 * @param h3 The H3 index.
1166
 * @param cb The boundary of the H3 cell in spherical coordinates.
1167
 */
1168
0
H3Error H3_EXPORT(cellToBoundary)(H3Index h3, CellBoundary *cb) {
1169
0
    FaceIJK fijk;
1170
0
    H3Error e = _h3ToFaceIjk(h3, &fijk);
1171
0
    if (e) {
1172
0
        return e;
1173
0
    }
1174
0
    if (H3_EXPORT(isPentagon)(h3)) {
1175
0
        _faceIjkPentToCellBoundary(&fijk, H3_GET_RESOLUTION(h3), 0,
1176
0
                                   NUM_PENT_VERTS, cb);
1177
0
    } else {
1178
0
        _faceIjkToCellBoundary(&fijk, H3_GET_RESOLUTION(h3), 0, NUM_HEX_VERTS,
1179
0
                               cb);
1180
0
    }
1181
0
    return E_SUCCESS;
1182
0
}
1183
1184
/**
1185
 * Returns the max number of possible icosahedron faces an H3 index
1186
 * may intersect.
1187
 *
1188
 * @return int count of faces
1189
 */
1190
0
H3Error H3_EXPORT(maxFaceCount)(H3Index h3, int *out) {
1191
    // a pentagon always intersects 5 faces, a hexagon never intersects more
1192
    // than 2 (but may only intersect 1)
1193
0
    *out = H3_EXPORT(isPentagon)(h3) ? 5 : 2;
1194
0
    return E_SUCCESS;
1195
0
}
1196
1197
/**
1198
 * Find all icosahedron faces intersected by a given H3 index, represented
1199
 * as integers from 0-19. The array is sparse; since 0 is a valid value,
1200
 * invalid array values are represented as -1. It is the responsibility of
1201
 * the caller to filter out invalid values.
1202
 *
1203
 * @param h3 The H3 index
1204
 * @param out Output array. Must be of size maxFaceCount(h3).
1205
 */
1206
0
H3Error H3_EXPORT(getIcosahedronFaces)(H3Index h3, int *out) {
1207
0
    int res = H3_GET_RESOLUTION(h3);
1208
0
    int isPent = H3_EXPORT(isPentagon)(h3);
1209
1210
    // We can't use the vertex-based approach here for class II pentagons,
1211
    // because all their vertices are on the icosahedron edges. Their
1212
    // direct child pentagons cross the same faces, so use those instead.
1213
0
    if (isPent && !isResolutionClassIII(res)) {
1214
        // Note that this would not work for res 15, but this is only run on
1215
        // Class II pentagons, it should never be invoked for a res 15 index.
1216
0
        H3Index childPentagon = makeDirectChild(h3, 0);
1217
0
        return H3_EXPORT(getIcosahedronFaces)(childPentagon, out);
1218
0
    }
1219
1220
    // convert to FaceIJK
1221
0
    FaceIJK fijk;
1222
0
    H3Error err = _h3ToFaceIjk(h3, &fijk);
1223
0
    if (err) {
1224
0
        return err;
1225
0
    }
1226
1227
    // Get all vertices as FaceIJK addresses. For simplicity, always
1228
    // initialize the array with 6 verts, ignoring the last one for pentagons
1229
0
    FaceIJK fijkVerts[NUM_HEX_VERTS];
1230
0
    int vertexCount;
1231
1232
0
    if (isPent) {
1233
0
        vertexCount = NUM_PENT_VERTS;
1234
0
        _faceIjkPentToVerts(&fijk, &res, fijkVerts);
1235
0
    } else {
1236
0
        vertexCount = NUM_HEX_VERTS;
1237
0
        _faceIjkToVerts(&fijk, &res, fijkVerts);
1238
0
    }
1239
1240
    // We may not use all of the slots in the output array,
1241
    // so fill with invalid values to indicate unused slots
1242
0
    int faceCount;
1243
0
    H3Error maxFaceCountError = H3_EXPORT(maxFaceCount)(h3, &faceCount);
1244
0
    if (NEVER(maxFaceCountError != E_SUCCESS)) {
1245
0
        return maxFaceCountError;
1246
0
    }
1247
0
    for (int i = 0; i < faceCount; i++) {
1248
0
        out[i] = INVALID_FACE;
1249
0
    }
1250
1251
    // add each vertex face, using the output array as a hash set
1252
0
    for (int i = 0; i < vertexCount; i++) {
1253
0
        FaceIJK *vert = &fijkVerts[i];
1254
1255
        // Adjust overage, determining whether this vertex is
1256
        // on another face
1257
0
        if (isPent) {
1258
0
            _adjustPentVertOverage(vert, res);
1259
0
        } else {
1260
0
            _adjustOverageClassII(vert, res, 0, 1);
1261
0
        }
1262
1263
        // Save the face to the output array
1264
0
        int face = vert->face;
1265
0
        int pos = 0;
1266
        // Find the first empty output position, or the first position
1267
        // matching the current face
1268
0
        while (out[pos] != INVALID_FACE && out[pos] != face) {
1269
0
            pos++;
1270
0
            if (pos >= faceCount) {
1271
                // Mismatch between the heuristic used in maxFaceCount and
1272
                // calculation here - indicates an invalid index.
1273
0
                return E_FAILED;
1274
0
            }
1275
0
        }
1276
0
        out[pos] = face;
1277
0
    }
1278
0
    return E_SUCCESS;
1279
0
}
1280
1281
/**
1282
 * pentagonCount returns the number of pentagons (same at any resolution)
1283
 *
1284
 * @return int count of pentagon indexes
1285
 */
1286
0
int H3_EXPORT(pentagonCount)(void) { return NUM_PENTAGONS; }
1287
1288
/**
1289
 * Generates all pentagons at the specified resolution
1290
 *
1291
 * @param res The resolution to produce pentagons at.
1292
 * @param out Output array. Must be of size pentagonCount().
1293
 */
1294
0
H3Error H3_EXPORT(getPentagons)(int res, H3Index *out) {
1295
0
    if (res < 0 || res > MAX_H3_RES) {
1296
0
        return E_RES_DOMAIN;
1297
0
    }
1298
0
    int i = 0;
1299
0
    for (int bc = 0; bc < NUM_BASE_CELLS; bc++) {
1300
0
        if (_isBaseCellPentagon(bc)) {
1301
0
            H3Index pentagon;
1302
0
            setH3Index(&pentagon, res, bc, 0);
1303
0
            out[i++] = pentagon;
1304
0
        }
1305
0
    }
1306
0
    return E_SUCCESS;
1307
0
}
1308
1309
/**
1310
 * Returns whether or not a resolution is a Class III grid. Note that odd
1311
 * resolutions are Class III and even resolutions are Class II.
1312
 * @param res The H3 resolution.
1313
 * @return 1 if the resolution is a Class III grid, and 0 if the resolution is
1314
 *         a Class II grid.
1315
 */
1316
79.9k
int isResolutionClassIII(int res) { return res % 2; }
1317
1318
/**
1319
 * Validate a child position in the context of a given parent, returning
1320
 * an error if validation fails.
1321
 */
1322
static H3Error validateChildPos(int64_t childPos, H3Index parent,
1323
0
                                int childRes) {
1324
0
    int64_t maxChildCount;
1325
0
    H3Error sizeError =
1326
0
        H3_EXPORT(cellToChildrenSize)(parent, childRes, &maxChildCount);
1327
0
    if (NEVER(sizeError)) {
1328
0
        return sizeError;
1329
0
    }
1330
0
    if (childPos < 0 || childPos >= maxChildCount) {
1331
0
        return E_DOMAIN;
1332
0
    }
1333
0
    return E_SUCCESS;
1334
0
}
1335
1336
/**
1337
 * Returns the position of the cell within an ordered list of all children of
1338
 * the cell's parent at the specified resolution
1339
 * @param child Child cell index
1340
 * @param parentRes Resolution of the parent cell to find the position within
1341
 * @param out Output: The position of the child cell within its parents cell
1342
 * list of children
1343
 */
1344
0
H3Error H3_EXPORT(cellToChildPos)(H3Index child, int parentRes, int64_t *out) {
1345
0
    int childRes = H3_GET_RESOLUTION(child);
1346
    // Get the parent at res. This will catch any resolution errors
1347
0
    H3Index originalParent;
1348
0
    H3Error parentError =
1349
0
        H3_EXPORT(cellToParent(child, parentRes, &originalParent));
1350
0
    if (parentError) {
1351
0
        return parentError;
1352
0
    }
1353
1354
    // Define the initial parent. Note that these variables are reassigned
1355
    // within the loop.
1356
0
    H3Index parent = originalParent;
1357
0
    int parentIsPentagon = H3_EXPORT(isPentagon)(parent);
1358
1359
    // Walk up the resolution digits, incrementing the index
1360
0
    *out = 0;
1361
0
    if (parentIsPentagon) {
1362
        // Pentagon logic. Pentagon parents skip the 1 digit, so the offsets are
1363
        // different from hexagons
1364
0
        for (int res = childRes; res > parentRes; res--) {
1365
0
            H3Error parentError =
1366
0
                H3_EXPORT(cellToParent(child, res - 1, &parent));
1367
0
            if (NEVER(parentError)) {
1368
0
                return parentError;
1369
0
            }
1370
1371
0
            parentIsPentagon = H3_EXPORT(isPentagon)(parent);
1372
0
            int rawDigit = H3_GET_INDEX_DIGIT(child, res);
1373
            // Validate the digit before proceeding
1374
0
            if (rawDigit == INVALID_DIGIT ||
1375
0
                (parentIsPentagon && rawDigit == K_AXES_DIGIT)) {
1376
0
                return E_CELL_INVALID;
1377
0
            }
1378
0
            int digit =
1379
0
                parentIsPentagon && rawDigit > 0 ? rawDigit - 1 : rawDigit;
1380
0
            if (digit != CENTER_DIGIT) {
1381
0
                int64_t hexChildCount = _ipow(7, childRes - res);
1382
                // The offset for the 0-digit slot depends on whether the
1383
                // current index is the child of a pentagon. If so, the offset
1384
                // is based on the count of pentagon children, otherwise,
1385
                // hexagon children.
1386
0
                *out += (parentIsPentagon
1387
0
                             ?  // pentagon children. See the explanation
1388
                                // for getNumCells in h3api.h.in
1389
0
                             1 + (5 * (hexChildCount - 1)) / 6
1390
0
                             :  // one hexagon's children
1391
0
                             hexChildCount) +
1392
                        // the other hexagon children
1393
0
                        (digit - 1) * hexChildCount;
1394
0
            }
1395
0
        }
1396
0
    } else {
1397
        // Hexagon logic. Offsets are simple powers of 7
1398
0
        for (int res = childRes; res > parentRes; res--) {
1399
0
            int digit = H3_GET_INDEX_DIGIT(child, res);
1400
0
            if (digit == INVALID_DIGIT) {
1401
0
                return E_CELL_INVALID;
1402
0
            }
1403
0
            *out += digit * _ipow(7, childRes - res);
1404
0
        }
1405
0
    }
1406
1407
0
    if (NEVER(validateChildPos(*out, originalParent, childRes))) {
1408
        // This is the result of an internal error, so return E_FAILED
1409
        // instead of the validation error
1410
0
        return E_FAILED;
1411
0
    }
1412
1413
0
    return E_SUCCESS;
1414
0
}
1415
1416
/**
1417
 * Returns the child cell at a given position within an ordered list of all
1418
 * children at the specified resolution
1419
 * @param childPos Position within the ordered list
1420
 * @param parent Parent cell of the cell index to find
1421
 * @param childRes Resolution of the child cell index
1422
 * @param child Output: child cell index
1423
 */
1424
H3Error H3_EXPORT(childPosToCell)(int64_t childPos, H3Index parent,
1425
0
                                  int childRes, H3Index *child) {
1426
    // Validate resolution
1427
0
    if (childRes < 0 || childRes > MAX_H3_RES) {
1428
0
        return E_RES_DOMAIN;
1429
0
    }
1430
    // Validate parent resolution
1431
0
    int parentRes = H3_GET_RESOLUTION(parent);
1432
0
    if (childRes < parentRes) {
1433
0
        return E_RES_MISMATCH;
1434
0
    }
1435
    // Validate child pos
1436
0
    H3Error childPosErr = validateChildPos(childPos, parent, childRes);
1437
0
    if (childPosErr) {
1438
0
        return childPosErr;
1439
0
    }
1440
1441
0
    int resOffset = childRes - parentRes;
1442
1443
0
    *child = parent;
1444
0
    int64_t idx = childPos;
1445
1446
0
    H3_SET_RESOLUTION(*child, childRes);
1447
1448
0
    if (H3_EXPORT(isPentagon)(parent)) {
1449
        // Pentagon tile logic. Pentagon tiles skip the 1 digit, so the offsets
1450
        // are different
1451
0
        bool inPent = true;
1452
0
        for (int res = 1; res <= resOffset; res++) {
1453
0
            int64_t resWidth = _ipow(7, resOffset - res);
1454
0
            if (inPent) {
1455
                // While we are inside a parent pentagon, we need to check if
1456
                // this cell is a pentagon, and if not, we need to offset its
1457
                // digit to account for the skipped direction
1458
0
                int64_t pentWidth = 1 + (5 * (resWidth - 1)) / 6;
1459
0
                if (idx < pentWidth) {
1460
0
                    H3_SET_INDEX_DIGIT(*child, parentRes + res, 0);
1461
0
                } else {
1462
0
                    idx -= pentWidth;
1463
0
                    inPent = false;
1464
0
                    H3_SET_INDEX_DIGIT(*child, parentRes + res,
1465
0
                                       (idx / resWidth) + 2);
1466
0
                    idx %= resWidth;
1467
0
                }
1468
0
            } else {
1469
                // We're no longer inside a pentagon, continue as for hex
1470
0
                H3_SET_INDEX_DIGIT(*child, parentRes + res, idx / resWidth);
1471
0
                idx %= resWidth;
1472
0
            }
1473
0
        }
1474
0
    } else {
1475
        // Hexagon tile logic. Offsets are simple powers of 7
1476
0
        for (int res = 1; res <= resOffset; res++) {
1477
0
            int64_t resWidth = _ipow(7, resOffset - res);
1478
0
            H3_SET_INDEX_DIGIT(*child, parentRes + res, idx / resWidth);
1479
0
            idx %= resWidth;
1480
0
        }
1481
0
    }
1482
1483
0
    return E_SUCCESS;
1484
0
}