Coverage Report

Created: 2026-10-17 07:07

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, 2026 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
398
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
399
static inline bool _hasGoodTopBits(H3Index h) {
217
399
    h >>= (64 - 8);
218
399
    return h == 0b00001000;
219
399
}
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
282
static inline bool _hasAny7UptoRes(H3Index h, int res) {
265
282
    const uint64_t MHI = 0b100100100100100100100100100100100100100100100;
266
282
    const uint64_t MLO = MHI >> 2;
267
268
282
    int shift = 3 * (15 - res);
269
282
    h >>= shift;
270
282
    h <<= shift;
271
282
    h = (h & MHI & (~h - MLO));
272
273
282
    return h != 0;
274
282
}
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
181
static inline bool _hasAll7AfterRes(H3Index h, int res) {
281
    // NOTE: res check is needed because we can't shift by 64
282
181
    if (res < 15) {
283
118
        int shift = 19 + 3 * res;
284
285
118
        h = ~h;
286
118
        h <<= shift;
287
118
        h >>= shift;
288
289
118
        return h == 0;
290
118
    }
291
63
    return true;
292
181
}
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
70
static inline int _firstOneIndex(H3Index h) {
301
70
#if defined(__GNUC__) || defined(__clang__)
302
70
    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
70
}
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
89
static inline bool _hasDeletedSubsequence(H3Index h, int base_cell) {
328
89
    if (isBaseCellPentagonArr[base_cell]) {
329
75
        h <<= 19;
330
75
        h >>= 19;
331
332
75
        if (h == 0) return false;  // all zeros: res 15 pentagon
333
70
        return _firstOneIndex(h) % 3 == 0;
334
75
    }
335
14
    return false;
336
89
}
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
399
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
399
    if (!_hasGoodTopBits(h)) return false;
366
367
    // No need to check resolution; any 4 bits give a valid resolution.
368
283
    const int res = H3_GET_RESOLUTION(h);
369
370
    // Get base cell number and check that it is valid.
371
283
    const int bc = H3_GET_BASE_CELL(h);
372
283
    if (bc >= NUM_BASE_CELLS) return false;
373
374
282
    if (_hasAny7UptoRes(h, res)) return false;
375
181
    if (!_hasAll7AfterRes(h, res)) return false;
376
89
    if (_hasDeletedSubsequence(h, bc)) return false;
377
378
    // If no disqualifications were identified, the index is a valid H3 cell.
379
81
    return true;
380
89
}
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
292
H3Error H3_EXPORT(cellToParent)(H3Index h, int parentRes, H3Index *out) {
417
292
    int childRes = H3_GET_RESOLUTION(h);
418
292
    if (parentRes < 0 || parentRes > MAX_H3_RES) {
419
0
        return E_RES_DOMAIN;
420
292
    } else if (parentRes > childRes) {
421
0
        return E_RES_MISMATCH;
422
292
    } else if (parentRes == childRes) {
423
0
        *out = h;
424
0
        return E_SUCCESS;
425
0
    }
426
292
    H3Index parentH = H3_SET_RESOLUTION(h, parentRes);
427
584
    for (int i = parentRes + 1; i <= childRes; i++) {
428
292
        H3_SET_INDEX_DIGIT(parentH, i, H3_DIGIT_MASK);
429
292
    }
430
292
    *out = parentH;
431
292
    return E_SUCCESS;
432
292
}
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
                // Can occur if 0 is passed in to the input to this function.
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
0
            if (currIndex != H3_NULL) {
703
0
                bool isUncompactable = true;
704
                // Resolution 0 cells always uncompactable, and trying to take
705
                // the res -1 parent of a cell is invalid.
706
0
                if (parentRes >= 0) {
707
0
                    H3Index parent;
708
0
                    H3Error parentError =
709
0
                        H3_EXPORT(cellToParent)(currIndex, parentRes, &parent);
710
0
                    if (NEVER(parentError)) {
711
0
                        H3_MEMORY(free)(compactableHexes);
712
0
                        H3_MEMORY(free)(remainingHexes);
713
0
                        H3_MEMORY(free)(hashSetArray);
714
0
                        return parentError;
715
0
                    }
716
                    // Modulus hash the parent into the temp array
717
                    // to determine if this index was included in
718
                    // the compactableHexes array
719
0
                    int64_t loc = (int64_t)(parent % numRemainingHexes);
720
0
                    DEFENSEONLY(int64_t loopCount = 0);
721
0
                    do {
722
0
                        if (NEVER(loopCount > numRemainingHexes)) {
723
                            // This case should not be possible because at most
724
                            // one index is placed into hashSetArray per input
725
                            // hexagon.
726
0
                            H3_MEMORY(free)(compactableHexes);
727
0
                            H3_MEMORY(free)(remainingHexes);
728
0
                            H3_MEMORY(free)(hashSetArray);
729
0
                            return E_FAILED;
730
0
                        }
731
0
                        H3Index tempIndex =
732
0
                            hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
733
0
                        if (tempIndex == parent) {
734
0
                            int count =
735
0
                                H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
736
0
                            if (count == 7) {
737
0
                                isUncompactable = false;
738
0
                            }
739
0
                            break;
740
0
                        } else {
741
0
                            loc = (loc + 1) % numRemainingHexes;
742
0
                        }
743
0
                        DEFENSEONLY(loopCount++;)
744
0
                    } while (hashSetArray[loc] != parent);
745
0
                }
746
0
                if (isUncompactable) {
747
0
                    compactedSetOffset[uncompactableCount] = remainingHexes[i];
748
0
                    uncompactableCount++;
749
0
                }
750
0
            }
