Skip to content

Commit

Permalink
Add fix for false positive on bad polygon point, plus more tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Nick Rabinowitz committed Feb 12, 2024
1 parent b57df8b commit b2463b6
Show file tree
Hide file tree
Showing 3 changed files with 259 additions and 94 deletions.
26 changes: 0 additions & 26 deletions src/apps/testapps/testPolyfillInternal.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,14 +36,6 @@ static GeoPolygon sfGeoPolygon = {
{0.6599990002976, -2.1376771158464}}},
.numHoles = 0};

static GeoPolygon invalidGeoPolygon = {
.geoloop = {.numVerts = 4,
.verts = (LatLng[]){{NAN, -2.1364398519396},
{0.6595011102219, NAN},
{NAN, -2.1354884206045},
{0.6581220034068, NAN}}},
.numHoles = 0};

SUITE(polyfillInternal) {
TEST(iterInitPolygonCompact_errors) {
IterCellsPolygonCompact iter;
Expand Down Expand Up @@ -142,24 +134,6 @@ SUITE(polyfillInternal) {
t_assert(iter.cell == H3_NULL, "Got null output for invalid cell");
}

TEST(iterStepPolygonCompact_invalidPolygonErrors) {
IterCellsPolygonCompact iter;

// Start with a good polygon, otherwise we error out early
iter =
iterInitPolygonCompact(&sfGeoPolygon, 5, CONTAINMENT_OVERLAPPING);
t_assertSuccess(iter.error);

// Give the iterator a bad polygon and a cell at target res
iter._polygon = &invalidGeoPolygon;
iter.cell = 0x85283473fffffff;

iterStepPolygonCompact(&iter);
t_assert(iter.error == E_LATLNG_DOMAIN,
"Got expected error for invalid polygon");
t_assert(iter.cell == H3_NULL, "Got null output for invalid cell");
}

TEST(iterDestroyPolygonCompact) {
IterCellsPolygonCompact iter =
iterInitPolygonCompact(&sfGeoPolygon, 9, CONTAINMENT_CENTER);
Expand Down
252 changes: 219 additions & 33 deletions src/apps/testapps/testPolygonToCellsExperimental.c
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,11 @@ static LatLng invalidVerts[] = {{INFINITY, INFINITY}, {-INFINITY, -INFINITY}};
static GeoLoop invalidGeoLoop = {.numVerts = 2, .verts = invalidVerts};
static GeoPolygon invalidGeoPolygon;

static LatLng outOfBoundsVert[] = {{-2000, -2000}};
static GeoLoop outOfBoundsVertGeoLoop = {.numVerts = 1,
.verts = outOfBoundsVert};
static GeoPolygon outOfBoundsVertGeoPolygon;

static LatLng invalid2Verts[] = {{NAN, NAN}, {-NAN, -NAN}};
static GeoLoop invalid2GeoLoop = {.numVerts = 2, .verts = invalid2Verts};
static GeoPolygon invalid2GeoPolygon;
Expand Down Expand Up @@ -173,6 +178,9 @@ SUITE(polygonToCells) {
invalid2GeoPolygon.geoloop = invalid2GeoLoop;
invalid2GeoPolygon.numHoles = 0;

outOfBoundsVertGeoPolygon.geoloop = outOfBoundsVertGeoLoop;
outOfBoundsVertGeoPolygon.numHoles = 0;

nullGeoPolygon.geoloop = nullGeoLoop;
nullGeoPolygon.numHoles = 0;

Expand Down Expand Up @@ -226,6 +234,21 @@ SUITE(polygonToCells) {
free(hexagons);
}

TEST(polygonToCells_OverlappingBBox) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&sfGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, &numHexagons));
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&sfGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes == 1416,
"got expected polygonToCells size (overlapping bbox mode)");
free(hexagons);
}

TEST(polygonToCellsHole) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
Expand Down Expand Up @@ -272,6 +295,22 @@ SUITE(polygonToCells) {
free(hexagons);
}

