/// <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> /// polyfill takes a given GeoJSON-like data structure and preallocated, /// zeroed memory, and fills it with the hexagons that are contained by /// the GeoJSON-like data structure. /// /// The current implementation is very primitive and slow, but correct, /// performing a point-in-poly operation on every hexagon in a k-ring defined /// around the given Geofence. /// </summary> /// <param name="geoPolygon">The Geofence and holes defining the relevant area</param> /// <param name="res"> The Hexagon resolution (0-15)</param> /// <param name="out_hex">The slab of zeroed memory to write to. Assumed to be big enough.</param> /// <!-- Based off 3.1.1 --> internal static void polyfill(GeoPolygon geoPolygon, int res, List <H3Index> out_hex) { // One of the goals of the polyfill algorithm is that two adjacent polygons // with zero overlap have zero overlapping hexagons. That the hexagons are // uniquely assigned. There are a few approaches to take here, such as // deciding based on which polygon has the greatest overlapping area of the // hexagon, or the most number of contained points on the hexagon (using the // center point as a tiebreaker). // // But if the polygons are convex, both of these more complex algorithms can // be reduced down to checking whether or not the center of the hexagon is // contained in the polygon, and so this is the approach that this polyfill // algorithm will follow, as it's simpler, faster, and the error for concave // polygons is still minimal (only affecting concave shapes on the order of // magnitude of the hexagon size or smaller, not impacting larger concave // shapes) // // This first part is identical to the maxPolyfillSize above. // Get the bounding boxes for the polygon and any holes int cnt = geoPolygon.numHoles + 1; List <BBox> bboxes = new List <BBox>(); for (int i = 0; i < cnt; i++) { bboxes.Add(new BBox()); } Polygon.bboxesFromGeoPolygon(geoPolygon, ref bboxes); int minK = BBox.bboxHexRadius(bboxes[0], res); int numHexagons = maxKringSize(minK); // Get the center hex GeoCoord center = new GeoCoord(); BBox.bboxCenter(bboxes[0], ref center); H3Index centerH3 = H3Index.geoToH3(ref center, res); // From here on it works differently, first we get all potential // hexagons inserted into the available memory kRing(centerH3, minK, ref out_hex); // Next we iterate through each hexagon, and test its center point to see if // it's contained in the GeoJSON-like struct for (int i = 0; i < numHexagons; i++) { // Skip records that are already zeroed if (out_hex[i] == 0) { continue; } // Check if hexagon is inside of polygon GeoCoord hexCenter = new GeoCoord(); H3Index.h3ToGeo(out_hex[i], ref hexCenter); hexCenter.lat = GeoCoord.constrainLat(hexCenter.lat); hexCenter.lon = GeoCoord.constrainLng(hexCenter.lon); // And remove from list if not if (!Polygon.pointInsidePolygon(geoPolygon, bboxes, hexCenter)) { out_hex[i] = H3Index.H3_INVALID_INDEX; } } }