751
0
        }
752
        // Set up for the next loop
753
0
        memset(hashSetArray, 0, numHexes * sizeof(H3Index));
754
0
        compactedSetOffset += uncompactableCount;
755
0
        memcpy(remainingHexes, compactableHexes,
756
0
               compactableCount * sizeof(H3Index));
757
0
        numRemainingHexes = compactableCount;
758
0
        H3_MEMORY(free)(compactableHexes);
759
0
    }
760
0
    H3_MEMORY(free)(remainingHexes);
761
0
    H3_MEMORY(free)(hashSetArray);
762
0
    return E_SUCCESS;
763
0
}
764
765
/**
766
 * uncompactCells takes a compressed set of cells and expands back to the
767
 * original set of cells.
768
 *
769
 * Skips elements that are H3_NULL (i.e., 0).
770
 *
771
 * @param   compactedSet  Set of compacted cells
772
 * @param   numCompacted  The number of cells in the input compacted set
773
 * @param   outSet      Output array for decompressed cells (preallocated)
774
 * @param   numOut      The size of the output array to bound check against
775
 * @param   res         The H3 resolution to decompress to
776
 * @return              An error code if output array is too small or any cell
777
 *                      is smaller than the output resolution.
778
 */
779
H3Error H3_EXPORT(uncompactCells)(const H3Index *compactedSet,
780
                                  const int64_t numCompacted, H3Index *outSet,
781
0
                                  const int64_t numOut, const int res) {
782
0
    int64_t i = 0;
783
784
0
    for (int64_t j = 0; j < numCompacted; j++) {
785
0
        if (!_hasChildAtRes(compactedSet[j], res)) return E_RES_MISMATCH;
786
787
0
        for (IterCellsChildren iter = iterInitParent(compactedSet[j], res);
788
0
             iter.h; i++, iterStepChild(&iter)) {
789
0
            if (i >= numOut) return E_MEMORY_BOUNDS;  // went too far; abort!
790
0
            outSet[i] = iter.h;
791
0
        }
792
0
    }
793
0
    return E_SUCCESS;
794
0
}
795
796
/**
797
 * uncompactCellsSize takes a compacted set of hexagons and provides
798
 * the exact size of the uncompacted set of hexagons.
799
 *
800
 * @param   compactedSet  Set of hexagons
801
 * @param   numCompacted  The number of hexes in the input set
802
 * @param   res           The hexagon resolution to decompress to
803
 * @param   out           The number of hexagons to allocate memory for
804
 * @returns E_SUCCESS on success, or another value on error
805
 */
806
H3Error H3_EXPORT(uncompactCellsSize)(const H3Index *compactedSet,
807
                                      const int64_t numCompacted, const int res,
808
0
                                      int64_t *out) {
809
0
    int64_t numOut = 0;
810
0
    for (int64_t i = 0; i < numCompacted; i++) {
811
0
        if (compactedSet[i] == H3_NULL) continue;
812
813
0
        int64_t childrenSize;
814
0
        H3Error childrenError =
815
0
            H3_EXPORT(cellToChildrenSize)(compactedSet[i], res, &childrenSize);
816
0
        if (childrenError) {
817
            // The parent res does not contain `res`.
818
0
            return E_RES_MISMATCH;
819
0
        }
820
0
        if (ADD_INT64S_OVERFLOWS(numOut, childrenSize)) {
821
            // numOut + childrenSize would overflow
822
0
            return E_MEMORY_ALLOC;
823
0
        }
824
0
        numOut += childrenSize;
825
0
    }
826
0
    *out = numOut;
827
0
    return E_SUCCESS;
828
0
}
829
830
/**
831
 * isResClassIII takes a hexagon ID and determines if it is in a
832
 * Class III resolution (rotated versus the icosahedron and subject
833
 * to shape distortion adding extra points on icosahedron edges, making
834
 * them not true hexagons).
835
 * @param h The H3Index to check.
836
 * @return Returns 1 if the hexagon is class III, otherwise 0.
837
 */
838
0
int H3_EXPORT(isResClassIII)(H3Index h) { return H3_GET_RESOLUTION(h) % 2; }
839
840
/**
841
 * isPentagon takes an H3Index and determines if it is actually a pentagon.
842
 * @param h The H3Index to check.
843
 * @return Returns 1 if it is a pentagon, otherwise 0.
844
 */
845
3.66k
int H3_EXPORT(isPentagon)(H3Index h) {
846
3.66k
    return _isBaseCellPentagon(H3_GET_BASE_CELL(h)) &&
847
1.94k
           !_h3LeadingNonZeroDigit(h);
848
3.66k
}
849
850
/**
851
 * Returns the highest resolution non-zero digit in an H3Index.
852
 * @param h The H3Index.
853
 * @return The highest resolution non-zero digit in the H3Index.
854
 */
