Skip to content

Commit 81812d2

Browse files
authored
change H3_INVALID_INDEX to H3_NULL (#379)
* change H3_INVALID_INDEX to H3_NULL * document H3_NULL in the naming RFC * some formatting happened * tell the people about `git clean -ffdx` * H3_INVALID_INDEX -> H3_NULL from Nick's change * formatting happened * build and clean instructions * where to run `make` * brew to `brew`, and no need to be stingy * Docs on Mode 0 vs H3_NULL * to the future! * add the `build` back into the .gitignore * I get H3_INIT now * going backwards on going forward
1 parent fd0f8af commit 81812d2

File tree

11 files changed

+85
-49
lines changed

11 files changed

+85
-49
lines changed

README.md

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ Documentation is available at [https://uber.github.io/h3/](https://uber.github.i
1919

2020
We recommend using prebuilt bindings if they are available for your programming language. Bindings for [Go](https://github.com/uber/h3-go), [Java](https://github.com/uber/h3-java), [JavaScript](https://github.com/uber/h3-js), [Python](https://github.com/uber/h3-py), and [others](https://uber.github.io/h3/#/documentation/community/bindings) are available.
2121

22-
On macOS, you can install H3 using brew:
22+
On macOS, you can install H3 using `brew`:
2323
```
2424
brew install h3
2525
```
@@ -46,7 +46,7 @@ sudo apt install cmake make gcc libtool
4646
sudo apt install clang-format cmake-curses-gui lcov doxygen
4747
```
4848

49-
* macOS (using brew)
49+
* macOS (using `brew`)
5050

5151
First make sure you [have the developer tools installed](http://osxdaily.com/2014/02/12/install-command-line-tools-mac-os-x/) and then
5252

@@ -63,19 +63,31 @@ You will need to install CMake and Visual Studio, including the Visual C++ compi
6363

6464
#### Compilation
6565

66-
From the repository you would then compile like so:
66+
From the repository root, you can compile H3 with:
6767

6868
```
69-
cmake .
69+
mkdir build
70+
cd build
71+
cmake ..
7072
make
7173
```
7274

75+
All subsequent `make` commands should be run from within the `build` directory.
76+
77+
**Note**: There are several ways to build H3 with CMake; the method above is just one example that restricts all build artifacts to the `build` directory.
78+
7379
You can install system-wide with:
7480

7581
```
7682
sudo make install
7783
```
7884

85+
If using the method above, from the repository root, you can clean all build artifacts with:
86+
87+
```
88+
rm -rf build
89+
```
90+
7991
#### Testing
8092

8193
After making the project, you can test with `make test`, and if `lcov` is installed you can `make coverage` to generate a code coverage report.

dev-docs/RFCs/v4.0.0/names_for_concepts_types_functions.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ The following technical terms should be used in the documentation, the H3 codeba
6666
- may include more than 6 points in the case that a cell is not a geometric hexagon, such as when a hexagon crosses an icosahedron boundary
6767
- may also be used to describe the boundary between two geometric cells, as in the case of an edge
6868
- represented in the H3 codebase with the `CellBoundary` struct (previously `GeoBoundary` before v4.0)
69+
- `H3_NULL`;
70+
- equivalent to `0` and guaranteed to never be a valid `H3Index` (even after any future H3 **modes** are added)
71+
- returned by functions to denote an error, or to denote missing data in arrays of `H3Index`
72+
- analogous to `NaN` in floating point
6973

7074

7175
### Use of "hex", "hexagon", "cell", "pentagon", etc.

docs/core-library/h3indexing.md

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,18 @@ Child hexagons are linearly smaller than their parent hexagons.
1313

1414
## H3Index Representation
1515

16-
The **H3Index** is the integer representation of an **H3** index, which can be placed into multiple modes to indicate the kind of concept being indexed. Mode 1 is an **H3** Cell (Hexagon) Index, mode 2 is an **H3** Unidirectional Edge (Hexagon A -> Hexagon B) Index, mode 3 is planned to be a bidirectional edge (Hexagon A <-> Hexagon B). Mode 0 is reserved and indicates an invalid **H3** index.
16+
The **H3Index** is the integer representation of an **H3** index, which can be placed into multiple modes to indicate the concept being indexed.
17+
18+
* Mode 1 is an **H3** Cell (Hexagon/Pentagon) index.
19+
* Mode 2 is an **H3** Unidirectional Edge (Cell A -> Cell B) index.
20+
* Mode 3 is planned to be a bidirectional edge (Cell A <-> Cell B).
21+
* Mode 0 is reserved and indicates an invalid **H3** index.
22+
* This mode remains, partially, for backwards compatibility with an older version of H3.
23+
24+
Mode 0 contains a special index, `H3_NULL`, which is unique: it is bit-equivalent to `0`.
25+
This index indicates, *specifically*, an invalid, missing, or uninitialized **H3** index;
26+
it is analogous to `NaN` in floating point.
27+
It should be used instead of an arbitrary Mode 0 index, due to its uniqueness and easy identifiability.
1728

1829
The components of the **H3** cell index (mode 1) are packed into a 64-bit integer in order, highest bit first, as follows:
1930

src/apps/applib/lib/utility.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -242,7 +242,7 @@ void randomGeo(GeoCoord* g) {
242242
int countActualHexagons(H3Index* hexagons, int numHexagons) {
243243
int actualNumHexagons = 0;
244244
for (int i = 0; i < numHexagons; i++) {
245-
if (hexagons[i] != H3_INVALID_INDEX) {
245+
if (hexagons[i] != H3_NULL) {
246246
actualNumHexagons++;
247247
}
248248
}

src/apps/testapps/testH3ToLocalIj.c

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -90,16 +90,19 @@ SUITE(h3ToLocalIj) {
9090
const int numCoords = 7;
9191
const CoordIJ coords[] = {{0, 0}, {1, 0}, {2, 0}, {3, 0},
9292
{4, 0}, {-4, 0}, {0, 4}};
93-
const H3Index expected[] = {0x81283ffffffffff, 0x81293ffffffffff,
94-
0x8150bffffffffff, 0x8151bffffffffff,
95-
H3_INVALID_INDEX, H3_INVALID_INDEX,
96-
H3_INVALID_INDEX};
93+
const H3Index expected[] = {0x81283ffffffffff,
94+
0x81293ffffffffff,
95+
0x8150bffffffffff,
96+
0x8151bffffffffff,
97+
H3_NULL,
98+
H3_NULL,
99+
H3_NULL};
97100

98101
for (int i = 0; i < numCoords; i++) {
99102
H3Index result;
100103
const int err = H3_EXPORT(experimentalLocalIjToH3)(
101104
expected[0], &coords[i], &result);
102-
if (expected[i] == H3_INVALID_INDEX) {
105+
if (expected[i] == H3_NULL) {
103106
t_assert(err != 0, "coordinates out of range");
104107
} else {
105108
t_assert(err == 0, "coordinates in range");

src/apps/testapps/testH3UniEdgeExhaustive.c

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -38,8 +38,7 @@ static void h3UniEdge_correctness_assertions(H3Index h3) {
3838

3939
for (int i = 0; i < 6; i++) {
4040
if (isPentagon && i == 0) {
41-
t_assert(edges[i] == H3_INVALID_INDEX,
42-
"last pentagon edge is empty");
41+
t_assert(edges[i] == H3_NULL, "last pentagon edge is empty");
4342
continue;
4443
}
4544
t_assert(H3_EXPORT(h3UnidirectionalEdgeIsValid)(edges[i]) == 1,
@@ -64,7 +63,7 @@ static void h3UniEdge_boundary_assertions(H3Index h3) {
6463
GeoBoundary revEdgeBoundary;
6564

6665
for (int i = 0; i < 6; i++) {
67-
if (edges[i] == H3_INVALID_INDEX) continue;
66+
if (edges[i] == H3_NULL) continue;
6867
H3_EXPORT(getH3UnidirectionalEdgeBoundary)(edges[i], &edgeBoundary);
6968
destination =
7069
H3_EXPORT(getDestinationH3IndexFromUnidirectionalEdge)(edges[i]);

src/apps/testapps/testPolyfill.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,7 @@ static void fillIndex_assertions(H3Index h) {
9292

9393
for (int i = 0; i < childrenSize; i++) {
9494
bool found = false;
95-
if (children[i] == H3_INVALID_INDEX) continue;
95+
if (children[i] == H3_NULL) continue;
9696
for (int j = 0; j < polyfillSize; j++) {
9797
if (polyfillOut[j] == children[i]) {
9898
found = true;

src/h3lib/include/h3Index.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -82,7 +82,11 @@
8282
/** 0's in the 7 base cell bits, 1's everywhere else. */
8383
#define H3_DIGIT_MASK_NEGATIVE (~H3_DIGIT_MASK)
8484

85-
/** H3 index with mode 0, res 0, base cell 0, and 7 for all index digits. */
85+
/**
86+
* H3 index with mode 0, res 0, base cell 0, and 7 for all index digits.
87+
* Typically used to initialize the creation of an H3 cell index, which
88+
* expects all direction digits to be 7 beyond the cell's resolution.
89+
*/
8690
#define H3_INIT (UINT64_C(35184372088831))
8791

8892
/**
@@ -161,9 +165,10 @@
161165
<< ((MAX_H3_RES - (res)) * H3_PER_DIGIT_OFFSET)))
162166

163167
/**
164-
* Invalid index used to indicate an error from geoToH3 and related functions.
168+
* Invalid index used to indicate an error from geoToH3 and related functions
169+
* or missing data in arrays of h3 indices. Analogous to NaN in floating point.
165170
*/
166-
#define H3_INVALID_INDEX 0
171+
#define H3_NULL 0
167172

168173
/*
169174
* Return codes for compact

src/h3lib/lib/algos.c

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -278,7 +278,7 @@ void _kRingInternal(H3Index origin, int k, H3Index* out, int* distances,
278278
* @param rotations Number of ccw rotations to perform to reorient the
279279
* translation vector. Will be modified to the new number of
280280
* rotations to perform (such as when crossing a face edge.)
281-
* @return H3Index of the specified neighbor or 0 if deleted k-subsequence
281+
* @return H3Index of the specified neighbor or H3_NULL if deleted k-subsequence
282282
* distortion is encountered.
283283
*/
284284
H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
@@ -363,7 +363,7 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
363363
// base cell.
364364
if (oldLeadingDigit == CENTER_DIGIT) {
365365
// Undefined: the k direction is deleted from here
366-
return H3_INVALID_INDEX;
366+
return H3_NULL;
367367
} else if (oldLeadingDigit == JK_AXES_DIGIT) {
368368
// Rotate out of the deleted k subsequence
369369
// We also need an additional change to the direction we're
@@ -378,7 +378,7 @@ H3Index h3NeighborRotations(H3Index origin, Direction dir, int* rotations) {
378378
*rotations = *rotations + 5;
379379
} else {
380380
// Should never occur
381-
return H3_INVALID_INDEX; // LCOV_EXCL_LINE
381+
return H3_NULL; // LCOV_EXCL_LINE
382382
}
383383
}
384384
}
@@ -693,7 +693,7 @@ void H3_EXPORT(polyfill)(const GeoPolygon* geoPolygon, int res, H3Index* out) {
693693
// LCOV_EXCL_START
694694
if (failure) {
695695
int numHexagons = H3_EXPORT(maxPolyfillSize)(geoPolygon, res);
696-
for (int i = 0; i < numHexagons; i++) out[i] = H3_INVALID_INDEX;
696+
for (int i = 0; i < numHexagons; i++) out[i] = H3_NULL;
697697
}
698698
// LCOV_EXCL_STOP
699699
}
@@ -865,7 +865,7 @@ int _polyfillInternal(const GeoPolygon* geoPolygon, int res, H3Index* out) {
865865
H3Index searchHex = search[i];
866866
H3_EXPORT(kRing)(searchHex, 1, ring);
867867
for (int j = 0; j < MAX_ONE_RING_SIZE; j++) {
868-
if (ring[j] == H3_INVALID_INDEX) {
868+
if (ring[j] == H3_NULL) {
869869
continue; // Skip if this was a pentagon and only had 5
870870
// neighbors
871871
}

src/h3lib/lib/h3Index.c

Lines changed: 19 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -51,11 +51,12 @@ int H3_EXPORT(h3GetBaseCell)(H3Index h) { return H3_GET_BASE_CELL(h); }
5151
/**
5252
* Converts a string representation of an H3 index into an H3 index.
5353
* @param str The string representation of an H3 index.
54-
* @return The H3 index corresponding to the string argument, or 0 if invalid.
54+
* @return The H3 index corresponding to the string argument, or H3_NULL if
55+
* invalid.
5556
*/
5657
H3Index H3_EXPORT(stringToH3)(const char* str) {
57-
H3Index h = H3_INVALID_INDEX;
58-
// If failed, h will be unmodified and we should return 0 anyways.
58+
H3Index h = H3_NULL;
59+
// If failed, h will be unmodified and we should return H3_NULL anyways.
5960
sscanf(str, "%" PRIx64, &h);
6061
return h;
6162
}
@@ -138,16 +139,16 @@ void setH3Index(H3Index* hp, int res, int baseCell, Direction initDigit) {
138139
* @param h H3Index to find parent of
139140
* @param parentRes The resolution to switch to (parent, grandparent, etc)
140141
*
141-
* @return H3Index of the parent, or 0 if you actually asked for a child
142+
* @return H3Index of the parent, or H3_NULL if you actually asked for a child
142143
*/
143144
H3Index H3_EXPORT(h3ToParent)(H3Index h, int parentRes) {
144145
int childRes = H3_GET_RESOLUTION(h);
145146
if (parentRes > childRes) {
146-
return H3_INVALID_INDEX;
147+
return H3_NULL;
147148
} else if (parentRes == childRes) {
148149
return h;
149150
} else if (parentRes < 0 || parentRes > MAX_H3_RES) {
150-
return H3_INVALID_INDEX;
151+
return H3_NULL;
151152
}
152153
H3Index parentH = H3_SET_RESOLUTION(h, parentRes);
153154
for (int i = parentRes + 1; i <= childRes; i++) {
@@ -231,7 +232,7 @@ void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
231232
if (isAPentagon && i == K_AXES_DIGIT) {
232233
H3Index* nextChild = children + bufferChildStep;
233234
while (children < nextChild) {
234-
*children = H3_INVALID_INDEX;
235+
*children = H3_NULL;
235236
children++;
236237
}
237238
} else {
@@ -248,12 +249,13 @@ void H3_EXPORT(h3ToChildren)(H3Index h, int childRes, H3Index* children) {
248249
* @param h H3Index to find center child of
249250
* @param childRes The resolution to switch to
250251
*
251-
* @return H3Index of the center child, or 0 if you actually asked for a parent
252+
* @return H3Index of the center child, or H3_NULL if you actually asked for a
253+
* parent
252254
*/
253255
H3Index H3_EXPORT(h3ToCenterChild)(H3Index h, int childRes) {
254256
int parentRes = H3_GET_RESOLUTION(h);
255257
if (!_isValidChildRes(parentRes, childRes)) {
256-
return H3_INVALID_INDEX;
258+
return H3_NULL;
257259
} else if (childRes == parentRes) {
258260
return h;
259261
}
@@ -343,7 +345,7 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
343345
return COMPACT_DUPLICATE;
344346
}
345347
H3_SET_RESERVED_BITS(parent, count);
346-
hashSetArray[loc] = H3_INVALID_INDEX;
348+
hashSetArray[loc] = H3_NULL;
347349
} else {
348350
loc = (loc + 1) % numRemainingHexes;
349351
}
@@ -394,7 +396,7 @@ int H3_EXPORT(compact)(const H3Index* h3Set, H3Index* compactedSet,
394396
int uncompactableCount = 0;
395397
for (int i = 0; i < numRemainingHexes; i++) {
396398
H3Index currIndex = remainingHexes[i];
397-
if (currIndex != H3_INVALID_INDEX) {
399+
if (currIndex != H3_NULL) {
398400
H3Index parent = H3_EXPORT(h3ToParent)(currIndex, parentRes);
399401
// Modulus hash the parent into the temp array
400402
// to determine if this index was included in
@@ -634,7 +636,7 @@ H3Index _h3Rotate60cw(H3Index h) {
634636
* Convert an FaceIJK address to the corresponding H3Index.
635637
* @param fijk The FaceIJK address.
636638
* @param res The cell resolution.
637-
* @return The encoded H3Index (or 0 on failure).
639+
* @return The encoded H3Index (or H3_NULL on failure).
638640
*/
639641
H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
640642
// initialize the index
@@ -647,7 +649,7 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
647649
if (fijk->coord.i > MAX_FACE_COORD || fijk->coord.j > MAX_FACE_COORD ||
648650
fijk->coord.k > MAX_FACE_COORD) {
649651
// out of range input
650-
return H3_INVALID_INDEX;
652+
return H3_NULL;
651653
}
652654

653655
H3_SET_BASE_CELL(h, _faceIjkToBaseCell(fijk));
@@ -691,7 +693,7 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
691693
if (fijkBC.coord.i > MAX_FACE_COORD || fijkBC.coord.j > MAX_FACE_COORD ||
692694
fijkBC.coord.k > MAX_FACE_COORD) {
693695
// out of range input
694-
return H3_INVALID_INDEX;
696+
return H3_NULL;
695697
}
696698

697699
// lookup the correct base cell
@@ -730,14 +732,14 @@ H3Index _faceIjkToH3(const FaceIJK* fijk, int res) {
730732
*
731733
* @param g The spherical coordinates to encode.
732734
* @param res The desired H3 resolution for the encoding.
733-
* @return The encoded H3Index (or 0 on failure).
735+
* @return The encoded H3Index (or H3_NULL on failure).
734736
*/
735737
H3Index H3_EXPORT(geoToH3)(const GeoCoord* g, int res) {
736738
if (res < 0 || res > MAX_H3_RES) {
737-
return H3_INVALID_INDEX;
739+
return H3_NULL;
738740
}
739741
if (!isfinite(g->lat) || !isfinite(g->lon)) {
740-
return H3_INVALID_INDEX;
742+
return H3_NULL;
741743
}
742744

743745
FaceIJK fijk;

0 commit comments

Comments
 (0)