uber / h3

Hexagonal hierarchical geospatial indexing system

Home Page:https://h3geo.org

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

bboxHexEstimate calls greatCircleDistanceKm with lat,lng instead of radians

jmontrose opened this issue · comments

My first thought was that this was a build issue on my side. I'm new to the library, and still not sure I've got this right. Given a polygon approximately 1 square km, the diagonal call to greatCircleDistanceKm returns 82km instead of 1.4.

1.4 is the number I get calculating manually, but more importantly, is the number I get calling h3 python.

I noticed this while investigating oddly high estimates in maxPolygonToCellsSize, and my theory is that because this bug is returning higher numbers in most cases, the effects are hidden by the bounds filtering in polygonToCells.

I tried this naive fix, which gives me the correct results for my case, but unsurprisingly causes some other tests to fail, which I haven't investigated.

diff --git a/src/h3lib/lib/bbox.c b/src/h3lib/lib/bbox.c
index 033b02ed..b7680cbe 100644
--- a/src/h3lib/lib/bbox.c
+++ b/src/h3lib/lib/bbox.c
@@ -116,10 +116,10 @@ H3Error bboxHexEstimate(const BBox *bbox, int res, int64_t *out) {
 
     // Then get the area of the bounding box of the geoloop in question
     LatLng p1, p2;
-    p1.lat = bbox->north;
-    p1.lng = bbox->east;
-    p2.lat = bbox->south;
-    p2.lng = bbox->west;
+    p1.lat = degsToRads(bbox->north);
+    p1.lng = degsToRads(bbox->east);
+    p2.lat = degsToRads(bbox->south);
+    p2.lng = degsToRads(bbox->west);
     double d = H3_EXPORT(greatCircleDistanceKm)(&p1, &p2);
     double lngDiff = fabs(p1.lng - p2.lng);
     double latDiff = fabs(p1.lat - p2.lat);

Here is the test I've been working with:


    TEST(circleDistanceIncorrect) {
        printf("\n\nTEST START\n\n");
        // Python
        // h3.point_dist((52.524754, 13.455842), (52.515767, 13.441110),
        //   'km') 1.4114413820554332
        // h3.point_dist((52.524754, 13.455842), (52.515767, 13.441110), 'rads')
        //   0.00022154132650843334

        LatLng radp1, radp2;
        radp1.lat = degsToRads(52.524754);
        radp1.lng = degsToRads(13.455842);
        radp2.lat = degsToRads(52.515767);
        radp2.lng = degsToRads(13.441110);

        printf("\nrad dist_km %f\n", greatCircleDistanceKm(&radp1, &radp2));
        printf("\nrad dist_rad %f\n", greatCircleDistanceRads(&radp1, &radp2));

        LatLng p1, p2;
        p1.lat = 52.524754;
        p1.lng = 13.455842;
        p2.lat = 52.515767;
        p2.lng = 13.441110;

        double dist_km = greatCircleDistanceKm(&p1, &p2);
        double dist_rad = greatCircleDistanceRads(&p1, &p2);
        printf("\ndist_km %f\n", dist_km);
        printf("\ndist_rad %f\n", dist_rad);
        // incorrect dist_km == 82.434516
        // incorrect dist_rad = 0.012939
        t_assert(dist_km == 1.4114413820554332, "got expected km distance");
    }

I think the issue here is just that all H3 coordinate input, in the C library, is expected to be in radians. We expose a degsToRads function to help with this, and in general the bindings (JS, Python, etc) all assume input in degrees, but in the C library itself everything is in radians. The BBox coordinates should be in radians, because the GeoPolygon coordinates should be in radians.

Ah, you are so right. I was caught off guard by "polygonToCells takes a given GeoJSON-like data structure" in the docs and sticking to GeoJSON's WGS84 requirement.

And of course, that means I was also ignoring the "latitude in radians" in the LatLng struct...

Thanks!