855
14.2k
Direction _h3LeadingNonZeroDigit(H3Index h) {
856
39.2k
    for (int r = 1; r <= H3_GET_RESOLUTION(h); r++)
857
37.4k
        if (H3_GET_INDEX_DIGIT(h, r)) return H3_GET_INDEX_DIGIT(h, r);
858
859
    // if we're here it's all 0's
860
1.86k
    return CENTER_DIGIT;
861
14.2k
}
862
863
/**
864
 * Rotate an H3Index 60 degrees counter-clockwise about a pentagonal center.
865
 * @param h The H3Index.
866
 */
867
468
H3Index _h3RotatePent60ccw(H3Index h) {
868
    // rotate in place; skips any leading 1 digits (k-axis)
869
870
468
    int foundFirstNonZeroDigit = 0;
871
2.64k
    for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
872
        // rotate this digit
873
2.18k
        H3_SET_INDEX_DIGIT(h, r, _rotate60ccw(H3_GET_INDEX_DIGIT(h, r)));
874
875
        // look for the first non-zero digit so we
876
        // can adjust for deleted k-axes sequence
877
        // if necessary
878
2.18k
        if (!foundFirstNonZeroDigit && H3_GET_INDEX_DIGIT(h, r) != 0) {
879
354
            foundFirstNonZeroDigit = 1;
880
881
            // adjust for deleted k-axes sequence
882
354
            if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT)
883
122
                h = _h3Rotate60ccw(h);
884
354
        }
885
2.18k
    }
886
468
    return h;
887
468
}
888
889
/**
890
 * Rotate an H3Index 60 degrees clockwise about a pentagonal center.
891
 * @param h The H3Index.
892
 */
893
0
H3Index _h3RotatePent60cw(H3Index h) {
894
    // rotate in place; skips any leading 1 digits (k-axis)
895
896
0
    int foundFirstNonZeroDigit = 0;
897
0
    for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
898
        // rotate this digit
899
0
        H3_SET_INDEX_DIGIT(h, r, _rotate60cw(H3_GET_INDEX_DIGIT(h, r)));
900
901
        // look for the first non-zero digit so we
902
        // can adjust for deleted k-axes sequence
903
        // if necessary
904
0
        if (!foundFirstNonZeroDigit && H3_GET_INDEX_DIGIT(h, r) != 0) {
905
0
            foundFirstNonZeroDigit = 1;
906
907
            // adjust for deleted k-axes sequence
908
0
            if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT) h = _h3Rotate60cw(h);
909
0
        }
910
0
    }
911
0
    return h;
912
0
}
913
914
/**
915
 * Rotate an H3Index 60 degrees counter-clockwise.
916
 * @param h The H3Index.
917
 */
918
2.18k
H3Index _h3Rotate60ccw(H3Index h) {
919
10.0k
    for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
920
7.84k
        Direction oldDigit = H3_GET_INDEX_DIGIT(h, r);
921
7.84k
        H3_SET_INDEX_DIGIT(h, r, _rotate60ccw(oldDigit));
922
7.84k
    }
923
924
2.18k
    return h;
925
2.18k
}
926
927
/**
928
 * Rotate an H3Index 60 degrees clockwise.
929
 * @param h The H3Index.
930
 */
931
166
H3Index _h3Rotate60cw(H3Index h) {
932
1.81k
    for (int r = 1, res = H3_GET_RESOLUTION(h); r <= res; r++) {
933
1.64k
        H3_SET_INDEX_DIGIT(h, r, _rotate60cw(H3_GET_INDEX_DIGIT(h, r)));
934
1.64k
    }
935
936
166
    return h;
937
166
}
938
939
/**
940
 * Convert an FaceIJK address to the corresponding H3Index.
941
 * @param fijk The FaceIJK address.
942
 * @param res The cell resolution.
943
 * @return The encoded H3Index (or H3_NULL on failure).
944
 */
