墨卡托经纬度计算(英国)裁剪地图上的 x 和 y

IT技术 javascript geolocation projection processing.js proj4js
2021-02-05 15:56:35

我有这张图。这是英国的地图(不包括南爱尔兰):

英国地图

我已经成功地获得了纬度和经度,并通过获取英国最左边的经度和最右边的经度并使用它们来确定在地图上放置点的位置,并将其绘制到这张地图上。

这是代码(用于 Processing.js 但可以用作 js 或任何东西):

// Size of the map
int width = 538;
int height = 811;
// X and Y boundaries
float westLong = -8.166667;
float eastLong = 1.762833;
float northLat = 58.666667;
float southLat = 49.95;

void drawPoint(float latitude, float longitude){

 fill(#000000);

 x = width * ((westLong-longitude)/(westLong-eastLong));
 y = (height * ((northLat-latitude)/(northLat-southLat)));

 console.log(x + ", " + y);
 ellipseMode(RADIUS);
 ellipse(x, y, 2, 2);    

}

但是,我无法对这些值实施墨卡托投影。这些图相当准确,但还不够好,这个投影可以解决这个问题。

我不知道该怎么做。我找到的所有例子都在解释如何为全世界做这件事。是一个很好的示例资源,解释了如何实现投影,但我无法让它工作。

另一个资源是英国极限点,我在那里获得了英国周围边界框的纬度和经度值。他们也在这里:

northLat = 58.666667; 
northLong = -3.366667; 
eastLat = 52.481167; 
eastLong = 1.762833; 
southLat = 49.95;
southLong = -5.2; 
westLat = 54.45;
westLong = -8.166667;

如果有人能帮助我解决这个问题,我将不胜感激!

谢谢

6个回答

我写了一个函数,它完全符合你的要求。我知道这有点晚了,但也许还有其他人感兴趣。

您需要一张墨卡托投影地图,并且您需要知道地图的纬度/经度位置。您可以从MapBox的免费软件TileMill获得具有完美匹配纬度/经度位置的定制墨卡托地图

我正在使用这个脚本并用一些谷歌地球位置对其进行了测试。它在像素级别上完美运行。实际上我没有在不同或更大的地图上测试这个。我希望它能帮助你!

拉斐尔 ;)

<?php

$mapWidth = 1500;
$mapHeight = 1577;

$mapLonLeft = 9.8;
$mapLonRight = 10.2;
$mapLonDelta = $mapLonRight - $mapLonLeft;

$mapLatBottom = 53.45;
$mapLatBottomDegree = $mapLatBottom * M_PI / 180;

function convertGeoToPixel($lat, $lon)
{
    global $mapWidth, $mapHeight, $mapLonLeft, $mapLonDelta, $mapLatBottom, $mapLatBottomDegree;

    $x = ($lon - $mapLonLeft) * ($mapWidth / $mapLonDelta);

    $lat = $lat * M_PI / 180;
    $worldMapWidth = (($mapWidth / $mapLonDelta) * 360) / (2 * M_PI);
    $mapOffsetY = ($worldMapWidth / 2 * log((1 + sin($mapLatBottomDegree)) / (1 - sin($mapLatBottomDegree))));
    $y = $mapHeight - (($worldMapWidth / 2 * log((1 + sin($lat)) / (1 - sin($lat)))) - $mapOffsetY);

    return array($x, $y);
}

$position = convertGeoToPixel(53.7, 9.95);
echo "x: ".$position[0]." / ".$position[1];

?>

这是我用 TileMill 创建的图像,我在这个例子中使用了它: 地图图像

很酷,感谢分享,很高兴有一些代码可供参考。这看起来像我最终的结果,但我最终是用 Javascript 完成的。
2021-03-17 15:56:35
@RaphaelWichmann 你有相反的想法吗?convertPixelToGeo()?我尝试将 xarinko 的答案转换为 Javascript,但没有得到相同的纬度/经度。我希望能够来回转换。
2021-03-26 15:56:35
非常感谢,这对我来说非常有用!在 javascript 中使用,它就像一个魅力
2021-03-30 15:56:35
您是否愿意发布您使用的带有这段代码的图像?谢谢!
2021-04-04 15:56:35
刚刚添加了图像。干杯,拉夫;)
2021-04-11 15:56:35

除了 Raphael Wichmann 发布的内容(顺便说一句,谢谢!),这里是反向函数,在 actionscript 中:

function convertPixelToGeo(tx:Number, ty:Number):Point
{   
    /* called worldMapWidth in Raphael's Code, but I think that's the radius since it's the map width or circumference divided by 2*PI  */   
    var worldMapRadius:Number = mapWidth / mapLonDelta * 360/(2 * Math.PI);     
    var mapOffsetY:Number = ( worldMapRadius / 2 * Math.log( (1 + Math.sin(mapLatBottomRadian) ) / (1 - Math.sin(mapLatBottomRadian))  ));
    var equatorY:Number = mapHeight + mapOffsetY;   
    var a:Number = (equatorY-ty)/worldMapRadius;

    var lat:Number = 180/Math.PI * (2 * Math.atan(Math.exp(a)) - Math.PI/2);
    var long:Number = mapLonLeft+tx/mapWidth*mapLonDelta;
    return new Point(lat,long);
}

