/// <summary> /// Returns the radius of a given hexagon in kilometers /// </summary> /// <param name="h3Index">Index of the hexagon</param> /// <returns>radius of hexagon in kilometers</returns> /// <!-- Based off 3.1.1 --> static double _hexRadiusKm(H3Index h3Index) { // There is probably a cheaper way to determine the radius of a // hexagon, but this way is conceptually simple GeoCoord h3Center = new GeoCoord(); GeoBoundary h3Boundary = new GeoBoundary(); H3Index.h3ToGeo(h3Index, ref h3Center); H3Index.h3ToGeoBoundary(h3Index, ref h3Boundary); return(GeoCoord._geoDistKm(h3Center, h3Boundary.verts)); }
/// <summary> /// Internal: Create a vertex graph from a set of hexagons. It is the /// responsibility of the caller to call destroyVertexGraph on the populated /// graph, otherwise the memory in the graph nodes will not be freed. /// </summary> /// /// <param name="h3Set">Set of hexagons</param> /// <param name="numHexes">Number of hexagons in the set</param> /// <param name="graph">Output graph</param> /// <!-- Based off 3.1.1 --> public static void h3SetToVertexGraph(ref List <H3Index> h3Set, int numHexes, ref VertexGraph graph) { GeoBoundary vertices = new GeoBoundary(); GeoCoord fromVertex = new GeoCoord(); GeoCoord toVertex = new GeoCoord(); VertexGraph.VertexNode edge; if (numHexes < 1) { // We still need to init the graph, or calls to destroyVertexGraph will // fail graph = new VertexGraph(0, 0); return; } int res = H3Index.H3_GET_RESOLUTION(h3Set[0]); const int minBuckets = 6; // TODO: Better way to calculate/guess? int numBuckets = numHexes > minBuckets ? numHexes : minBuckets; graph = new VertexGraph(numBuckets, res); // Iterate through every hexagon for (int i = 0; i < numHexes; i++) { H3Index.h3ToGeoBoundary(h3Set[i], ref vertices); // iterate through every edge for (int j = 0; j < vertices.numVerts; j++) { fromVertex = new GeoCoord(vertices.verts[j].lat, vertices.verts[j].lon); //fromVtx = vertices.verts[j]; int idx = (j + 1) % vertices.numVerts; toVertex = new GeoCoord(vertices.verts[idx].lat, vertices.verts[idx].lon); //toVtx = vertices.verts[(j + 1) % vertices.numVerts]; // If we've seen this edge already, it will be reversed edge = VertexGraph.findNodeForEdge(ref graph, toVertex, fromVertex); if (edge != null) { // If we've seen it, drop it. No edge is shared by more than 2 // hexagons, so we'll never see it again. VertexGraph.removeVertexNode(ref graph, ref edge); } else { // Add a new node for this edge VertexGraph.addVertexNode(ref graph, fromVertex, toVertex); } } } }
/// <summary> /// Provides the coordinates defining the unidirectional edge. /// </summary> /// <param name="edge">The unidirectional edge H3Index</param> /// <param name="gb"> /// The geoboundary object to store the edge coordinates. /// </param> /// <!-- Based off 3.1.1 --> public static void getH3UnidirectionalEdgeBoundary(H3Index edge, ref GeoBoundary gb) { // TODO: More efficient solution :) GeoBoundary origin = new GeoBoundary(); GeoBoundary destination = new GeoBoundary(); GeoCoord postponedVertex = new GeoCoord(); bool hasPostponedVertex = false; H3Index.h3ToGeoBoundary(getOriginH3IndexFromUnidirectionalEdge(edge), ref origin); H3Index.h3ToGeoBoundary(getDestinationH3IndexFromUnidirectionalEdge(edge), ref destination); 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++; } } } // If we postponed adding the last vertex, add it now if (hasPostponedVertex) { gb.verts[k] = postponedVertex; k++; } gb.numVerts = k; }