945
0
H3Index _faceIjkToH3(const FaceIJK *fijk, int res) {
946
    // initialize the index
947
0
    H3Index h = H3_INIT;
948
0
    H3_SET_MODE(h, H3_CELL_MODE);
949
0
    H3_SET_RESOLUTION(h, res);
950
951
    // check for res 0/base cell
952
0
    if (res == 0) {
953
0
        if (fijk->coord.i > MAX_FACE_COORD || fijk->coord.j > MAX_FACE_COORD ||
954
0
            fijk->coord.k > MAX_FACE_COORD) {
955
            // out of range input
956
0
            return H3_NULL;
957
0
        }
958
959
0
        H3_SET_BASE_CELL(h, _faceIjkToBaseCell(fijk));
960
0
        return h;
961
0
    }
962
963
    // we need to find the correct base cell FaceIJK for this H3 index;
964
    // start with the passed in face and resolution res ijk coordinates
965
    // in that face's coordinate system
966
0
    FaceIJK fijkBC = *fijk;
967
968
    // build the H3Index from finest res up
969
    // adjust r for the fact that the res 0 base cell offsets the indexing
970
    // digits
971
0
    CoordIJK *ijk = &fijkBC.coord;
972
0
    for (int r = res - 1; r >= 0; r--) {
973
0
        CoordIJK lastIJK = *ijk;
974
0
        CoordIJK lastCenter;
975
0
        if (isResolutionClassIII(r + 1)) {
976
            // rotate ccw
977
0
            _upAp7(ijk);
978
0
            lastCenter = *ijk;
979
0
            _downAp7(&lastCenter);
980
0
        } else {
981
            // rotate cw
982
0
            _upAp7r(ijk);
983
0
            lastCenter = *ijk;
984
0
            _downAp7r(&lastCenter);
985
0
        }
986
987
0
        CoordIJK diff;
988
0
        _ijkSub(&lastIJK, &lastCenter, &diff);
989
0
        _ijkNormalize(&diff);
990
991
0
        H3_SET_INDEX_DIGIT(h, r + 1, _unitIjkToDigit(&diff));
992
0
    }
993
994
    // fijkBC should now hold the IJK of the base cell in the
995
    // coordinate system of the current face
996
997
0
    if (fijkBC.coord.i > MAX_FACE_COORD || fijkBC.coord.j > MAX_FACE_COORD ||
998
0
        fijkBC.coord.k > MAX_FACE_COORD) {
999
        // out of range input
1000
0
        return H3_NULL;
1001
0
    }
1002
1003
    // lookup the correct base cell
1004
0
    int baseCell = _faceIjkToBaseCell(&fijkBC);
1005
0
    H3_SET_BASE_CELL(h, baseCell);
1006
1007
    // rotate if necessary to get canonical base cell orientation
1008
    // for this base cell
1009
0
    int numRots = _faceIjkToBaseCellCCWrot60(&fijkBC);
1010
0
    if (_isBaseCellPentagon(baseCell)) {
1011
        // force rotation out of missing k-axes sub-sequence
1012
0
        if (_h3LeadingNonZeroDigit(h) == K_AXES_DIGIT) {
1013
            // check for a cw/ccw offset face; default is ccw
1014
0
            if (_baseCellIsCwOffset(baseCell, fijkBC.face)) {
1015
0
                h = _h3Rotate60cw(h);
1016
0
            } else {
1017
0
                h = _h3Rotate60ccw(h);
1018
0
            }
1019
0
        }
1020
1021
0
        for (int i = 0; i < numRots; i++) h = _h3RotatePent60ccw(h);
1022
0
    } else {
1023
0
        for (int i = 0; i < numRots; i++) {
1024
0
            h = _h3Rotate60ccw(h);
1025
0
        }
1026
0
    }
1027
1028
0
    return h;
1029
0
}
1030
1031
/**
1032
 * Encodes a coordinate on the sphere to the H3 index of the containing cell at
1033
 * the specified resolution.
1034
 *
1035
 * Returns 0 on invalid input.
1036
 *
1037
 * @param g The spherical coordinates to encode.
1038
 * @param res The desired H3 resolution for the encoding.
1039
 * @param out The encoded H3Index.
1040
 * @returns E_SUCCESS (0) on success, another value otherwise
1041
 */
1042
0
H3Error H3_EXPORT(latLngToCell)(const LatLng *g, int res, H3Index *out) {
1043
0
    if (res < 0 || res > MAX_H3_RES) {
1044
0
        return E_RES_DOMAIN;
1045
0
    }
1046
0
    if (!isfinite(g->lat) || !isfinite(g->lng)) {
1047
0
        return E_LATLNG_DOMAIN;
1048
0
    }
1049
1050
0
    Vec3d v = latLngToVec3(*g);
1051
0
    return vec3ToCell(&v, res, out);
1052
0
}
1053
1054
/**
1055
 * Encodes a coordinate on the sphere to the H3 index of the containing cell at
1056
 * the specified resolution.
1057
 *
1058
 * Vec3d v is expected to be on the unit sphere.
1059
 *
1060
 * @param v The 3D cartesian coordinates to encode.
1061
 * @param res The desired H3 resolution for the encoding.
1062
 * @param out The encoded H3Index.
1063
 * @returns E_SUCCESS on success, another value otherwise
1064
 */
1065
0
H3Error vec3ToCell(const Vec3d *v, int res, H3Index *out) {
1066
0
    if (res < 0 || res > MAX_H3_RES) {
1067
0
        return E_RES_DOMAIN;
1068
0
    }
1069
0
    if (!isfinite(v->x) || !isfinite(v->y) || !isfinite(v->z)) {
1070
0
        return E_DOMAIN;
1071
0
    }
1072
1073
0
    FaceIJK fijk;
1074
0
    _vec3ToFaceIjk(*v, res, &fijk);
1075
0
    *out = _faceIjkToH3(&fijk, res);
1076
0
    if (ALWAYS(*out)) {
1077
0
        return E_SUCCESS;
1078
0
    } else {
1079
0
        return E_FAILED;
1080
0
    }
1081
0
}
1082
1083
/**
1084
 * Convert an H3Index to the FaceIJK address on a specified icosahedral face.
1085
 * @param h The H3Index.
1086
 * @param fijk The FaceIJK address, initialized with the desired face
1087
 *        and normalized base cell coordinates.
1088
 * @return Returns 1 if the possibility of overage exists, otherwise 0.
1089
 */
