9

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

另外,我发现这个函数需要一个纬度并返回谷歌地图的瓦片,谷歌地图也使用墨卡托。似乎如果我知道如何反转这个函数,我就会非常接近得到我的答案。

/*<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);
    }
4

5 回答 5

9

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

    /// <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;
    }
于 2009-07-22T15:26:09.027 回答
3

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

我刚刚使用“理论上的 256x256 墨卡托图块”(谷歌的世界地图单图块版本)对其进行了测试。

瓷砖0

这里有更多代码(JavaScript,但易于理解)来说明。

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

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

152.88327883810192

如果从图块顶部向下数 152 像素,您会找到澳大利亚。我还通过将结果与已知良好的函数进行比较来验证这个答案是正确的。

可以肯定的是,我们可以反转该计算:

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

我们返回-32.99613291758226

棘手的部分不在于古德曼函数,而在于两个尺度之间的转换。

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

    /**
     * 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];
    }

而原函数的 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
    );
}
于 2016-10-17T10:07:14.577 回答
2

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

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

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

于 2009-07-22T15:28:52.623 回答
0

我做过类似的事情。特别是如果您有来自世界某个地方的图像。裁剪的地图或不是完整的世界地图:https ://stackoverflow.com/a/10401734/730823

于 2012-05-02T05:40:56.910 回答
0

执行逆运算时的一个重要注意事项是,没有像大多数其他地图投影那样的“墨卡托地图” 存在的每个墨卡托图根据输入的 phi 值而有所不同。根据维基百科,谷歌使用 85.051129,其他地图提供商使用 85.05113。因此,Gudermannian 的输入值必须根据例如 GudermannianInv(85.05113) 进行缩放。

于 2015-11-28T23:46:48.110 回答