Search code examples
latitude-longitude

Problem converting fom latitude and longitude to position


I would like to be able to convert from a 3d position on a sphere to latitude and longitude and back. I tried converting to latitude and longitude using:

lat = acos(y / sphere_radius) * 180 / PI
long = atan2(x, z) * 180 / PI

and it seems to work. Some values I got were:

(0, 1, 0) -> (0, 0)
(1, 0, 0) -> (90, 90)
(0, 0, 1) -> (90, 0)
(0, 1, 1) -> (45, 0)

So that means that y is my up and z my forward direction and my latitude goes from 0-180 and my longitude from 0-360. But now I would like to convert the latitude and longitude back to a position vector, so I found this snippet online (at https://stackoverflow.com/a/59720312/13215204):

z = sphere_radius * cos(longitude) * cos(latitude)
x = -sphere_radius * cos(longitude) * sin(latitude)
y = sphere_radius * sin(latitude)

It does indeed returns a point on the sphere, and the point even moves arround when I change the latitude and longitude, but the position isn't correct. If I for example first convert the point (1, 0, 0) to (90, 90) and then try to convert it back, it returns (-0.4005763, 0.8939967, 0.20077). I have heard that you need to convert back to radians first, but that doesn't seem to help (it instead returns (4.371139e-08, 1, 1.910685e-15)). Maybe I just need to flip a few sines and cosines arround?


Solution

  • It works now! These are the Methods I ended up using (in C#, Mathf is part of Unity, but I'm sure you can find other Libraries that are able to do sin, cos, acos and atan pretty easy)

    public static Vector2 ToLatLon(this Vector3 vector, float sphere_radius)
    {
        return new Vector2(
            Mathf.Acos(vector.y / sphere_radius),
            Mathf.Atan2(vector.x, vector.z)
        );
    }
    

    and

    public static Vector3 ToVector(this Vector2 latlon, float sphere_radius)
    {
        return new Vector3(
             sphere_radius * Mathf.Sin(latlon.y) * Mathf.Sin(latlon.x),
             sphere_radius * Mathf.Cos(latlon.x),
             sphere_radius * Mathf.Cos(latlon.y) * Mathf.Sin(latlon.x)
        );
    }
    

    I had the equations for x, y and z in the wrong order and also had to remove the minus from the sphere_radius when calculating x. I also removed the conversion from radians to degrees for the latitude and longitude, because there was no need for them (apart from being easier to read). So I instead do the conversion to degrees outside the function using Mathf.Rad2Deg when I need the values in degrees for debugging.