1090
796
int _h3ToFaceIjkWithInitializedFijk(H3Index h, FaceIJK *fijk) {
1091
796
    CoordIJK *ijk = &fijk->coord;
1092
796
    int res = H3_GET_RESOLUTION(h);
1093
1094
    // center base cell hierarchy is entirely on this face
1095
796
    int possibleOverage = 1;
1096
796
    if (!_isBaseCellPentagon(H3_GET_BASE_CELL(h)) &&
1097
308
        (res == 0 ||
1098
284
         (fijk->coord.i == 0 && fijk->coord.j == 0 && fijk->coord.k == 0)))
1099
36
        possibleOverage = 0;
1100
1101
9.28k
    for (int r = 1; r <= res; r++) {
1102
8.49k
        if (isResolutionClassIII(r)) {
1103
            // Class III == rotate ccw
1104
4.58k
            _downAp7(ijk);
1105
4.58k
        } else {
1106
            // Class II == rotate cw
1107
3.90k
            _downAp7r(ijk);
1108
3.90k
        }
1109
1110
8.49k
        _neighbor(ijk, H3_GET_INDEX_DIGIT(h, r));
1111
8.49k
    }
1112
1113
796
    return possibleOverage;
1114
796
}
1115
1116
/**
1117
 * Convert an H3Index to a FaceIJK address.
1118
 * @param h The H3Index.
1119
 * @param fijk The corresponding FaceIJK address.
1120
 */
1121
797
H3Error _h3ToFaceIjk(H3Index h, FaceIJK *fijk) {
1122
797
    int baseCell = H3_GET_BASE_CELL(h);
1123
797
    if (NEVER(baseCell < 0) || baseCell >= NUM_BASE_CELLS) {
1124
        // Base cells less than zero can not be represented in an index
1125
        // To prevent reading uninitialized memory, we zero the output.
1126
1
        fijk->face = 0;
1127
1
        fijk->coord.i = fijk->coord.j = fijk->coord.k = 0;
1128
1
        return E_CELL_INVALID;
1129
1
    }
1130
    // adjust for the pentagonal missing sequence; all of sub-sequence 5 needs
1131
    // to be adjusted (and some of sub-sequence 4 below)
1132
796
    if (_isBaseCellPentagon(baseCell) && _h3LeadingNonZeroDigit(h) == 5)
1133
54
        h = _h3Rotate60cw(h);
1134
1135
    // start with the "home" face and ijk+ coordinates for the base cell of c
1136
796
    *fijk = baseCellData[baseCell].homeFijk;
1137
796
    if (!_h3ToFaceIjkWithInitializedFijk(h, fijk))
1138
36
        return E_SUCCESS;  // no overage is possible; h lies on this face
1139
1140
    // if we're here we have the potential for an "overage"; i.e., it is
1141
    // possible that c lies on an adjacent face
1142
1143
760
    CoordIJK origIJK = fijk->coord;
1144
1145
    // if we're in Class III, drop into the next finer Class II grid
1146
760
    int res = H3_GET_RESOLUTION(h);
1147
760
    if (isResolutionClassIII(res)) {
1148
        // Class III
1149
664
        _downAp7r(&fijk->coord);
1150
664
        res++;
1151
664
    }
1152
1153
    // adjust for overage if needed
1154
    // a pentagon base cell with a leading 4 digit requires special handling
1155
760
    int pentLeading4 =
1156
760
        (_isBaseCellPentagon(baseCell) && _h3LeadingNonZeroDigit(h) == 4);
1157
760
    if (_adjustOverageClassII(fijk, res, pentLeading4, 0) != NO_OVERAGE) {
1158
        // if the base cell is a pentagon we have the potential for secondary
1159
        // overages
1160
498
        if (_isBaseCellPentagon(baseCell)) {
1161
712
            while (_adjustOverageClassII(fijk, res, 0, 0) != NO_OVERAGE)
1162
344
                continue;
1163
368
        }
1164
1165
498
        if (res != H3_GET_RESOLUTION(h)) _upAp7r(&fijk->coord);
1166
498
    } else if (res != H3_GET_RESOLUTION(h)) {
1167
216
        fijk->coord = origIJK;
1168
216
    }
1169
760
    return E_SUCCESS;
1170
796
}
1171
1172
/**
1173
 * Determines the 3D cartesian coordinates of the center of an H3 cell.
1174
 *
1175
 * @param h3 The H3 index.
1176
 * @param v The 3D cartesian coordinates of the H3 cell center.
1177
 * @return E_SUCCESS on success, or another H3Error code on failure.
1178
 */
1179
0
H3Error cellToVec3(H3Index h3, Vec3d *v) {
1180
0
    FaceIJK fijk;
1181
0
    H3Error e = _h3ToFaceIjk(h3, &fijk);
1182
0
    if (e) {
1183
0
        return e;
1184
0
    }
1185
0
    _faceIjkToVec3(&fijk, H3_GET_RESOLUTION(h3), v);
1186
0
    return E_SUCCESS;
1187
0
}
1188
1189
/**
1190
 * Determines the spherical coordinates of the center point of an H3 index.
1191
 *
1192
 * @param h3 The H3 index.
1193
 * @param g The spherical coordinates of the H3 cell center.
1194
 */