TEST(polygonToCellsHoleOverlappingBBox) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&holeGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, &numHexagons));
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&holeGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);

t_assert(
actualNumIndexes == 1403,
"got expected polygonToCells size (hole, overlapping bbox mode)");
free(hexagons);
}

TEST(polygonToCellsHoleParentIssue) {
// This checks a specific issue where the bounding box of the parent
// cell fully contains the hole.
Expand Down Expand Up @@ -398,6 +437,22 @@ SUITE(polygonToCells) {
free(hexagons);
}

TEST(polygonToCellsContainsPolygon_OverlappingBBox) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&sfGeoPolygon, 4, CONTAINMENT_OVERLAPPING_BBOX, &numHexagons));
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&sfGeoPolygon, 4, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes == 5,
"got expected polygonToCells size (overlapping bbox mode)");
t_assert(hexagons[0] == 0x8428309ffffffff, "got expected hexagon");
free(hexagons);
}

TEST(polygonToCellsExact) {
LatLng somewhere = {1, 2};
H3Index origin;
Expand Down Expand Up @@ -440,6 +495,15 @@ SUITE(polygonToCells) {
// TODO: CONTAINMENT_OVERLAPPING yields 7 cells, presumably due to FPE
// in the various cell boundaries

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&someHexagon, 9, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);
// Overlapping BBox is very rough, so we get a couple of overlaps from
// non-neighboring cells
t_assert(actualNumIndexes == 9,
"got expected polygonToCells size for overlapping bbox "
"containment");

free(hexagons);
free(verts);
}
Expand Down Expand Up @@ -643,48 +707,105 @@ SUITE(polygonToCells) {
}

TEST(polygonToCellsPointPolygon) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&pointGeoPolygon, 9, CONTAINMENT_CENTER, &numHexagons));
t_assert(numHexagons == 1, "got expected estimated size");
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&pointGeoPolygon, 9, CONTAINMENT_CENTER, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes == 0, "got expected polygonToCells size");
free(hexagons);
for (int res = 0; res < MAX_H3_RES; res++) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&pointGeoPolygon, res, CONTAINMENT_CENTER, &numHexagons));
t_assert(numHexagons >= 1 && numHexagons <= 5,
"got expected estimated size");
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&pointGeoPolygon, res, CONTAINMENT_CENTER, hexagons));
int64_t actualNumIndexes =
countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes == 0, "got expected polygonToCells size");
free(hexagons);
}
}

TEST(polygonToCellsPointPolygon_full) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&pointGeoPolygon, 9, CONTAINMENT_FULL, &numHexagons));
t_assert(numHexagons == 1, "got expected estimated size");
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));
for (int res = 0; res < MAX_H3_RES; res++) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&pointGeoPolygon, res, CONTAINMENT_FULL, &numHexagons));
t_assert(numHexagons >= 1 && numHexagons <= 5,
"got expected estimated size");
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&pointGeoPolygon, res, CONTAINMENT_FULL, hexagons));
int64_t actualNumIndexes =
countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes == 0, "got expected polygonToCells size");
free(hexagons);
}
}

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&pointGeoPolygon, 9, CONTAINMENT_FULL, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);
TEST(polygonToCellsPointPolygon_overlapping) {
for (int res = 0; res < MAX_H3_RES; res++) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&pointGeoPolygon, res, CONTAINMENT_OVERLAPPING, &numHexagons));
t_assert(numHexagons >= 1 && numHexagons <= 5,
"got expected estimated size");
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&pointGeoPolygon, res, CONTAINMENT_OVERLAPPING, hexagons));
int64_t actualNumIndexes =
countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes == 1, "got expected polygonToCells size");
free(hexagons);
}
}

