如何在墨卡托地图(JPEG)上获得x,y的纬度,经度?

时间:2021-11-24 05:37:50

I have a Mercator projection map as a JPEG and I would like to know how to relate a given x, y coordinate to its latitude and longitude. I've looked at the Gudermannian function but I honestly don't understand how to take that function and apply it. Namely, what input is it expecting? The implementation I found (JavaScript) seems to take a range between -PI and PI, but what's the correlation between my y-value in pixels and that range?

我有一个墨卡托投影图作为JPEG,我想知道如何将给定的x,y坐标与其纬度和经度相关联。我看过Gudermannian函数,但老实说我不明白如何使用该函数并应用它。即,它期待什么输入?我发现的实现(JavaScript)似乎在-PI和PI之间取得了一个范围,但是我的y值(以像素为单位)与该范围之间的相关性是什么?

Also, I found this function which takes a latitude and returns the tile for Google Maps, which also uses Mercator. It would seem that if I knew how to inverse this function, I'd be pretty close to having my answer.

此外,我发现这个功能需要一个纬度并返回谷歌地图的瓷砖,谷歌地图也使用墨卡托。似乎如果我知道如何反转这个功能,我会非常接近我的答案。

/*<summary>Get the vertical tile number from a latitude
using Mercator projection formula</summary>*/

    private int getMercatorLatitude(double lati)
    {
        double maxlat = Math.PI;

        double lat = lati;

        if (lat > 90) lat = lat - 180;
        if (lat < -90) lat = lat + 180;

        // conversion degre=>radians
        double phi = Math.PI * lat / 180;

        double res;
        //double temp = Math.Tan(Math.PI / 4 - phi / 2);
        //res = Math.Log(temp);
        res = 0.5 * Math.Log((1 + Math.Sin(phi)) / (1 - Math.Sin(phi)));
        double maxTileY = Math.Pow(2, zoom);
        int result = (int)(((1 - res / maxlat) / 2) * (maxTileY));

        return (result);
    }

5 个解决方案

#1


Here is some code for you... Let me know if you need more explanation.

这里有一些代码...如果您需要更多解释,请告诉我。

    /// <summary>
    /// Calculates the Y-value (inverse Gudermannian function) for a latitude. 
    /// <para><see cref="http://en.wikipedia.org/wiki/Gudermannian_function"/></para>
    /// </summary>
    /// <param name="latitude">The latitude in degrees to use for calculating the Y-value.</param>
    /// <returns>The Y-value for the given latitude.</returns>
    public static double GudermannianInv(double latitude)
    {
        double sign = Math.Sign(latitude);
        double sin = Math.Sin(latitude * RADIANS_PER_DEGREE * sign);
        return sign * (Math.Log((1.0 + sin) / (1.0 - sin)) / 2.0);
    }

    /// <summary>
    /// Returns the Latitude in degrees for a given Y.
    /// </summary>
    /// <param name="y">Y is in the range of +PI to -PI.</param>
    /// <returns>Latitude in degrees.</returns>
    public static double Gudermannian(double y)
    {
        return Math.Atan(Math.Sinh(y)) * DEGREES_PER_RADIAN;
    }

#2


Google, etc., use "spherical Mercator", the Mercator projection using a spherical Earth model rather than the slower and more complex elliptical equations.

谷歌等使用“球形墨卡托”,墨卡托投影使用球形地球模型而不是更慢更复杂的椭圆方程。

The transformations are available as part of the OpenLayers code:

转换作为OpenLayers代码的一部分提供:

http://docs.openlayers.org/library/spherical_mercator.html

#3


Erich Mirabal's answer was completely correct (if not completely complete).

Erich Mirabal的回答是完全正确的(如果不是完全完整的话)。