1195
0
H3Error H3_EXPORT(cellToLatLng)(H3Index h3, LatLng *g) {
1196
0
    Vec3d v;
1197
0
    H3Error e = cellToVec3(h3, &v);
1198
0
    if (e) {
1199
0
        return e;
1200
0
    }
1201
0
    *g = vec3ToLatLng(v);
1202
0
    return E_SUCCESS;
1203
0
}
1204
1205
/**
1206
 * Determines the cell boundary in spherical coordinates for an H3 index.
1207
 *
1208
 * @param h3 The H3 index.
1209
 * @param cb The boundary of the H3 cell in spherical coordinates.
1210
 */
1211
0
H3Error H3_EXPORT(cellToBoundary)(H3Index h3, CellBoundary *cb) {
1212
0
    FaceIJK fijk;
1213
0
    H3Error e = _h3ToFaceIjk(h3, &fijk);
1214
0
    if (e) {
1215
0
        return e;
1216
0
    }
1217
0
    if (H3_EXPORT(isPentagon)(h3)) {
1218
0
        _faceIjkPentToCellBoundary(&fijk, H3_GET_RESOLUTION(h3), 0,
1219
0
                                   NUM_PENT_VERTS, cb);
1220
0
    } else {
1221
0
        _faceIjkToCellBoundary(&fijk, H3_GET_RESOLUTION(h3), 0, NUM_HEX_VERTS,
1222
0
                               cb);
1223
0
    }
1224
0
    return E_SUCCESS;
1225
0
}
1226
1227
/**
1228
 * Returns the max number of possible icosahedron faces an H3 index
1229
 * may intersect.
1230
 *
1231
 * @return int count of faces
1232
 */
1233
0
H3Error H3_EXPORT(maxFaceCount)(H3Index h3, int *out) {
1234
    // a pentagon always intersects 5 faces, a hexagon never intersects more
1235
    // than 2 (but may only intersect 1)
1236
0
    *out = H3_EXPORT(isPentagon)(h3) ? 5 : 2;
1237
0
    return E_SUCCESS;
1238
0
}
1239
1240
/**
1241
 * Find all icosahedron faces intersected by a given H3 index, represented
1242
 * as integers from 0-19. The array is sparse; since 0 is a valid value,
1243
 * invalid array values are represented as -1. It is the responsibility of
1244
 * the caller to filter out invalid values.
1245
 *
1246
 * @param h3 The H3 index
1247
 * @param out Output array. Must be of size maxFaceCount(h3).
1248
 */
1249
0
H3Error H3_EXPORT(getIcosahedronFaces)(H3Index h3, int *out) {
1250
0
    int res = H3_GET_RESOLUTION(h3);
1251
0
    int isPent = H3_EXPORT(isPentagon)(h3);
1252
1253
    // We can't use the vertex-based approach here for class II pentagons,
1254
    // because all their vertices are on the icosahedron edges. Their
1255
    // direct child pentagons cross the same faces, so use those instead.
1256
0
    if (isPent && !isResolutionClassIII(res)) {
1257
        // Note that this would not work for res 15, but this is only run on
1258
        // Class II pentagons, it should never be invoked for a res 15 index.
1259
0
        H3Index childPentagon = makeDirectChild(h3, 0);
1260
0
        return H3_EXPORT(getIcosahedronFaces)(childPentagon, out);
1261
0
    }
1262
1263
    // convert to FaceIJK
1264
0
    FaceIJK fijk;
1265
0
    H3Error err = _h3ToFaceIjk(h3, &fijk);
1266
0
    if (err) {
1267
0
        return err;
1268
0
    }
1269
1270
    // Get all vertices as FaceIJK addresses. For simplicity, always
1271
    // initialize the array with 6 verts, ignoring the last one for pentagons
1272
0
    FaceIJK fijkVerts[NUM_HEX_VERTS];
1273
0
    int vertexCount;
1274
1275
0
    if (isPent) {
1276
0
        vertexCount = NUM_PENT_VERTS;
1277
0
        _faceIjkPentToVerts(&fijk, &res, fijkVerts);
1278
0
    } else {
1279
0
        vertexCount = NUM_HEX_VERTS;
1280
0
        _faceIjkToVerts(&fijk, &res, fijkVerts);
1281
0
    }
1282
1283
    // We may not use all of the slots in the output array,
1284
    // so fill with invalid values to indicate unused slots
1285
0
    int faceCount;
1286
0
    H3Error maxFaceCountError = H3_EXPORT(maxFaceCount)(h3, &faceCount);
1287
0
    if (NEVER(maxFaceCountError != E_SUCCESS)) {
1288
0
        return maxFaceCountError;
1289
0
    }
1290
0
    for (int i = 0; i < faceCount; i++) {
1291
0
        out[i] = INVALID_FACE;
1292
0
    }
1293
1294
    // add each vertex face, using the output array as a hash set
1295
0
    for (int i = 0; i < vertexCount; i++) {
1296
0
        FaceIJK *vert = &fijkVerts[i];
1297
1298
        // Adjust overage, determining whether this vertex is
1299
        // on another face
1300
0
        if (isPent) {
1301
0
            _adjustPentVertOverage(vert, res);
1302
0
        } else {
1303
0
            _adjustOverageClassII(vert, res, 0, 1);
1304
0
        }
1305
1306
        // Save the face to the output array
1307
0
        int face = vert->face;
1308
0
        int pos = 0;
1309
        // Find the first empty output position, or the first position
1310
        // matching the current face
1311
0
        while (out[pos] != INVALID_FACE && out[pos] != face) {
1312
0
            pos++;
1313
0
            if (pos >= faceCount) {
1314
                // Mismatch between the heuristic used in maxFaceCount and
1315
                // calculation here - indicates an invalid index.
1316
0
                return E_FAILED;
1317
0
            }
1318
0
        }
1319
0
        out[pos] = face;
1320
0
    }
1321
0
    return E_SUCCESS;
1322
0
}
1323
1324
/**
1325
 * pentagonCount returns the number of pentagons (same at any resolution)
1326
 *
1327
 * @return int count of pentagon indexes
1328
 */
