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

我有这个形象: 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); } 

但是,我还没有能够对这些值实施墨卡托投影。 情节是相当准确的,但他们不够好,这个预测将解决它。

我无法弄清楚如何去做。 我发现的所有例子都是为了解释整个世界如何去做。 这是解释如何实现投影的例子的一个很好的资源,但我还没有能够得到它的工作。

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

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

如果有人能帮助我,我将不胜感激!

谢谢

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

您可能能够使用您正在尝试的计算“足够接近”,但为了获得最佳准确性,您可能需要使用定义明确的投影的地图,或创build自己的地图。

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

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

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

拉斐尔;)

 <?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创build的图像,我在这个例子中使用了: 地图图像

除了Raphael Wichmann发布的内容(谢谢,顺便说一下!),这里是相反的function,在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}; } 

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

英国地图倾向于使用基于横轴墨卡托投影的OSGB国家网格。 IE浏览器。 像一个传统的墨卡托,但转过90度,使“赤道”成为一条子午线。

Javascript中的@Xarinko Actionscript片段(带有一些testing值)

 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) 

如果你想避免Proj4JS固有的纬度/经度投影的一些混乱的方面,你可以使用D3,它提供了许多烘焙的投影和渲染漂亮。 这里有几种Azimuthal投影的交互式例子 。 我更喜欢Albers的美国地图。

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

这个函数对我很好,因为我想根据我想要绘制的地图来定义mapHeight。 我正在生成PDF地图。 我所需要做的就是传入地图的最大纬度,最小值Lon,然后返回地图的像素大小[高度,宽度]。

convertGeoToPixel(maxlatitude,maxlongitude)

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

 $y = (($worldMapWidth / 2 * log((1 + sin($lat)) / (1 - sin($lat)))) - $mapOffsetY); 

这是另一个Javascript实现。 这是@Rob Willet解决scheme的简化。 它不需要计算值作为函数的参数,它只需要基本的值并计算它们的一切:

 function convertGeoToPixel(latitude, longitude, mapWidth, // in pixels mapHeight, // in pixels mapLngLeft, // in degrees. the longitude of the left side of the map (ie 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 }