I have just tested it using a 'theoretical 256x256 Mercator tile' (Google's single tile version of a world map).

我刚刚使用'理论上的256x256墨卡托瓷砖'(Google的世界地图的单一瓷砖版本)进行了测试。

如何在墨卡托地图(JPEG)上获得x,y的纬度,经度?

Here's a little more code (JavaScript, but easy to follow) to elucidate.

这里有一些代码(JavaScript,但很容易理解)来阐明。

I live in Australia, at a latitude of about -33°.

我住在澳大利亚,纬度约为-33°。

convertRange(
    GudermannianInv(-33), 
    [Math.PI, - Math.PI], 
    [0, 256]
);

152.88327883810192

If you count 152 pixels down from the top of the tile, you will find Australia. I have also verified this answer is correct by comparing the result to known-good functions.

如果你从瓷砖顶部算下152像素,你会发现澳大利亚。通过将结果与已知良好函数进行比较,我也验证了这个答案是正确的。

To be sure, we can reverse that calculation:

可以肯定的是,我们可以改变这种计算:

Gudermannian(
    convertRange(
        152.88, 
        [0, 256], 
        [Math.PI, - Math.PI]
));

And we are returned -32.99613291758226.

我们返回-32.99613291758226。

The tricky part isn't in the Gudermannian function, but in the conversion between two scales.

棘手的部分不是Gudermannian函数,而是两个尺度之间的转换。

Fortunately, being rather lazy, and hating these kind of scaling problems, I already had a little function to do that messy conversion for me.

幸运的是,相当懒惰,并且讨厌这些缩放问题,我已经有了一些功能来为我做那个混乱的转换。

    /**
     * convert number from _n_ of r1[0] .. r1[1] to _n_ of r2[0] .. r2[1]
     * @example `convertRange( 5, [0, 10], [0, 100] ) === 50`
     *
     * @param {number} value
     * @param {array<number>} r1 old range
     * @param {array<number>} r2 new range
     * @returns {number} value adjusted for new range
     */
    function convertRange( value, r1, r2 ) {
        return ( value - r1[0] )
             * ( r2[1] - r2[0] )
             / ( r1[1] - r1[0] )
             +   r2[0];
    }

And the JavaScript versions of the original functions are naturally:

原始函数的JavaScript版本自然是:

function Gudermannian(y) {
    return Math.atan(Math.sinh(y)) * (180 / Math.PI)
}

function GudermannianInv(latitude)
{
    var sign = Math.sign(latitude);
    var sin  = Math.sin(
                          latitude 
                        * (Math.PI / 180) 
                        * sign
    );
    return sign * (
        Math.log(
            (1 + sin) / (1 - sin)
        ) / 2
    );
}

#4


I've done something similiar. Especially if you have an image from a part of the world. A cropped map or just not a complete world map: https://*.com/a/10401734/730823

我做了类似的事情。特别是如果你有一个来自世界的一部分的图像。裁剪地图或不是完整的世界地图:https://*.com/a/10401734/730823

#5


An important note when performing an inverse is that there is no such thing as "the mercator map" as is the case with most other map projections. Each mercator map in existence is different depending on the input phi value. According to wikipedia google uses 85.051129, and other map providers use 85.05113. Therefore the input values to Gudermannian must be scaled based on e.g. GudermannianInv(85.05113).

执行逆操作时的一个重要注意事项是,与大多数其他地图投影的情况一样,不存在“墨卡托地图”。存在的每个墨卡托图根据输入的phi值而不同。根据*谷歌使用85.051129,其他地图提供商使用85.05113。因此,必须根据例如缩放Gudermannian的输入值。 GudermannianInv(85.05113)。

#1


Here is some code for you... Let me know if you need more explanation.

这里有一些代码...如果您需要更多解释,请告诉我。

    /// <summary>
    /// Calculates the Y-value (inverse Gudermannian function) for a latitude. 
    /// <para><see cref="http://en.wikipedia.org/wiki/Gudermannian_function"/></para>
    /// </summary>
    /// <param name="latitude">The latitude in degrees to use for calculating the Y-value.</param>
    /// <returns>The Y-value for the given latitude.</returns>
    public static double GudermannianInv(double latitude)
    {
        double sign = Math.Sign(latitude);
        double sin = Math.Sin(latitude * RADIANS_PER_DEGREE * sign);
        return sign * (Math.Log((1.0 + sin) / (1.0 - sin)) / 2.0);
    }

    /// <summary>
    /// Returns the Latitude in degrees for a given Y.
    /// </summary>
    /// <param name="y">Y is in the range of +PI to -PI.</param>
    /// <returns>Latitude in degrees.</returns>
    public static double Gudermannian(double y)
    {
        return Math.Atan(Math.Sinh(y)) * DEGREES_PER_RADIAN;
    }

#2


Google, etc., use "spherical Mercator", the Mercator projection using a spherical Earth model rather than the slower and more complex elliptical equations.

谷歌等使用“球形墨卡托”,墨卡托投影使用球形地球模型而不是更慢更复杂的椭圆方程。

The transformations are available as part of the OpenLayers code:

转换作为OpenLayers代码的一部分提供:

http://docs.openlayers.org/library/spherical_mercator.html

#3


Erich Mirabal's answer was completely correct (if not completely complete).

Erich Mirabal的回答是完全正确的(如果不是完全完整的话)。

I have just tested it using a 'theoretical 256x256 Mercator tile' (Google's single tile version of a world map).

我刚刚使用'理论上的256x256墨卡托瓷砖'(Google的世界地图的单一瓷砖版本)进行了测试。

如何在墨卡托地图(JPEG)上获得x,y的纬度,经度?

Here's a little more code (JavaScript, but easy to follow) to elucidate.

这里有一些代码(JavaScript,但很容易理解)来阐明。

I live in Australia, at a latitude of about -33°.

我住在澳大利亚,纬度约为-33°。

convertRange(
    GudermannianInv(-33), 
    [Math.PI, - Math.PI], 
    [0, 256]
);

152.88327883810192

If you count 152 pixels down from the top of the tile, you will find Australia. I have also verified this answer is correct by comparing the result to known-good functions.

如果你从瓷砖顶部算下152像素,你会发现澳大利亚。通过将结果与已知良好函数进行比较,我也验证了这个答案是正确的。

To be sure, we can reverse that calculation:

可以肯定的是,我们可以改变这种计算:

Gudermannian(
    convertRange(
        152.88, 
        [0, 256], 
        [Math.PI, - Math.PI]
));

And we are returned -32.99613291758226.

我们返回-32.99613291758226。

The tricky part isn't in the Gudermannian function, but in the conversion between two scales.

棘手的部分不是Gudermannian函数,而是两个尺度之间的转换。

Fortunately, being rather lazy, and hating these kind of scaling problems, I already had a little function to do that messy conversion for me.

幸运的是,相当懒惰,并且讨厌这些缩放问题,我已经有了一些功能来为我做那个混乱的转换。

    /**
     * convert number from _n_ of r1[0] .. r1[1] to _n_ of r2[0] .. r2[1]
     * @example `convertRange( 5, [0, 10], [0, 100] ) === 50`
     *
     * @param {number} value
     * @param {array<number>} r1 old range
     * @param {array<number>} r2 new range
     * @returns {number} value adjusted for new range
     */
    function convertRange( value, r1, r2 ) {
        return ( value - r1[0] )
             * ( r2[1] - r2[0] )
             / ( r1[1] - r1[0] )
             +   r2[0];
    }

And the JavaScript versions of the original functions are naturally:

原始函数的JavaScript版本自然是:

function Gudermannian(y) {
    return Math.atan(Math.sinh(y)) * (180 / Math.PI)
}

function GudermannianInv(latitude)
{
    var sign = Math.sign(latitude);
    var sin  = Math.sin(
                          latitude 
                        * (Math.PI / 180) 
                        * sign
    );
    return sign * (
        Math.log(
            (1 + sin) / (1 - sin)
        ) / 2
    );
}

#4


I've done something similiar. Especially if you have an image from a part of the world. A cropped map or just not a complete world map: https://*.com/a/10401734/730823

我做了类似的事情。特别是如果你有一个来自世界的一部分的图像。裁剪地图或不是完整的世界地图:https://*.com/a/10401734/730823

#5


An important note when performing an inverse is that there is no such thing as "the mercator map" as is the case with most other map projections. Each mercator map in existence is different depending on the input phi value. According to wikipedia google uses 85.051129, and other map providers use 85.05113. Therefore the input values to Gudermannian must be scaled based on e.g. GudermannianInv(85.05113).

执行逆操作时的一个重要注意事项是,与大多数其他地图投影的情况一样,不存在“墨卡托地图”。存在的每个墨卡托图根据输入的phi值而不同。根据*谷歌使用85.051129,其他地图提供商使用85.05113。因此,必须根据例如缩放Gudermannian的输入值。 GudermannianInv(85.05113)。