我有一个墨卡托投影图作为JPEG,我想知道如何将给定的x,y坐标与其纬度和经度相关联。我看过Gudermannian函数,但老实说我不明白如何使用该函数并应用它。即,它期待什么输入?我发现的实现(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);
}
答案 0 :(得分:8)
以下是一些代码...如果您需要更多解释,请告诉我。
/// <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;
}
答案 1 :(得分:2)
转换是OpenLayers代码的一部分:
答案 2 :(得分:2)
Erich Mirabal's answer完全正确(如果没有完全完成)。
我刚刚使用'理论上的256x256墨卡托瓷砖'(Google的世界地图的单一瓷砖版本)进行了测试。
这里有一些代码(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 。
棘手的部分不是Gudermannian函数,而是两个尺度之间的转换。
幸运的是,相当懒惰,并且讨厌这些缩放问题,我已经有了一些功能来为我做那个混乱的转换。
/**
* 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
);
}
答案 3 :(得分:0)
我做了类似的事情。特别是如果你有一个来自世界的一部分的图像。裁剪地图或不是完整的世界地图:https://stackoverflow.com/a/10401734/730823
答案 4 :(得分:0)
执行逆操作时的一个重要注意事项是,与大多数其他地图投影的情况一样,没有“ mercator map”。存在的每个墨卡托图根据输入的phi值而不同。根据维基百科谷歌使用85.051129,其他地图提供商使用85.05113。因此,必须根据例如缩放Gudermannian的输入值。 GudermannianInv(85.05113)。