ext/h3/src/src/h3lib/lib/h3Index.c in h3-3.6.2 vs ext/h3/src/src/h3lib/lib/h3Index.c in h3-3.7.1
- old
+ new
@@ -16,15 +16,18 @@
/** @file h3Index.c
* @brief H3Index utility functions
* (see h3api.h for the main library entry functions)
*/
#include "h3Index.h"
+
#include <faceijk.h>
#include <inttypes.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
+
+#include "alloc.h"
#include "baseCells.h"
#include "faceijk.h"
#include "mathExtensions.h"
/**
@@ -33,24 +36,29 @@
* @return The resolution of the H3 index argument.
*/
int H3_EXPORT(h3GetResolution)(H3Index h) { return H3_GET_RESOLUTION(h); }
/**
- * Returns the H3 base cell number of an H3 index.
- * @param h The H3 index.
- * @return The base cell of the H3 index argument.
+ * Returns the H3 base cell "number" of an H3 cell (hexagon or pentagon).
+ *
+ * Note: Technically works on H3 edges, but will return base cell of the
+ * origin cell.
+ *
+ * @param h The H3 cell.
+ * @return The base cell "number" of the H3 cell argument.
*/
int H3_EXPORT(h3GetBaseCell)(H3Index h) { return H3_GET_BASE_CELL(h); }
/**
* Converts a string representation of an H3 index into an H3 index.
* @param str The string representation of an H3 index.
- * @return The H3 index corresponding to the string argument, or 0 if invalid.
+ * @return The H3 index corresponding to the string argument, or H3_NULL if
+ * invalid.
*/
H3Index H3_EXPORT(stringToH3)(const char* str) {
- H3Index h = H3_INVALID_INDEX;
- // If failed, h will be unmodified and we should return 0 anyways.
+ H3Index h = H3_NULL;
+ // If failed, h will be unmodified and we should return H3_NULL anyways.
sscanf(str, "%" PRIx64, &h);
return h;
}
/**
@@ -68,17 +76,21 @@
}
sprintf(str, "%" PRIx64, h);
}
/**
- * Returns whether or not an H3 index is valid.
+ * Returns whether or not an H3 index is a valid cell (hexagon or pentagon).
* @param h The H3 index to validate.
* @return 1 if the H3 index if valid, and 0 if it is not.
*/
int H3_EXPORT(h3IsValid)(H3Index h) {
+ if (H3_GET_HIGH_BIT(h) != 0) return 0;
+
if (H3_GET_MODE(h) != H3_HEXAGON_MODE) return 0;
+ if (H3_GET_RESERVED_BITS(h) != 0) return 0;
+
int baseCell = H3_GET_BASE_CELL(h);
if (baseCell < 0 || baseCell >= NUM_BASE_CELLS) return 0;
int res = H3_GET_RESOLUTION(h);
if (res < 0 || res > MAX_H3_RES) return 0;
@@ -125,20 +137,20 @@
* h3ToParent produces the parent index for a given H3 index
*
* @param h H3Index to find parent of
* @param parentRes The resolution to switch to (parent, grandparent, etc)
*
- * @return H3Index of the parent, or 0 if you actually asked for a child
+ * @return H3Index of the parent, or H3_NULL if you actually asked for a child
*/
H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes) {
int childRes = H3_GET_RESOLUTION(h);
if (parentRes > childRes) {
- return H3_INVALID_INDEX;
+ return H3_NULL;
} else if (parentRes == childRes) {
return h;
} else if (parentRes < 0 || parentRes > MAX_H3_RES) {
- return H3_INVALID_INDEX;
+ return H3_NULL;
}
H3Index parentH = H3_SET_RESOLUTION(h, parentRes);
for (int i = parentRes + 1; i <= childRes; i++) {
H3_SET_INDEX_DIGIT(parentH, i, H3_DIGIT_MASK);
}
@@ -218,11 +230,11 @@
int isAPentagon = H3_EXPORT(h3IsPentagon)(h);
for (int i = 0; i < 7; i++) {
if (isAPentagon && i == K_AXES_DIGIT) {
H3Index* nextChild = children + bufferChildStep;
while (children < nextChild) {
- *children = H3_INVALID_INDEX;
+ *children = H3_NULL;
children++;
}
} else {
H3_EXPORT(h3ToChildren)(makeDirectChild(h, i), childRes, children);
children += bufferChildStep;
@@ -235,16 +247,17 @@
* the specified resolution
*
* @param h H3Index to find center child of
* @param childRes The resolution to switch to
*
- * @return H3Index of the center child, or 0 if you actually asked for a parent
+ * @return H3Index of the center child, or H3_NULL if you actually asked for a
+ * parent
*/
H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
int parentRes = H3_GET_RESOLUTION(h);
if (!_isValidChildRes(parentRes, childRes)) {
- return H3_INVALID_INDEX;
+ return H3_NULL;
} else if (childRes == parentRes) {
return h;
}
H3Index child = H3_SET_RESOLUTION(h, childRes);
for (int i = parentRes + 1; i <= childRes; i++) {
@@ -265,23 +278,30 @@
* @return an error code on bad input data
*/
int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
const int numHexes) {
if (numHexes == 0) {
- return 0;
+ return COMPACT_SUCCESS;
}
int res = H3_GET_RESOLUTION(h3Set[0]);
if (res == 0) {
// No compaction possible, just copy the set to output
for (int i = 0; i < numHexes; i++) {
compactedSet[i] = h3Set[i];
}
- return 0;
+ return COMPACT_SUCCESS;
}
- H3Index* remainingHexes = malloc(numHexes * sizeof(H3Index));
+ H3Index* remainingHexes = H3_MEMORY(malloc)(numHexes * sizeof(H3Index));
+ if (!remainingHexes) {
+ return COMPACT_ALLOC_FAILED;
+ }
memcpy(remainingHexes, h3Set, numHexes * sizeof(H3Index));
- H3Index* hashSetArray = calloc(numHexes, sizeof(H3Index));
+ H3Index* hashSetArray = H3_MEMORY(calloc)(numHexes, sizeof(H3Index));
+ if (!hashSetArray) {
+ H3_MEMORY(free)(remainingHexes);
+ return COMPACT_ALLOC_FAILED;
+ }
H3Index* compactedSetOffset = compactedSet;
int numRemainingHexes = numHexes;
while (numRemainingHexes) {
res = H3_GET_RESOLUTION(remainingHexes[0]);
int parentRes = res - 1;
@@ -299,27 +319,35 @@
if (loopCount > numRemainingHexes) { // LCOV_EXCL_BR_LINE
// LCOV_EXCL_START
// This case should not be possible because at most one
// index is placed into hashSetArray per
// numRemainingHexes.
- free(remainingHexes);
- free(hashSetArray);
- return -1;
+ H3_MEMORY(free)(remainingHexes);
+ H3_MEMORY(free)(hashSetArray);
+ return COMPACT_LOOP_EXCEEDED;
// LCOV_EXCL_STOP
}
H3Index tempIndex =
hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
if (tempIndex == parent) {
int count = H3_GET_RESERVED_BITS(hashSetArray[loc]) + 1;
- if (count > 7) {
+ int limitCount = 7;
+ if (H3_EXPORT(h3IsPentagon)(
+ tempIndex & H3_RESERVED_MASK_NEGATIVE)) {
+ limitCount--;
+ }
+ // One is added to count for this check to match one
+ // being added to count later in this function when
+ // checking for all children being present.
+ if (count + 1 > limitCount) {
// Only possible on duplicate input
- free(remainingHexes);
- free(hashSetArray);
- return -2;
+ H3_MEMORY(free)(remainingHexes);
+ H3_MEMORY(free)(hashSetArray);
+ return COMPACT_DUPLICATE;
}
H3_SET_RESERVED_BITS(parent, count);
- hashSetArray[loc] = H3_INVALID_INDEX;
+ hashSetArray[loc] = H3_NULL;
} else {
loc = (loc + 1) % numRemainingHexes;
}
loopCount++;
}
@@ -335,11 +363,16 @@
memcpy(compactedSetOffset, remainingHexes,
numRemainingHexes * sizeof(remainingHexes[0]));
break;
}
H3Index* compactableHexes =
- malloc(maxCompactableCount * sizeof(H3Index));
+ H3_MEMORY(calloc)(maxCompactableCount, sizeof(H3Index));
+ if (!compactableHexes) {
+ H3_MEMORY(free)(remainingHexes);
+ H3_MEMORY(free)(hashSetArray);
+ return COMPACT_ALLOC_FAILED;
+ }
for (int i = 0; i < numRemainingHexes; i++) {
if (hashSetArray[i] == 0) continue;
int count = H3_GET_RESERVED_BITS(hashSetArray[i]) + 1;
// Include the deleted direction for pentagons as implicitly "there"
if (H3_EXPORT(h3IsPentagon)(hashSetArray[i] &
@@ -361,11 +394,11 @@
// Uncompactable hexes are immediately copied into the
// output compactedSetOffset
int uncompactableCount = 0;
for (int i = 0; i < numRemainingHexes; i++) {
H3Index currIndex = remainingHexes[i];
- if (currIndex != H3_INVALID_INDEX) {
+ if (currIndex != H3_NULL) {
H3Index parent = H3_EXPORT(h3ToParent)(currIndex, parentRes);
// Modulus hash the parent into the temp array
// to determine if this index was included in
// the compactableHexes array
int loc = (int)(parent % numRemainingHexes);
@@ -374,14 +407,14 @@
do {
if (loopCount > numRemainingHexes) { // LCOV_EXCL_BR_LINE
// LCOV_EXCL_START
// This case should not be possible because at most one
// index is placed into hashSetArray per input hexagon.
- free(compactableHexes);
- free(remainingHexes);
- free(hashSetArray);
- return -1; // Only possible on duplicate input
+ H3_MEMORY(free)(compactableHexes);
+ H3_MEMORY(free)(remainingHexes);
+ H3_MEMORY(free)(hashSetArray);
+ return COMPACT_LOOP_EXCEEDED;
// LCOV_EXCL_STOP
}
H3Index tempIndex =
hashSetArray[loc] & H3_RESERVED_MASK_NEGATIVE;
if (tempIndex == parent) {
@@ -405,15 +438,15 @@
memset(hashSetArray, 0, numHexes * sizeof(H3Index));
compactedSetOffset += uncompactableCount;
memcpy(remainingHexes, compactableHexes,
compactableCount * sizeof(H3Index));
numRemainingHexes = compactableCount;
- free(compactableHexes);
+ H3_MEMORY(free)(compactableHexes);
}
- free(remainingHexes);
- free(hashSetArray);
- return 0;
+ H3_MEMORY(free)(remainingHexes);
+ H3_MEMORY(free)(hashSetArray);
+ return COMPACT_SUCCESS;
}
/**
* uncompact takes a compressed set of hexagons and expands back to the
* original set of hexagons.
@@ -601,11 +634,11 @@
/**
* Convert an FaceIJK address to the corresponding H3Index.
* @param fijk The FaceIJK address.
* @param res The cell resolution.
- * @return The encoded H3Index (or 0 on failure).
+ * @return The encoded H3Index (or H3_NULL on failure).
*/
H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
// initialize the index
H3Index h = H3_INIT;
H3_SET_MODE(h, H3_HEXAGON_MODE);
@@ -614,11 +647,11 @@
// check for res 0/base cell
if (res == 0) {
if (fijk->coord.i > MAX_FACE_COORD || fijk->coord.j > MAX_FACE_COORD ||
fijk->coord.k > MAX_FACE_COORD) {
// out of range input
- return H3_INVALID_INDEX;
+ return H3_NULL;
}
H3_SET_BASE_CELL(h, _faceIjkToBaseCell(fijk));
return h;
}
@@ -658,11 +691,11 @@
// coordinate system of the current face
if (fijkBC.coord.i > MAX_FACE_COORD || fijkBC.coord.j > MAX_FACE_COORD ||
fijkBC.coord.k > MAX_FACE_COORD) {
// out of range input
- return H3_INVALID_INDEX;
+ return H3_NULL;
}
// lookup the correct base cell
int baseCell = _faceIjkToBaseCell(&fijkBC);
H3_SET_BASE_CELL(h, baseCell);
@@ -697,18 +730,18 @@
*
* Returns 0 on invalid input.
*
* @param g The spherical coordinates to encode.
* @param res The desired H3 resolution for the encoding.
- * @return The encoded H3Index (or 0 on failure).
+ * @return The encoded H3Index (or H3_NULL on failure).
*/
H3Index H3_EXPORT(geoToH3)(const GeoCoord* g, int res) {
if (res < 0 || res > MAX_H3_RES) {
- return H3_INVALID_INDEX;
+ return H3_NULL;
}
if (!isfinite(g->lat) || !isfinite(g->lon)) {
- return H3_INVALID_INDEX;
+ return H3_NULL;
}
FaceIJK fijk;
_geoToFaceIjk(g, res, &fijk);
return _faceIjkToH3(&fijk, res);
@@ -814,11 +847,16 @@
* @param gb The boundary of the H3 cell in spherical coordinates.
*/
void H3_EXPORT(h3ToGeoBoundary)(H3Index h3, GeoBoundary* gb) {
FaceIJK fijk;
_h3ToFaceIjk(h3, &fijk);
- _faceIjkToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3),
- H3_EXPORT(h3IsPentagon)(h3), gb);
+ if (H3_EXPORT(h3IsPentagon)(h3)) {
+ _faceIjkPentToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3), 0,
+ NUM_PENT_VERTS, gb);
+ } else {
+ _faceIjkToGeoBoundary(&fijk, H3_GET_RESOLUTION(h3), 0, NUM_HEX_VERTS,
+ gb);
+ }
}
/**
* Returns the max number of possible icosahedron faces an H3 index
* may intersect.