uber / h3

Hexagonal hierarchical geospatial indexing system
https://h3geo.org
Apache License 2.0
4.81k stars 457 forks source link

Most accurate x,y,z to lat, long formula/values ? #698

Closed SkybuckFlying closed 1 year ago

SkybuckFlying commented 1 year ago

I see a lot of different conversion formulas and values, I tried a few, but they seem slightly off from where H3 thinks the lat, long should be for a certain X,Y,Z.

There is _GeoToVec3d in H3 library to convert from lat, long to x,y,z but what would be the opposite function/formula ?

What I am currently using is:

// https://www.nosco.ch/mathematics/en/earth-coordinates.php
procedure XYZtoLatLong( X,Y,Z : double; var Lat,Long : double );
var
    R : double;
begin
//  R := sqrt( (X*X) + (Y*Y) + (Z*Z) );
//  R := 6.371;
//  R := 6.378137;
//  R := 6.356752315;
    R := 6.371 * 0.9966472;
    Lat := arcsin( Z / R );
    Long := arctan2( Y, X);
end;
// strange how this one is diffrent from uber h3 _GeoToVec3D
procedure LatLongToXYZ( Lat, Long : double; var X,Y,Z : double );
var
    R : double;
begin
//  R := 6.371;
//  R := 6.378137;
//  R := 6.356752315;
    R := 6.371 * 0.9966472;
    X := R * cos( Lat ) * cos( Long );
    Y := R * cos( Lat ) * sin( Long );
    Z := R * sin( Lat );
end;

I find it strange how _geoToVec3d is different from this above link:

/**
 * Calculate the 3D coordinate on unit sphere from the latitude and longitude.
 *
 * @param geo The latitude and longitude of the point.
 * @param v The 3D coordinate of the point.
 */
void _geoToVec3d(const LatLng *geo, Vec3d *v) {
    double r = cos(geo->lat);

    v->z = sin(geo->lat);
    v->x = cos(geo->lng) * r;
    v->y = sin(geo->lng) * r;
}

Why is this ?

Also the output of _geoToVec3d is normalized ? and must be multiplied with 6.371 to get something resembling the center of the H3 index/hexagon, but still not perfect...

Here you can see slight inaccuracies, not sure what is causing it, I suspect conversion trouble or maybe it's something else:

https://youtu.be/eqntfB5Y7K4

nrabinowitz commented 1 year ago

We only use this in one place in the runtime code, which is to find the closest face of the icosahedron to a given point. The primary consideration here is performance, so there's no need to scale the vector, and we don't have any requirement to do the reverse operation.

Long story short, I would consider _geoToVec3d to be an internal implementation detail (hence the underscored name), and not intended for more general use. You should use whatever lat/lng to XYZ conversion works for your use case.

SkybuckFlying commented 1 year ago

We only use this in one place in the runtime code, which is to find the closest face of the icosahedron to a given point. The primary consideration here is performance, so there's no need to scale the vector, and we don't have any requirement to do the reverse operation.

Long story short, I would consider _geoToVec3d to be an internal implementation detail (hence the underscored name), and not intended for more general use. You should use whatever lat/lng to XYZ conversion works for your use case.

There must be more to it... once the closest face is found it must then find in which hexagon it lies at different/deeper resolutions.

Here the H3 library seems to rotate the hexagons as it goes deeper, back and forth 19.x degrees... ultimately somehow it calculate resolution 15 to be as close around the point as possible I would assume.

So is my assumption correct that the given lat/long will lie perfectly within the deepest resolution 15 hexagon ? Or is H3 only trying to approximate it and is it possible that the lat/long lies outside of the resolution 15 hexagon ?

nrabinowitz commented 1 year ago

That's not actually how the H3 indexing system works. There's a detailed description of the algorithm in the docs. Essentially:

The lat/lng values are almost perfectly within the hexagons (in some edges cases they're subject to FPE, but in general if you test a lat/lng against the boundary of a cell modeled as a spherical polygon, the point will be within the shape of the hexagon it indexes to).