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

时间:2010-01-20 18:33:24

标签: javascript geolocation projection processing.js proj4js

我有这张图片:http://imgur.com/99tSz.png。英国地图(不包括南爱尔兰)。

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

这是代码(用于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);    

}

但是,我无法对这些值实施墨卡托投影。这些图很合理,但它们不够好,这个投影可以解决它。

我无法弄明白该怎么做。我找到的所有例子都在解释如何为整个世界做这件事。 This是解释如何实施预测的一个很好的示例资源,但我无法让它发挥作用。

另一个资源是Extreme points of the United Kingdom,我获得了英国各地边界框的纬度和经度值。他们也在这里:

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

如果有人能帮助我,我会非常感激!

由于

10 个答案:

答案 0 :(得分:39)

我写了一个功能,它完全符合您的要求。我知道这有点晚了,但也许还有其他人对此感兴趣。

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

我正在使用此脚本并使用一些Google地球位置进行测试。它在像素级别上工作得很好。实际上我没有在不同或更大的地图上测试这个。我希望它可以帮到你!

拉斐尔;)

<?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创建的图像以及我在此示例中使用的图像:map image

答案 1 :(得分:10)

除了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);
}

答案 2 :(得分:9)

我已将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};
}

答案 3 :(得分:7)

我认为值得注意的是,并非所有平面地图都是墨卡托投影。如果不了解更多有关该地图的信息,很难确定。您可能会发现世界上一小块区域的大多数地图更可能是圆锥形类型投影,其中地图上感兴趣的区域比全球墨卡托投影上的“更平坦” 。这一点尤其重要的是你越远离赤道(英国远远不够了)。

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

答案 4 :(得分:5)

这是另一个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
}

答案 5 :(得分:4)

我知道问题是在不久前问过的,但Proj4JS库非常适合在JavaScript中的不同地图投影之间进行转换。

英国地图倾向于使用OSGB的国家网格,该网格基于横轴墨卡托投影。 IE浏览器。就像传统的墨卡托一样转动90度,使“赤道”成为经络。

答案 6 :(得分:3)

Javascript中的@Xarinko Actionscript片段(包含一些测试值)

var mapWidth = 1500;
var mapHeight = 1577;

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

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



function convertPixelToGeo(tx, ty)
{   
    /* 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 = mapWidth / mapLonDelta * 360/(2 * Math.PI);     
    var mapOffsetY = ( worldMapRadius / 2 * Math.log( (1 + Math.sin(mapLatBottomRadian) ) / (1 - Math.sin(mapLatBottomRadian))  ));
    var equatorY = mapHeight + mapOffsetY;   
    var a = (equatorY-ty)/worldMapRadius;

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

convertPixelToGeo(241,444)

答案 7 :(得分:0)

如果你想避免Proj4JS内在的lat / lng投影的一些杂乱的方面,你可以使用D3,它提供许多烘焙投影和渲染精美。这是几种方位角投影的interactive example。我更喜欢阿尔伯斯的美国地图。

如果D3不是最终用户选项 - 比如说,你需要支持IE 7/8 - 你可以在D3中渲染,然后从D3生成的结果SVG文件中获取xy坐标。然后,您可以在Raphael中渲染这些xy坐标。

答案 8 :(得分:0)

这个功能对我很有用,因为我想根据我想要绘制的地图定义mapHeight。我正在生成PDF地图。我需要做的就是传递地图的最大Lat,min Lon并将地图的像素大小作为[height,width]返回。

convertGeoToPixel(maxlatitude,maxlongitude)

设置$ y的最后一步中的一个注释,如果您的坐标系'xy'从底部/左侧开始,请不要从mapHeight中减去计算,就像使用PDF一样,这将反转地图。

person.name

答案 9 :(得分:0)

C#实现:

private Point ConvertGeoToPixel(
    double latitude, double longitude, // The coordinate to translate
    int imageWidth, int imageHeight, // The dimensions of the target space (in pixels)
    double mapLonLeft, double mapLonRight, double mapLatBottom // The bounds of the target space (in geo coordinates)
) {
    double mapLatBottomRad = mapLatBottom * Math.PI / 180;
    double latitudeRad = latitude * Math.PI / 180;

    double mapLonDelta = mapLonRight - mapLonLeft;
    double worldMapWidth = (imageWidth / mapLonDelta * 360) / (2 * Math.PI);
    double mapOffsetY = worldMapWidth / 2 * Math.Log((1 + Math.Sin(mapLatBottomRad)) / (1 - Math.Sin(mapLatBottomRad)));

    double x = (longitude - mapLonLeft) * (imageWidth / mapLonDelta);
    double y = imageHeight - ((worldMapWidth / 2 * Math.Log((1 + Math.Sin(latitudeRad)) / (1 - Math.Sin(latitudeRad)))) - mapOffsetY);

    return new Point()
    {
        X = Convert.ToInt32(x),
        Y = Convert.ToInt32(y)
    };
}