1329
0
int H3_EXPORT(pentagonCount)(void) { return NUM_PENTAGONS; }
1330
1331
/**
1332
 * Generates all pentagons at the specified resolution
1333
 *
1334
 * @param res The resolution to produce pentagons at.
1335
 * @param out Output array. Must be of size pentagonCount().
1336
 */
1337
0
H3Error H3_EXPORT(getPentagons)(int res, H3Index *out) {
1338
0
    if (res < 0 || res > MAX_H3_RES) {
1339
0
        return E_RES_DOMAIN;
1340
0
    }
1341
0
    int i = 0;
1342
0
    for (int bc = 0; bc < NUM_BASE_CELLS; bc++) {
1343
0
        if (_isBaseCellPentagon(bc)) {
1344
0
            H3Index pentagon;
1345
0
            setH3Index(&pentagon, res, bc, 0);
1346
0
            out[i++] = pentagon;
1347
0
        }
1348
0
    }
1349
0
    return E_SUCCESS;
1350
0
}
1351
1352
/**
1353
 * Returns whether or not a resolution is a Class III grid. Note that odd
1354
 * resolutions are Class III and even resolutions are Class II.
1355
 * @param res The H3 resolution.
1356
 * @return 1 if the resolution is a Class III grid, and 0 if the resolution is
1357
 *         a Class II grid.
1358
 */
1359
22.3k
int isResolutionClassIII(int res) { return res % 2; }
1360
1361
/**
1362
 * Validate a child position in the context of a given parent, returning
1363
 * an error if validation fails.
1364
 */
1365
static H3Error validateChildPos(int64_t childPos, H3Index parent,
1366
0
                                int childRes) {
1367
0
    int64_t maxChildCount;
1368
0
    H3Error sizeError =
1369
0
        H3_EXPORT(cellToChildrenSize)(parent, childRes, &maxChildCount);
1370
0
    if (NEVER(sizeError)) {
1371
0
        return sizeError;
1372
0
    }
1373
0
    if (childPos < 0 || childPos >= maxChildCount) {
1374
0
        return E_DOMAIN;
1375
0
    }
1376
0
    return E_SUCCESS;
1377
0
}
1378
1379
/**
1380
 * Returns the position of the cell within an ordered list of all children of
1381
 * the cell's parent at the specified resolution
1382
 * @param child Child cell index
1383
 * @param parentRes Resolution of the parent cell to find the position within
1384
 * @param out Output: The position of the child cell within its parents cell
1385
 * list of children
1386
 */
