-
Notifications
You must be signed in to change notification settings - Fork 450
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Fix for edge directions in getH3UnidirectionalEdgeBoundary #78
Changes from 4 commits
a25f18c
622f617
ee30ce6
e5b130e
e7001d9
2d93522
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,9 @@ | |
|
||
#include <stdlib.h> | ||
#include "constants.h" | ||
#include "geoCoord.h" | ||
#include "h3Index.h" | ||
#include "stackAlloc.h" | ||
#include "test.h" | ||
|
||
// Fixtures | ||
|
@@ -31,7 +33,7 @@ BEGIN_TESTS(h3UniEdge); | |
|
||
TEST(h3IndexesAreNeighbors) { | ||
H3Index sf = H3_EXPORT(geoToH3)(&sfGeo, 9); | ||
H3Index* ring = calloc(H3_EXPORT(maxKringSize)(1), sizeof(H3Index)); | ||
STACK_ARRAY_CALLOC(H3Index, ring, H3_EXPORT(maxKringSize)(1)); | ||
H3_EXPORT(hexRing)(sf, 1, ring); | ||
|
||
t_assert(H3_EXPORT(h3IndexesAreNeighbors)(sf, sf) == 0, | ||
|
@@ -46,7 +48,7 @@ TEST(h3IndexesAreNeighbors) { | |
t_assert(neighbors == 6, | ||
"got the expected number of neighbors from a k-ring of 1"); | ||
|
||
H3Index* largerRing = calloc(H3_EXPORT(maxKringSize)(2), sizeof(H3Index)); | ||
STACK_ARRAY_CALLOC(H3Index, largerRing, H3_EXPORT(maxKringSize)(2)); | ||
H3_EXPORT(hexRing)(sf, 2, largerRing); | ||
|
||
neighbors = 0; | ||
|
@@ -58,7 +60,6 @@ TEST(h3IndexesAreNeighbors) { | |
} | ||
t_assert(neighbors == 0, | ||
"got no neighbors, as expected, from a k-ring of 2"); | ||
free(largerRing); | ||
|
||
H3Index sfBroken = sf; | ||
H3_SET_MODE(sfBroken, H3_UNIEDGE_MODE); | ||
|
@@ -71,15 +72,13 @@ TEST(h3IndexesAreNeighbors) { | |
|
||
t_assert(H3_EXPORT(h3IndexesAreNeighbors)(ring[2], ring[1]) == 1, | ||
"hexagons in a ring are neighbors"); | ||
free(ring); | ||
} | ||
|
||
TEST(getH3UnidirectionalEdgeAndFriends) { | ||
H3Index sf = H3_EXPORT(geoToH3)(&sfGeo, 9); | ||
H3Index* ring = calloc(H3_EXPORT(maxKringSize)(1), sizeof(H3Index)); | ||
STACK_ARRAY_CALLOC(H3Index, ring, H3_EXPORT(maxKringSize)(1)); | ||
H3_EXPORT(hexRing)(sf, 1, ring); | ||
H3Index sf2 = ring[0]; | ||
free(ring); | ||
|
||
H3Index edge = H3_EXPORT(getH3UnidirectionalEdge)(sf, sf2); | ||
t_assert(sf == H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(edge), | ||
|
@@ -95,10 +94,9 @@ TEST(getH3UnidirectionalEdgeAndFriends) { | |
t_assert(originDestination[1] == sf2, | ||
"got the destination last in the pair request"); | ||
|
||
H3Index* largerRing = calloc(H3_EXPORT(maxKringSize)(2), sizeof(H3Index)); | ||
STACK_ARRAY_CALLOC(H3Index, largerRing, H3_EXPORT(maxKringSize)(2)); | ||
H3_EXPORT(hexRing)(sf, 2, largerRing); | ||
H3Index sf3 = largerRing[0]; | ||
free(largerRing); | ||
|
||
H3Index notEdge = H3_EXPORT(getH3UnidirectionalEdge)(sf, sf3); | ||
t_assert(notEdge == 0, "Non-neighbors can't have edges"); | ||
|
@@ -135,10 +133,9 @@ TEST(getH3UnidirectionalEdgeFromPentagon) { | |
|
||
TEST(h3UnidirectionalEdgeIsValid) { | ||
H3Index sf = H3_EXPORT(geoToH3)(&sfGeo, 9); | ||
H3Index* ring = calloc(H3_EXPORT(maxKringSize)(1), sizeof(H3Index)); | ||
STACK_ARRAY_CALLOC(H3Index, ring, H3_EXPORT(maxKringSize)(1)); | ||
H3_EXPORT(hexRing)(sf, 1, ring); | ||
H3Index sf2 = ring[0]; | ||
free(ring); | ||
|
||
H3Index edge = H3_EXPORT(getH3UnidirectionalEdge)(sf, sf2); | ||
t_assert(H3_EXPORT(h3UnidirectionalEdgeIsValid)(edge) == 1, | ||
|
@@ -166,7 +163,7 @@ TEST(h3UnidirectionalEdgeIsValid) { | |
|
||
TEST(getH3UnidirectionalEdgesFromHexagon) { | ||
H3Index sf = H3_EXPORT(geoToH3)(&sfGeo, 9); | ||
H3Index* edges = calloc(6, sizeof(H3Index)); | ||
STACK_ARRAY_CALLOC(H3Index, edges, 6); | ||
H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(sf, edges); | ||
|
||
for (int i = 0; i < 6; i++) { | ||
|
@@ -179,10 +176,11 @@ TEST(getH3UnidirectionalEdgesFromHexagon) { | |
edges[i]), | ||
"destination is not origin"); | ||
} | ||
free(edges); | ||
} | ||
|
||
TEST(getH3UnidirectionalEdgesFromPentagon) { | ||
H3Index pentagon = 0x821c07fffffffff; | ||
edges = calloc(6, sizeof(H3Index)); | ||
STACK_ARRAY_CALLOC(H3Index, edges, 6); | ||
H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(pentagon, edges); | ||
|
||
int missingEdgeCount = 0; | ||
|
@@ -196,47 +194,118 @@ TEST(getH3UnidirectionalEdgesFromHexagon) { | |
pentagon == | ||
H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(edges[i]), | ||
"origin is correct"); | ||
t_assert( | ||
sf != H3_EXPORT(getDestinationH3IndexFromUnidirectionalEdge)( | ||
edges[i]), | ||
"destination is not origin"); | ||
t_assert(pentagon != | ||
H3_EXPORT(getDestinationH3IndexFromUnidirectionalEdge)( | ||
edges[i]), | ||
"destination is not origin"); | ||
} | ||
} | ||
t_assert(missingEdgeCount == 1, | ||
"Only one edge was deleted for the pentagon"); | ||
free(edges); | ||
} | ||
|
||
TEST(getH3UnidirectionalEdgeBoundary) { | ||
H3Index sf = H3_EXPORT(geoToH3)(&sfGeo, 9); | ||
H3Index* edges = calloc(6, sizeof(H3Index)); | ||
H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(sf, edges); | ||
|
||
GeoBoundary gb; | ||
for (int i = 0; i < 6; i++) { | ||
H3_EXPORT(getH3UnidirectionalEdgeBoundary)(edges[i], &gb); | ||
t_assert(gb.numVerts == 2, "Got the expected number of vertices back"); | ||
H3Index sf; | ||
GeoBoundary boundary; | ||
GeoBoundary edgeBoundary; | ||
STACK_ARRAY_CALLOC(H3Index, edges, 6); | ||
|
||
const int expectedVertices[][2] = {{3, 4}, {1, 2}, {2, 3}, | ||
{5, 0}, {4, 5}, {0, 1}}; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will add. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Waiting on this when you have a chance. |
||
|
||
for (int res = 0; res < 13; res++) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note that the current approach fails at res > 12 because of the geo comparison precision. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Might be worth adding as a comment. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Will do. |
||
sf = H3_EXPORT(geoToH3)(&sfGeo, res); | ||
H3_EXPORT(h3ToGeoBoundary)(sf, &boundary); | ||
H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(sf, edges); | ||
|
||
for (int i = 0; i < 6; i++) { | ||
H3_EXPORT(getH3UnidirectionalEdgeBoundary)(edges[i], &edgeBoundary); | ||
t_assert(edgeBoundary.numVerts == 2, | ||
"Got the expected number of vertices back"); | ||
for (int j = 0; j < edgeBoundary.numVerts; j++) { | ||
t_assert( | ||
geoAlmostEqual(&edgeBoundary.verts[j], | ||
&boundary.verts[expectedVertices[i][j]]), | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm too tired to figure this out at the moment. Looks fun :). |
||
"Got expected vertex"); | ||
} | ||
} | ||
} | ||
free(edges); | ||
} | ||
|
||
H3Index pentagon = 0x811c0ffffffffff; | ||
edges = calloc(6, sizeof(H3Index)); | ||
H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(pentagon, edges); | ||
TEST(getH3UnidirectionalEdgeBoundaryPentagonClassIII) { | ||
H3Index pentagon; | ||
GeoBoundary boundary; | ||
GeoBoundary edgeBoundary; | ||
STACK_ARRAY_CALLOC(H3Index, edges, 6); | ||
|
||
const int expectedVertices[][3] = {{-1, -1, -1}, {2, 3, 4}, {4, 5, 6}, | ||
{8, 9, 0}, {6, 7, 8}, {0, 1, 2}}; | ||
|
||
for (int res = 1; res < 13; res += 2) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please add comments for why we don't test all resolutions. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added. |
||
setH3Index(&pentagon, res, 24, 0); | ||
H3_EXPORT(h3ToGeoBoundary)(pentagon, &boundary); | ||
H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(pentagon, edges); | ||
|
||
int missingEdgeCount = 0; | ||
for (int i = 0; i < 6; i++) { | ||
if (edges[i] == 0) { | ||
missingEdgeCount++; | ||
} else { | ||
H3_EXPORT(getH3UnidirectionalEdgeBoundary) | ||
(edges[i], &edgeBoundary); | ||
t_assert( | ||
edgeBoundary.numVerts == 3, | ||
"Got the expected number of vertices back for a Class III " | ||
"pentagon"); | ||
for (int j = 0; j < edgeBoundary.numVerts; j++) { | ||
t_assert( | ||
geoAlmostEqual(&edgeBoundary.verts[j], | ||
&boundary.verts[expectedVertices[i][j]]), | ||
"Got expected vertex"); | ||
} | ||
} | ||
} | ||
t_assert(missingEdgeCount == 1, | ||
"Only one edge was deleted for the pentagon"); | ||
} | ||
} | ||
|
||
int missingEdgeCount = 0; | ||
for (int i = 0; i < 6; i++) { | ||
if (edges[i] == 0) { | ||
missingEdgeCount++; | ||
} else { | ||
H3_EXPORT(getH3UnidirectionalEdgeBoundary)(edges[i], &gb); | ||
t_assert(gb.numVerts == 3, | ||
"Got the expected number of vertices back for a Class III " | ||
"pentagon"); | ||
TEST(getH3UnidirectionalEdgeBoundaryPentagonClassII) { | ||
H3Index pentagon; | ||
GeoBoundary boundary; | ||
GeoBoundary edgeBoundary; | ||
STACK_ARRAY_CALLOC(H3Index, edges, 6); | ||
|
||
const int expectedVertices[][3] = {{-1, -1}, {1, 2}, {2, 3}, | ||
{4, 0}, {3, 4}, {0, 1}}; | ||
|
||
for (int res = 0; res < 12; res += 2) { | ||
setH3Index(&pentagon, res, 24, 0); | ||
H3_EXPORT(h3ToGeoBoundary)(pentagon, &boundary); | ||
H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(pentagon, edges); | ||
|
||
int missingEdgeCount = 0; | ||
for (int i = 0; i < 6; i++) { | ||
if (edges[i] == 0) { | ||
missingEdgeCount++; | ||
} else { | ||
H3_EXPORT(getH3UnidirectionalEdgeBoundary) | ||
(edges[i], &edgeBoundary); | ||
t_assert( | ||
edgeBoundary.numVerts == 2, | ||
"Got the expected number of vertices back for a Class II " | ||
"pentagon"); | ||
for (int j = 0; j < edgeBoundary.numVerts; j++) { | ||
t_assert( | ||
geoAlmostEqual(&edgeBoundary.verts[j], | ||
&boundary.verts[expectedVertices[i][j]]), | ||
"Got expected vertex"); | ||
} | ||
} | ||
} | ||
t_assert(missingEdgeCount == 1, | ||
"Only one edge was deleted for the pentagon"); | ||
} | ||
t_assert(missingEdgeCount == 1, | ||
"Only one edge was deleted for the pentagon"); | ||
free(edges); | ||
} | ||
|
||
END_TESTS(); |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,7 @@ | |
*/ | ||
|
||
#include <inttypes.h> | ||
#include <stdbool.h> | ||
#include "algos.h" | ||
#include "constants.h" | ||
#include "coordijk.h" | ||
|
@@ -212,6 +213,22 @@ void H3_EXPORT(getH3UnidirectionalEdgesFromHexagon)(H3Index origin, | |
} | ||
} | ||
|
||
/** | ||
* Whether the given coordinate has a matching vertex in the given geo boundary. | ||
* @param vertex Coordinate to check | ||
* @param boundary Geo boundary to look in | ||
* @return Whether a match was found | ||
*/ | ||
static bool _hasMatchingVertex(const GeoCoord* vertex, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Great! |
||
const GeoBoundary* boundary) { | ||
for (int i = 0; i < boundary->numVerts; i++) { | ||
if (geoAlmostEqualThreshold(vertex, &boundary->verts[i], 0.000001)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
|
||
/** | ||
* Provides the coordinates defining the unidirectional edge. | ||
* @param edge The unidirectional edge H3Index | ||
|
@@ -221,6 +238,9 @@ void H3_EXPORT(getH3UnidirectionalEdgeBoundary)(H3Index edge, GeoBoundary* gb) { | |
// TODO: More efficient solution :) | ||
GeoBoundary origin = {0}; | ||
GeoBoundary destination = {0}; | ||
GeoCoord postponedVertex = {0}; | ||
bool hasPostponedVertex = false; | ||
|
||
H3_EXPORT(h3ToGeoBoundary) | ||
(H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(edge), &origin); | ||
H3_EXPORT(h3ToGeoBoundary) | ||
|
@@ -229,14 +249,23 @@ void H3_EXPORT(getH3UnidirectionalEdgeBoundary)(H3Index edge, GeoBoundary* gb) { | |
|
||
int k = 0; | ||
for (int i = 0; i < origin.numVerts; i++) { | ||
for (int j = 0; j < destination.numVerts; j++) { | ||
if (geoAlmostEqualThreshold(&origin.verts[i], &destination.verts[j], | ||
0.000001)) { | ||
gb->verts[k].lat = origin.verts[i].lat; | ||
gb->verts[k].lon = origin.verts[i].lon; | ||
if (_hasMatchingVertex(&origin.verts[i], &destination)) { | ||
// If we are on vertex 0, we need to handle the case where it's the | ||
// end of the edge, not the beginning. | ||
if (i == 0 && | ||
!_hasMatchingVertex(&origin.verts[i + 1], &destination)) { | ||
postponedVertex = origin.verts[i]; | ||
hasPostponedVertex = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Is zero a valid vertex? If not, you can just check that There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
} else { | ||
gb->verts[k] = origin.verts[i]; | ||
k++; | ||
} | ||
} | ||
} | ||
// If we postponed adding the last vertex, add it now | ||
if (hasPostponedVertex) { | ||
gb->verts[k] = postponedVertex; | ||
k++; | ||
} | ||
gb->numVerts = k; | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