t_assert(actualNumIndexes == 0, "got expected polygonToCells size");
free(hexagons);
TEST(polygonToCellsPointPolygon_overlappingBBox) {
for (int res = 0; res < MAX_H3_RES; res++) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&pointGeoPolygon, res, CONTAINMENT_OVERLAPPING_BBOX,
&numHexagons));
t_assert(numHexagons >= 1 && numHexagons <= 5,
"got expected estimated size");
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&pointGeoPolygon, res, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
int64_t actualNumIndexes =
countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes >= 1 && actualNumIndexes <= 5,
"got expected polygonToCells size");
free(hexagons);
}
}

TEST(polygonToCellsPointPolygon_overlapping) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&pointGeoPolygon, 9, CONTAINMENT_OVERLAPPING, &numHexagons));
t_assert(numHexagons == 1, "got expected estimated size");
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));
TEST(polygonToCellsOutOfBoundsPolygon) {
for (int res = 0; res < MAX_H3_RES; res++) {
for (uint32_t flags = 0; flags < CONTAINMENT_INVALID; flags++) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&outOfBoundsVertGeoPolygon, res, flags, &numHexagons));
t_assert(numHexagons == 0, "got expected estimated size");
// Note: We're allocating more memory than the estimate to test
// for out-of-bounds writes here
H3Index *hexagons = calloc(10, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&pointGeoPolygon, 9, CONTAINMENT_OVERLAPPING, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);
t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&outOfBoundsVertGeoPolygon, res, flags, hexagons));
int64_t actualNumIndexes =
countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes == 1, "got expected polygonToCells size");
free(hexagons);
h3Println(hexagons[0]);
t_assert(actualNumIndexes == 0,
"got expected polygonToCells size");
free(hexagons);
}
}
}

TEST(polygonToCellsLinePolygon) {
Expand Down Expand Up @@ -729,6 +850,20 @@ SUITE(polygonToCells) {
free(hexagons);
}

TEST(polygonToCellsLinePolygon_overlappingBBox) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&lineGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, &numHexagons));
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&lineGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);

t_assert(actualNumIndexes == 21, "got expected polygonToCells size");
free(hexagons);
}

TEST(polygonToCellsNullHole) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
Expand Down Expand Up @@ -777,6 +912,23 @@ SUITE(polygonToCells) {
free(hexagons);
}

TEST(polygonToCellsNullHole_overlappingBBox) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&nullHoleGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX,
&numHexagons));
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&nullHoleGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);

// Same as without the hole
t_assert(actualNumIndexes == 1416,
"got expected polygonToCells size (null hole)");
free(hexagons);
}

TEST(polygonToCellsPointHole) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
Expand Down Expand Up @@ -825,6 +977,23 @@ SUITE(polygonToCells) {
free(hexagons);
}

TEST(polygonToCellsPointHole_overlappingBBox) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&pointHoleGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX,
&numHexagons));
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&pointHoleGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);

// Same as without the hole
t_assert(actualNumIndexes == 1416,
"got expected polygonToCells size (point hole)");
free(hexagons);
}

TEST(polygonToCellsLineHole) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
Expand Down Expand Up @@ -873,6 +1042,23 @@ SUITE(polygonToCells) {
free(hexagons);
}

TEST(polygonToCellsLineHole_overlappingBBox) {
int64_t numHexagons;
t_assertSuccess(H3_EXPORT(maxPolygonToCellsSizeExperimental)(
&lineHoleGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX,
&numHexagons));
H3Index *hexagons = calloc(numHexagons, sizeof(H3Index));

t_assertSuccess(H3_EXPORT(polygonToCellsExperimental)(
&lineHoleGeoPolygon, 9, CONTAINMENT_OVERLAPPING_BBOX, hexagons));
int64_t actualNumIndexes = countNonNullIndexes(hexagons, numHexagons);

// Same as without the hole
t_assert(actualNumIndexes == 1416,
"got expected polygonToCells size (line hole)");
free(hexagons);
}

TEST(invalidFlags) {
int64_t numHexagons;
for (uint32_t flags = CONTAINMENT_INVALID; flags <= 32; flags++) {
Expand Down
Loading

0 comments on commit b2463b6

Please sign in to comment.