1387
0
H3Error H3_EXPORT(cellToChildPos)(H3Index child, int parentRes, int64_t *out) {
1388
0
    int childRes = H3_GET_RESOLUTION(child);
1389
    // Get the parent at res. This will catch any resolution errors
1390
0
    H3Index originalParent;
1391
0
    H3Error parentError =
1392
0
        H3_EXPORT(cellToParent(child, parentRes, &originalParent));
1393
0
    if (parentError) {
1394
0
        return parentError;
1395
0
    }
1396
1397
    // Define the initial parent. Note that these variables are reassigned
1398
    // within the loop.
1399
0
    H3Index parent = originalParent;
1400
0
    int parentIsPentagon = H3_EXPORT(isPentagon)(parent);
1401
1402
    // Walk up the resolution digits, incrementing the index
1403
0
    *out = 0;
1404
0
    if (parentIsPentagon) {
1405
        // Pentagon logic. Pentagon parents skip the 1 digit, so the offsets are
1406
        // different from hexagons
1407
0
        for (int res = childRes; res > parentRes; res--) {
1408
0
            H3Error parentError =
1409
0
                H3_EXPORT(cellToParent(child, res - 1, &parent));
1410
0
            if (NEVER(parentError)) {
1411
0
                return parentError;
1412
0
            }
1413
1414
0
            parentIsPentagon = H3_EXPORT(isPentagon)(parent);
1415
0
            int rawDigit = H3_GET_INDEX_DIGIT(child, res);
1416
            // Validate the digit before proceeding
1417
0
            if (rawDigit == INVALID_DIGIT ||
1418
0
                (parentIsPentagon && rawDigit == K_AXES_DIGIT)) {
1419
0
                return E_CELL_INVALID;
1420
0
            }
1421
0
            int digit =
1422
0
                parentIsPentagon && rawDigit > 0 ? rawDigit - 1 : rawDigit;
1423
0
            if (digit != CENTER_DIGIT) {
1424
0
                int64_t hexChildCount = _ipow(7, childRes - res);
1425
                // The offset for the 0-digit slot depends on whether the
1426
                // current index is the child of a pentagon. If so, the offset
1427
                // is based on the count of pentagon children, otherwise,
1428
                // hexagon children.
1429
0
                *out += (parentIsPentagon
1430
0
                             ?  // pentagon children. See the explanation
1431
                                // for getNumCells in h3api.h.in
1432
0
                             1 + (5 * (hexChildCount - 1)) / 6
1433
0
                             :  // one hexagon's children
1434
0
                             hexChildCount) +
1435
                        // the other hexagon children
1436
0
                        (digit - 1) * hexChildCount;
1437
0
            }
1438
0
        }
1439
0
    } else {
1440
        // Hexagon logic. Offsets are simple powers of 7
1441
0
        for (int res = childRes; res > parentRes; res--) {
1442
0
            int digit = H3_GET_INDEX_DIGIT(child, res);
1443
0
            if (digit == INVALID_DIGIT) {
1444
0
                return E_CELL_INVALID;
1445
0
            }
1446
0
            *out += digit * _ipow(7, childRes - res);
1447
0
        }
1448
0
    }
1449
1450
0
    if (NEVER(validateChildPos(*out, originalParent, childRes))) {
1451
        // This is the result of an internal error, so return E_FAILED
1452
        // instead of the validation error
1453
0
        return E_FAILED;
1454
0
    }
1455
1456
0
    return E_SUCCESS;
1457
0
}
1458
1459
/**
1460
 * Returns the child cell at a given position within an ordered list of all
1461
 * children at the specified resolution
1462
 * @param childPos Position within the ordered list
1463
 * @param parent Parent cell of the cell index to find
1464
 * @param childRes Resolution of the child cell index
1465
 * @param child Output: child cell index
1466
 */
1467
H3Error H3_EXPORT(childPosToCell)(int64_t childPos, H3Index parent,
1468
0
                                  int childRes, H3Index *child) {
1469
    // Validate resolution
1470
0
    if (childRes < 0 || childRes > MAX_H3_RES) {
1471
0
        return E_RES_DOMAIN;
1472
0
    }
1473
    // Validate parent resolution
1474
0
    int parentRes = H3_GET_RESOLUTION(parent);
1475
0
    if (childRes < parentRes) {
1476
0
        return E_RES_MISMATCH;
1477
0
    }
1478
    // Validate child pos
1479
0
    H3Error childPosErr = validateChildPos(childPos, parent, childRes);
1480
0
    if (childPosErr) {
1481
0
        return childPosErr;
1482
0
    }
1483
1484
0
    int resOffset = childRes - parentRes;
1485
1486
0
    *child = parent;
1487
0
    int64_t idx = childPos;
1488
1489
0
    H3_SET_RESOLUTION(*child, childRes);
1490
1491
0
    if (H3_EXPORT(isPentagon)(parent)) {
1492
        // Pentagon tile logic. Pentagon tiles skip the 1 digit, so the offsets
1493
        // are different
1494
0
        bool inPent = true;
1495
0
        for (int res = 1; res <= resOffset; res++) {
1496
0
            int64_t resWidth = _ipow(7, resOffset - res);
1497
0
            if (inPent) {
1498
                // While we are inside a parent pentagon, we need to check if
1499
                // this cell is a pentagon, and if not, we need to offset its
1500
                // digit to account for the skipped direction
1501
0
                int64_t pentWidth = 1 + (5 * (resWidth - 1)) / 6;
1502
0
                if (idx < pentWidth) {
1503
0
                    H3_SET_INDEX_DIGIT(*child, parentRes + res, 0);
1504
0
                } else {
1505
0
                    idx -= pentWidth;
1506
0
                    inPent = false;
1507
0
                    H3_SET_INDEX_DIGIT(*child, parentRes + res,
1508
0
                                       (idx / resWidth) + 2);
1509
0
                    idx %= resWidth;
1510
0
                }
1511
0
            } else {
1512
                // We're no longer inside a pentagon, continue as for hex
1513
0
                H3_SET_INDEX_DIGIT(*child, parentRes + res, idx / resWidth);
1514
0
                idx %= resWidth;
1515
0
            }
1516
0
        }
1517
0
    } else {
1518
        // Hexagon tile logic. Offsets are simple powers of 7
1519
0
        for (int res = 1; res <= resOffset; res++) {
1520
0
            int64_t resWidth = _ipow(7, resOffset - res);
1521
0
            H3_SET_INDEX_DIGIT(*child, parentRes + res, idx / resWidth);
1522
0
            idx %= resWidth;
1523
0
        }
1524
0
    }
1525
1526
0
    return E_SUCCESS;
1527
0
}