Skip to content

Commit

Permalink
Add error returns to average area functions, etc (#550)
Browse files Browse the repository at this point in the history
* Add DECLSPEC to distance functions
  • Loading branch information
isaacbrodsky authored Jan 3, 2022
1 parent cd47015 commit efad372
Show file tree
Hide file tree
Showing 13 changed files with 197 additions and 76 deletions.
2 changes: 1 addition & 1 deletion src/apps/testapps/testBaseCells.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ SUITE(baseCells) {
TEST(getRes0Cells) {
int count = H3_EXPORT(res0CellCount)();
H3Index* indexes = malloc(count * sizeof(H3Index));
H3_EXPORT(getRes0Cells)(indexes);
t_assertSuccess(H3_EXPORT(getRes0Cells)(indexes));
t_assert(indexes[0] == 0x8001fffffffffff, "correct first basecell");
t_assert(indexes[121] == 0x80f3fffffffffff, "correct last basecell");
free(indexes);
Expand Down
36 changes: 24 additions & 12 deletions src/apps/testapps/testDirectedEdge.c
Original file line number Diff line number Diff line change
Expand Up @@ -37,13 +37,18 @@ SUITE(directedEdge) {
H3Index ring[7] = {0};
t_assertSuccess(H3_EXPORT(gridRingUnsafe)(sf, 1, ring));

t_assert(H3_EXPORT(areNeighborCells)(sf, sf) == 0,
"an index does not neighbor itself");
int isNeighbor;
t_assertSuccess(H3_EXPORT(areNeighborCells)(sf, sf, &isNeighbor));
t_assert(!isNeighbor, "an index does not neighbor itself");

int neighbors = 0;
for (int i = 0; i < H3_EXPORT(maxGridDiskSize)(1); i++) {
if (ring[i] != 0 && H3_EXPORT(areNeighborCells)(sf, ring[i])) {
neighbors++;
if (ring[i] != 0) {
t_assertSuccess(
H3_EXPORT(areNeighborCells)(sf, ring[i], &isNeighbor));
if (isNeighbor) {
neighbors++;
}
}
}
t_assert(neighbors == 6,
Expand All @@ -54,28 +59,35 @@ SUITE(directedEdge) {

neighbors = 0;
for (int i = 0; i < H3_EXPORT(maxGridDiskSize)(2); i++) {
if (largerRing[i] != 0 &&
H3_EXPORT(areNeighborCells)(sf, largerRing[i])) {
neighbors++;
if (largerRing[i] != 0) {
t_assertSuccess(H3_EXPORT(areNeighborCells)(sf, largerRing[i],
&isNeighbor));
if (isNeighbor) {
neighbors++;
}
}
}
t_assert(neighbors == 0,
"got no neighbors, as expected, from a k-ring of 2");

H3Index sfBroken = sf;
H3_SET_MODE(sfBroken, H3_DIRECTEDEDGE_MODE);
t_assert(H3_EXPORT(areNeighborCells)(sf, sfBroken) == 0,
t_assert(H3_EXPORT(areNeighborCells)(sf, sfBroken, &isNeighbor) ==
E_CELL_INVALID,
"broken H3Indexes can't be neighbors");
t_assert(H3_EXPORT(areNeighborCells)(sfBroken, sf) == 0,
t_assert(H3_EXPORT(areNeighborCells)(sfBroken, sf, &isNeighbor) ==
E_CELL_INVALID,
"broken H3Indexes can't be neighbors (reversed)");

H3Index sfBigger;
t_assertSuccess(H3_EXPORT(latLngToCell)(&sfGeo, 7, &sfBigger));
t_assert(H3_EXPORT(areNeighborCells)(sf, sfBigger) == 0,
t_assert(H3_EXPORT(areNeighborCells)(sf, sfBigger, &isNeighbor) ==
E_RES_MISMATCH,
"hexagons of different resolution can't be neighbors");

t_assert(H3_EXPORT(areNeighborCells)(ring[2], ring[1]) == 1,
"hexagons in a ring are neighbors");
t_assertSuccess(
H3_EXPORT(areNeighborCells)(ring[2], ring[1], &isNeighbor));
t_assert(isNeighbor, "hexagons in a ring are neighbors");
}

TEST(cellsToDirectedEdgeAndFriends) {
Expand Down
6 changes: 4 additions & 2 deletions src/apps/testapps/testDirectedEdgeExhaustive.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,8 +50,10 @@ static void directedEdge_correctness_assertions(H3Index h3) {
H3Index destination;
t_assertSuccess(
H3_EXPORT(getDirectedEdgeDestination)(edges[i], &destination));
t_assert(H3_EXPORT(areNeighborCells)(h3, destination),
"destination is a neighbor");
int isNeighbor;
t_assertSuccess(
H3_EXPORT(areNeighborCells)(h3, destination, &isNeighbor));
t_assert(isNeighbor, "destination is a neighbor");
}
}

Expand Down
10 changes: 7 additions & 3 deletions src/apps/testapps/testGridPathCellsExhaustive.c
Original file line number Diff line number Diff line change
Expand Up @@ -48,11 +48,15 @@ static void gridPathCells_assertions(H3Index start, H3Index end) {

for (int i = 1; i < sz; i++) {
t_assert(H3_EXPORT(isValidCell)(line[i]), "index is valid");
t_assert(H3_EXPORT(areNeighborCells)(line[i], line[i - 1]),
"index is a neighbor of the previous index");
int isNeighbor;
t_assertSuccess(
H3_EXPORT(areNeighborCells)(line[i], line[i - 1], &isNeighbor));
t_assert(isNeighbor, "index is a neighbor of the previous index");
if (i > 1) {
t_assertSuccess(
H3_EXPORT(areNeighborCells)(line[i], line[i - 2], &isNeighbor));
t_assert(
!H3_EXPORT(areNeighborCells)(line[i], line[i - 2]),
!isNeighbor,
"index is not a neighbor of the index before the previous");
}
}
Expand Down
14 changes: 13 additions & 1 deletion src/apps/testapps/testH3CellArea.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,22 @@ SUITE(h3CellArea) {
for (int res = 0; res <= MAX_H3_RES - 1; res++) {
H3Index cell;
t_assertSuccess(H3_EXPORT(latLngToCell)(&gc, res, &cell));
double area = H3_EXPORT(cellAreaKm2)(cell);
double area;
t_assertSuccess(H3_EXPORT(cellAreaKm2)(cell, &area));

t_assert(fabs(area - areasKm2[res]) < 1e-8,
"cell area should match expectation");
}
}

TEST(cell_area_invalid) {
H3Index invalid = 0xFFFFFFFFFFFFFFFF;
double area;
t_assert(H3_EXPORT(cellAreaRads2)(invalid, &area) == E_CELL_INVALID,
"cellAreaRads2 invalid input");
t_assert(H3_EXPORT(cellAreaKm2)(invalid, &area) == E_CELL_INVALID,
"cellAreaKm2 invalid input");
t_assert(H3_EXPORT(cellAreaM2)(invalid, &area) == E_CELL_INVALID,
"cellAreaM2 invalid input");
}
}
21 changes: 16 additions & 5 deletions src/apps/testapps/testH3CellAreaExhaustive.c
Original file line number Diff line number Diff line change
Expand Up @@ -109,9 +109,18 @@ static void edge_length_assert(H3Index edge) {
static void cell_area_assert(H3Index cell) {
char msg[] = "cell has positive area";

t_assert(H3_EXPORT(cellAreaRads2)(cell) > 0, msg);
t_assert(H3_EXPORT(cellAreaKm2)(cell) > 0, msg);
t_assert(H3_EXPORT(cellAreaM2)(cell) > 0, msg);
double areaRads;
t_assertSuccess(H3_EXPORT(cellAreaRads2)(cell, &areaRads));
t_assert(areaRads > 0, msg);
double areaKm2;
t_assertSuccess(H3_EXPORT(cellAreaKm2)(cell, &areaKm2));
t_assert(areaKm2 > 0, msg);
double areaM2;
t_assertSuccess(H3_EXPORT(cellAreaM2)(cell, &areaM2));
t_assert(areaM2 > 0, msg);

t_assert(areaRads < areaKm2, "area in rads smaller than area in km2");
t_assert(areaKm2 < areaM2, "area in km2 smaller than area in m2");
}

/**
Expand All @@ -123,12 +132,14 @@ static void cell_area_assert(H3Index cell) {
* @param target expected earth area in some units
* @param tol error tolerance allowed between expected and actual
*/
static void earth_area_test(int res, double (*cell_area)(H3Index),
static void earth_area_test(int res, H3Error (*cell_area)(H3Index, double *),
double target, double tol) {
double area = 0.0;
for (IterCellsResolution iter = iterInitRes(res); iter.h;
iterStepRes(&iter)) {
area += (*cell_area)(iter.h);
double cellArea;
t_assertSuccess((*cell_area)(iter.h, &cellArea));
area += cellArea;
}

t_assert(fabs(area - target) < tol,
Expand Down
3 changes: 2 additions & 1 deletion src/apps/testapps/testH3Iterators.c
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,8 @@ static void test_number(int res) {
count++;
}

int64_t expected = H3_EXPORT(getNumCells)(res);
int64_t expected;
t_assertSuccess(H3_EXPORT(getNumCells)(res, &expected));

t_assert(count == expected,
"expect the correct number of cells from the iterator");
Expand Down
37 changes: 33 additions & 4 deletions src/apps/testapps/testLatLng.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,12 +35,12 @@
* @param function
* @param message
*/
static void testDecreasingFunction(double (*function)(int),
static void testDecreasingFunction(H3Error (*function)(int, double *),
const char *message) {
double last = 0;
double next;
for (int i = MAX_H3_RES; i >= 0; i--) {
next = function(i);
t_assertSuccess(function(i, &next));
t_assert(next > last, message);
last = next;
}
Expand Down Expand Up @@ -219,17 +219,45 @@ SUITE(latLng) {
"getHexagonEdgeLengthAvgM ordering");
}

TEST(doubleConstantsErrors) {
double out;
t_assert(H3_EXPORT(getHexagonAreaAvgKm2)(-1, &out) == E_RES_DOMAIN,
"getHexagonAreaAvgKm2 resolution negative");
t_assert(H3_EXPORT(getHexagonAreaAvgKm2)(16, &out) == E_RES_DOMAIN,
"getHexagonAreaAvgKm2 resolution too high");
t_assert(H3_EXPORT(getHexagonAreaAvgM2)(-1, &out) == E_RES_DOMAIN,
"getHexagonAreaAvgM2 resolution negative");
t_assert(H3_EXPORT(getHexagonAreaAvgM2)(16, &out) == E_RES_DOMAIN,
"getHexagonAreaAvgM2 resolution too high");
t_assert(H3_EXPORT(getHexagonEdgeLengthAvgKm)(-1, &out) == E_RES_DOMAIN,
"getHexagonEdgeLengthAvgKm resolution negative");
t_assert(H3_EXPORT(getHexagonEdgeLengthAvgKm)(16, &out) == E_RES_DOMAIN,
"getHexagonEdgeLengthAvgKm resolution too high");
t_assert(H3_EXPORT(getHexagonEdgeLengthAvgM)(-1, &out) == E_RES_DOMAIN,
"getHexagonEdgeLengthAvgM resolution negative");
t_assert(H3_EXPORT(getHexagonEdgeLengthAvgM)(16, &out) == E_RES_DOMAIN,
"getHexagonEdgeLengthAvgM resolution too high");
}

TEST(intConstants) {
// Simple checks for ordering of values
int64_t last = 0;
int64_t next;
for (int i = 0; i <= MAX_H3_RES; i++) {
next = H3_EXPORT(getNumCells)(i);
t_assertSuccess(H3_EXPORT(getNumCells)(i, &next));
t_assert(next > last, "getNumCells ordering");
last = next;
}
}

TEST(intConstantsErrors) {
int64_t out;
t_assert(H3_EXPORT(getNumCells)(-1, &out) == E_RES_DOMAIN,
"getNumCells resolution negative");
t_assert(H3_EXPORT(getNumCells)(16, &out) == E_RES_DOMAIN,
"getNumCells resolution too high");
}

TEST(numHexagons) {
// Test numHexagon counts of the number of *cells* at each resolution
static const int64_t expected[] = {122L,
Expand All @@ -250,7 +278,8 @@ SUITE(latLng) {
569707381193162L};

for (int r = 0; r <= MAX_H3_RES; r++) {
int64_t num = H3_EXPORT(getNumCells)(r);
int64_t num;
t_assertSuccess(H3_EXPORT(getNumCells)(r, &num));
t_assert(num == expected[r], "incorrect numHexagons count");
}
}
Expand Down
5 changes: 3 additions & 2 deletions src/apps/testapps/testPolygonToCellsReported.c
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,9 @@ SUITE(polygonToCells_reported) {
int64_t actualNumIndexes2 =
countNonNullIndexes(polygonToCellsOut2, polygonToCellsSize2);

t_assert(actualNumIndexes + actualNumIndexes2 ==
H3_EXPORT(getNumCells)(res),
int64_t expectedTotalWorld;
t_assertSuccess(H3_EXPORT(getNumCells)(res, &expectedTotalWorld));
t_assert(actualNumIndexes + actualNumIndexes2 == expectedTotalWorld,
"got expected polygonToCells size (entire world)");

// Sets should be disjoint
Expand Down
33 changes: 17 additions & 16 deletions src/h3lib/include/h3api.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -316,65 +316,65 @@ DECLSPEC double H3_EXPORT(radsToDegs)(double radians);
* @{
*/
/** @brief "great circle distance" between pairs of LatLng points in radians*/
double H3_EXPORT(distanceRads)(const LatLng *a, const LatLng *b);
DECLSPEC double H3_EXPORT(distanceRads)(const LatLng *a, const LatLng *b);

/** @brief "great circle distance" between pairs of LatLng points in
* kilometers*/
double H3_EXPORT(distanceKm)(const LatLng *a, const LatLng *b);
DECLSPEC double H3_EXPORT(distanceKm)(const LatLng *a, const LatLng *b);

/** @brief "great circle distance" between pairs of LatLng points in meters*/
double H3_EXPORT(distanceM)(const LatLng *a, const LatLng *b);
DECLSPEC double H3_EXPORT(distanceM)(const LatLng *a, const LatLng *b);
/** @} */

/** @defgroup getHexagonAreaAvg getHexagonAreaAvg
* Functions for getHexagonAreaAvg
* @{
*/
/** @brief average hexagon area in square kilometers (excludes pentagons) */
DECLSPEC double H3_EXPORT(getHexagonAreaAvgKm2)(int res);
DECLSPEC H3Error H3_EXPORT(getHexagonAreaAvgKm2)(int res, double *out);

/** @brief average hexagon area in square meters (excludes pentagons) */
DECLSPEC double H3_EXPORT(getHexagonAreaAvgM2)(int res);
DECLSPEC H3Error H3_EXPORT(getHexagonAreaAvgM2)(int res, double *out);
/** @} */

/** @defgroup cellArea cellArea
* Functions for cellArea
* @{
*/
/** @brief exact area for a specific cell (hexagon or pentagon) in radians^2 */
double H3_EXPORT(cellAreaRads2)(H3Index h);
DECLSPEC H3Error H3_EXPORT(cellAreaRads2)(H3Index h, double *out);

/** @brief exact area for a specific cell (hexagon or pentagon) in kilometers^2
*/
double H3_EXPORT(cellAreaKm2)(H3Index h);
DECLSPEC H3Error H3_EXPORT(cellAreaKm2)(H3Index h, double *out);

/** @brief exact area for a specific cell (hexagon or pentagon) in meters^2 */
double H3_EXPORT(cellAreaM2)(H3Index h);
DECLSPEC H3Error H3_EXPORT(cellAreaM2)(H3Index h, double *out);
/** @} */

/** @defgroup getHexagonEdgeLengthAvg getHexagonEdgeLengthAvg
* Functions for getHexagonEdgeLengthAvg
* @{
*/
/** @brief average hexagon edge length in kilometers (excludes pentagons) */
DECLSPEC double H3_EXPORT(getHexagonEdgeLengthAvgKm)(int res);
DECLSPEC H3Error H3_EXPORT(getHexagonEdgeLengthAvgKm)(int res, double *out);

/** @brief average hexagon edge length in meters (excludes pentagons) */
DECLSPEC double H3_EXPORT(getHexagonEdgeLengthAvgM)(int res);
DECLSPEC H3Error H3_EXPORT(getHexagonEdgeLengthAvgM)(int res, double *out);
/** @} */

/** @defgroup exactEdgeLength exactEdgeLength
* Functions for exactEdgeLength
* @{
*/
/** @brief exact length for a specific directed edge in radians*/
H3Error H3_EXPORT(exactEdgeLengthRads)(H3Index edge, double *length);
DECLSPEC H3Error H3_EXPORT(exactEdgeLengthRads)(H3Index edge, double *length);

/** @brief exact length for a specific directed edge in kilometers*/
H3Error H3_EXPORT(exactEdgeLengthKm)(H3Index edge, double *length);
DECLSPEC H3Error H3_EXPORT(exactEdgeLengthKm)(H3Index edge, double *length);

/** @brief exact length for a specific directed edge in meters*/
H3Error H3_EXPORT(exactEdgeLengthM)(H3Index edge, double *length);
DECLSPEC H3Error H3_EXPORT(exactEdgeLengthM)(H3Index edge, double *length);
/** @} */

/** @defgroup getNumCells getNumCells
Expand Down Expand Up @@ -423,7 +423,7 @@ H3Error H3_EXPORT(exactEdgeLengthM)(H3Index edge, double *length);
*
* @return number of cells at resolution `res`
*/
DECLSPEC int64_t H3_EXPORT(getNumCells)(int res);
DECLSPEC H3Error H3_EXPORT(getNumCells)(int res, int64_t *out);
/** @} */

/** @defgroup getRes0Cells getRes0Cells
Expand All @@ -434,7 +434,7 @@ DECLSPEC int64_t H3_EXPORT(getNumCells)(int res);
DECLSPEC int H3_EXPORT(res0CellCount)();

/** @brief provides all base cells in H3Index format*/
DECLSPEC void H3_EXPORT(getRes0Cells)(H3Index *out);
DECLSPEC H3Error H3_EXPORT(getRes0Cells)(H3Index *out);
/** @} */

/** @defgroup getPentagons getPentagons
Expand Down Expand Up @@ -586,7 +586,8 @@ DECLSPEC H3Error H3_EXPORT(getIcosahedronFaces)(H3Index h3, int *out);
* @{
*/
/** @brief returns whether or not the provided hexagons border */
DECLSPEC int H3_EXPORT(areNeighborCells)(H3Index origin, H3Index destination);
DECLSPEC H3Error H3_EXPORT(areNeighborCells)(H3Index origin,
H3Index destination, int *out);
/** @} */

/** @defgroup cellsToDirectedEdge cellsToDirectedEdge
Expand Down
4 changes: 3 additions & 1 deletion src/h3lib/lib/baseCells.c
Original file line number Diff line number Diff line change
Expand Up @@ -926,12 +926,14 @@ int H3_EXPORT(res0CellCount)() { return NUM_BASE_CELLS; }
* memory pointer. Buffer must be of size NUM_BASE_CELLS * sizeof(H3Index).
*
* @param out H3Index* the memory to store the resulting base cells in
* @returns E_SUCCESS.
*/
void H3_EXPORT(getRes0Cells)(H3Index *out) {
H3Error H3_EXPORT(getRes0Cells)(H3Index *out) {
for (int bc = 0; bc < NUM_BASE_CELLS; bc++) {
H3Index baseCell = H3_INIT;
H3_SET_MODE(baseCell, H3_CELL_MODE);
H3_SET_BASE_CELL(baseCell, bc);
out[bc] = baseCell;
}
return E_SUCCESS;
}
Loading

0 comments on commit efad372

Please sign in to comment.