ext/h3/src/src/h3lib/lib/h3UniEdge.c in h3-3.6.2 vs ext/h3/src/src/h3lib/lib/h3UniEdge.c in h3-3.7.1

- old
+ new

@@ -17,15 +17,17 @@ * @brief H3UniEdge functions for manipulating unidirectional edge indexes. */ #include <inttypes.h> #include <stdbool.h> + #include "algos.h" #include "constants.h" #include "coordijk.h" #include "geoCoord.h" #include "h3Index.h" +#include "vertex.h" /** * Returns whether or not the provided H3Indexes are neighbors. * @param origin The origin H3 index. * @param destination The destination H3 index. @@ -94,64 +96,69 @@ /** * Returns a unidirectional edge H3 index based on the provided origin and * destination * @param origin The origin H3 hexagon index * @param destination The destination H3 hexagon index - * @return The unidirectional edge H3Index, or 0 on failure. + * @return The unidirectional edge H3Index, or H3_NULL on failure. */ H3Index H3_EXPORT(getH3UnidirectionalEdge)(H3Index origin, H3Index destination) { // Short-circuit and return an invalid index value if they are not neighbors if (H3_EXPORT(h3IndexesAreNeighbors)(origin, destination) == 0) { - return H3_INVALID_INDEX; + return H3_NULL; } // Otherwise, determine the IJK direction from the origin to the destination H3Index output = origin; H3_SET_MODE(output, H3_UNIEDGE_MODE); + bool isPentagon = H3_EXPORT(h3IsPentagon)(origin); + // Checks each neighbor, in order, to determine which direction the // destination neighbor is located. Skips CENTER_DIGIT since that // would be this index. H3Index neighbor; - for (Direction direction = K_AXES_DIGIT; direction < NUM_DIGITS; - direction++) { + // Excluding from branch coverage as we never hit the end condition + // LCOV_EXCL_BR_START + for (Direction direction = isPentagon ? J_AXES_DIGIT : K_AXES_DIGIT; + direction < NUM_DIGITS; direction++) { + // LCOV_EXCL_BR_STOP int rotations = 0; neighbor = h3NeighborRotations(origin, direction, &rotations); if (neighbor == destination) { H3_SET_RESERVED_BITS(output, direction); return output; } } - // This should be impossible, return an invalid H3Index in this case; - return H3_INVALID_INDEX; // LCOV_EXCL_LINE + // This should be impossible, return H3_NULL in this case; + return H3_NULL; // LCOV_EXCL_LINE } /** * Returns the origin hexagon from the unidirectional edge H3Index * @param edge The edge H3 index - * @return The origin H3 hexagon index + * @return The origin H3 hexagon index, or H3_NULL on failure */ H3Index H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(H3Index edge) { if (H3_GET_MODE(edge) != H3_UNIEDGE_MODE) { - return H3_INVALID_INDEX; + return H3_NULL; } H3Index origin = edge; H3_SET_MODE(origin, H3_HEXAGON_MODE); H3_SET_RESERVED_BITS(origin, 0); return origin; } /** * Returns the destination hexagon from the unidirectional edge H3Index * @param edge The edge H3 index - * @return The destination H3 hexagon index + * @return The destination H3 hexagon index, or H3_NULL on failure */ H3Index H3_EXPORT(getDestinationH3IndexFromUnidirectionalEdge)(H3Index edge) { if (H3_GET_MODE(edge) != H3_UNIEDGE_MODE) { - return H3_INVALID_INDEX; + return H3_NULL; } Direction direction = H3_GET_RESERVED_BITS(edge); int rotations = 0; H3Index destination = h3NeighborRotations( H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(edge), direction, @@ -209,70 +216,48 @@ // This is actually quite simple. Just modify the bits of the origin // slightly for each direction, except the 'k' direction in pentagons, // which is zeroed. for (int i = 0; i < 6; i++) { if (isPentagon && i == 0) { - edges[i] = H3_INVALID_INDEX; + edges[i] = H3_NULL; } else { edges[i] = origin; H3_SET_MODE(edges[i], H3_UNIEDGE_MODE); H3_SET_RESERVED_BITS(edges[i], i + 1); } } } /** - * 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, - 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 * @param gb The geoboundary object to store the edge coordinates. */ void H3_EXPORT(getH3UnidirectionalEdgeBoundary)(H3Index edge, GeoBoundary* gb) { - // TODO: More efficient solution :) - GeoBoundary origin = {0}; - GeoBoundary destination = {0}; - GeoCoord postponedVertex = {0}; - bool hasPostponedVertex = false; + // Get the origin and neighbor direction from the edge + Direction direction = H3_GET_RESERVED_BITS(edge); + H3Index origin = H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(edge); - H3_EXPORT(h3ToGeoBoundary) - (H3_EXPORT(getOriginH3IndexFromUnidirectionalEdge)(edge), &origin); - H3_EXPORT(h3ToGeoBoundary) - (H3_EXPORT(getDestinationH3IndexFromUnidirectionalEdge)(edge), - &destination); + // Get the start vertex for the edge + int startVertex = vertexNumForDirection(origin, direction); + if (startVertex == INVALID_VERTEX_NUM) { + // This is not actually an edge (i.e. no valid direction), + // so return no vertices. + gb->numVerts = 0; + return; + } - int k = 0; - for (int i = 0; i < origin.numVerts; i++) { - 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; - } else { - gb->verts[k] = origin.verts[i]; - k++; - } - } + // Get the geo boundary for the appropriate vertexes of the origin. Note + // that while there are always 2 topological vertexes per edge, the + // resulting edge boundary may have an additional distortion vertex if it + // crosses an edge of the icosahedron. + FaceIJK fijk; + _h3ToFaceIjk(origin, &fijk); + int res = H3_GET_RESOLUTION(origin); + int isPentagon = H3_EXPORT(h3IsPentagon)(origin); + + if (isPentagon) { + _faceIjkPentToGeoBoundary(&fijk, res, startVertex, 2, gb); + } else { + _faceIjkToGeoBoundary(&fijk, res, startVertex, 2, gb); } - // If we postponed adding the last vertex, add it now - if (hasPostponedVertex) { - gb->verts[k] = postponedVertex; - k++; - } - gb->numVerts = k; }