我已将 Raphael 提供的 PHP 代码转换为 JavaScript,并且可以确认它可以工作,并且此代码自己也可以工作。所有功劳都归功于拉斐尔。

/*
var mapWidth = 1500;
var mapHeight = 1577;

var mapLonLeft = 9.8;
var mapLonRight = 10.2;
var mapLonDelta = mapLonRight - mapLonLeft;

var mapLatBottom = 53.45;
var mapLatBottomDegree = mapLatBottom * Math.PI / 180;
*/

function convertGeoToPixel(latitude, longitude ,
                           mapWidth , // in pixels
                           mapHeight , // in pixels
                           mapLonLeft , // in degrees
                           mapLonDelta , // in degrees (mapLonRight - mapLonLeft);
                           mapLatBottom , // in degrees
                           mapLatBottomDegree) // in Radians
{
    var x = (longitude - mapLonLeft) * (mapWidth / mapLonDelta);

    latitude = latitude * Math.PI / 180;
    var worldMapWidth = ((mapWidth / mapLonDelta) * 360) / (2 * Math.PI);
    var mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomDegree)) / (1 - Math.sin(mapLatBottomDegree))));
    var y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitude)) / (1 - Math.sin(latitude)))) - mapOffsetY);

    return { "x": x , "y": y};
}
谢谢你的这种转换,它对我需要的东西非常有用,我试图给你和拉斐尔投票。
2021-04-08 15:56:35

这是另一个 Javascript 实现。这是上面@Rob Willet 解决方案的简化。它不需要计算值作为函数的参数,它只需要基本值并从中计算所有内容:

function convertGeoToPixel(latitude, longitude,
                  mapWidth, // in pixels
                  mapHeight, // in pixels
                  mapLngLeft, // in degrees. the longitude of the left side of the map (i.e. the longitude of whatever is depicted on the left-most part of the map image)
                  mapLngRight, // in degrees. the longitude of the right side of the map
                  mapLatBottom) // in degrees.  the latitude of the bottom of the map
{
    const mapLatBottomRad = mapLatBottom * Math.PI / 180
    const latitudeRad = latitude * Math.PI / 180
    const mapLngDelta = (mapLngRight - mapLngLeft)

    const worldMapWidth = ((mapWidth / mapLngDelta) * 360) / (2 * Math.PI)
    const mapOffsetY = (worldMapWidth / 2 * Math.log((1 + Math.sin(mapLatBottomRad)) / (1 - Math.sin(mapLatBottomRad))))

    const x = (longitude - mapLngLeft) * (mapWidth / mapLngDelta)
    const y = mapHeight - ((worldMapWidth / 2 * Math.log((1 + Math.sin(latitudeRad)) / (1 - Math.sin(latitudeRad)))) - mapOffsetY)

    return {x, y} // the pixel x,y value of this point on the map image
}
发现。一开始以为不行,后来发现地图底部的纬度不对
2021-03-15 15:56:35

我认为值得记住的是,并非所有平面地图都是墨卡托投影。如果不特别了解那张地图,就很难确定。您可能会发现,世界上一小部分区域的大多数地图更可能是圆锥形投影,其中地图上的感兴趣区域比全球墨卡托投影“更平坦”。离赤道越远,这一点尤其重要(英国离赤道很远,这很重要)。

您可能能够使用您正在尝试的计算获得“足够接近”,但为了获得最佳精度,您可能希望使用具有明确定义的投影的地图,或者创建自己的地图。

我相当肯定它是 - 在这个页面上:en.wikipedia.org/wiki/Mercator_projection#Uses它提到谷歌地图使用投影。我将帖子中包含的地图(也可以在这里找到:en.wikipedia.org/wiki/File : Uk-map.svg叠加到谷歌地图版本上,它们完全吻合,让我觉得它是。是否仍然可以使用墨卡托投影?如果不仅是为了看看这是否能解决问题......还是我应该重新考虑我的地图?
2021-03-19 15:56:35
@betamax:嗯,看起来那张地图可能确实是墨卡托。当然可以将纬度/经度投影到现有地图上,实际上您的线性插值方法应该适用于经度。但是,对于纬度,您需要使用该维基百科页面上提供的投影方程,并计算出实际纬度与地图上的坐标之间的关系。它应该是墨卡托y和您的地图坐标之间的线性关系(意味着只有乘法和加法)y'也就是说,对于某些 A 和 B,y' = Ay + B。
2021-04-07 15:56:35