墨卡托投影稍微偏离

时间:2014-12-22 08:05:07

标签: python python-2.7

我正在构建一个需要大量谷歌地图图像的项目。我将这些函数定义为在另一个自动收集图像的函数中使用。纬度变化很好,但我注意到经度略有偏差。这是近似墨卡托投影方法的神器吗?我的印象是,除了接近两极以外,我使用的转换非常准确。

import math
import os
import DLMaps
#Finds the distance covered in a Static Maps image pixel
def PixDist(zoom,scale=2):
    earthCirc = 40075.0 #in Km's
    base = 256 #size of google maps at zoom = 0
    return earthCirc/(base*scale*(2**zoom))

#Finds the Km distance to the next google static maps image based on size of images,
# and distance per pixel
def DistNextImage(distpp, scale=2, size=640):
    return distpp*scale*size

#returns a new Lat, Lon co-ordinate given a starting point, km distance change and
# a NESW direction, values 1-4 being used to represent corresponding direction.
def NewLatLon(lat,lon, dist, direction):
    if direction==1:
        dist = dist/110.54 #approximate change in latitude mercator projection
        lat = lat + dist #heading north
    elif direction == 2:
        dist = dist/(110.32 * math.cos(math.pi*lat/180.0)) #approx change in lon
        lon = lon + dist
    elif direction==3:
        dist = dist/110.54 #approximate change in latitude mercator projection
        lat = lat - dist #heading south
    elif direction ==4:
        dist = dist/(110.32 * math.cos(math.pi*lat/180.0)) #approx change in lon
        lon = lon - dist
    return lat, lon

2 个答案:

答案 0 :(得分:3)

地球不是真正的椭圆体,有大量的坐标系,从一个系统传递到另一个系统远非简单。您可以查看pyproj与众所周知的proj.4库的Python接口,以便将Lat-Lon(我假设WGS84 ...)转换为几乎任何其他坐标,当然包括Mercator。你可以尝试自己动手,但是有很多警告,例如不同的原点经络,参考椭球的微小差异,你没有希望得到正确和准确的结果。

但是你在wikipedia

上的WGS84上有一些参考资料

答案 1 :(得分:2)

我做了一个做类似计算的对象。也许它可能会给你一些灵感。 基本上我把地球当作一个椭圆体。沿着赤道的地球沿着地球穿过两极并不一样。 我尝试在米之间的距离之间进行转换< - >纬度和角度LNG。

看看我的对象是否比你的更准确(如果你使用了一些极端值,我肯定会有错误)

/**
* @file:  Javascript object to help calculate with latitude, longitude, together with distances (in meter) and angles.
* The initial goal was to calculate the end point (in lat and latitude & longitude) of a line perpendicular to another line.
*
* Planet Earth is approximately an ellipsoid.  The circumference along the equator is
*   somewhat greater than the equator through both poles.
* this javascript object makes calculations that are useful for Google Maps. 
*   This will allow to use pythagoras for coordinates, as if earth is a flat rectangle.
* The precision of the results decreases when the distances increase; and near the poles.
*   Any calculation where the latitude goes beyond the poles ( > 90 or < -90 ) will probably return complete nonsence.
* 
* @author: Emmanuel Delay, emmanueldelay@gmail.com
* copyleft 2014.  Feel free to use, copy, share, improve
*  Please send me the code, if you make improvements.
* 
* Examples:
<script>
  function log(message) {
    document.getElementById('log').innerHTML += message + '<br>';
  }
  window.onload = function() {       
    var dLatLng = Earth.xy2LatLng(5000000, 5000000, 0.0);
    latLng = [dLatLng.lat, dLatLng.lng ]; 
    log(
      'Start from 0,0 ; move 5000km to the north, 5000km to the east: ' +
      latLng[0] +','+ latLng[1]
    );

    var eifel = {lat: 48.8582186, lng: 2.2946114};
    var dLatLng = Earth.xy2LatLng(1000, 2000, eifel.lat);

    latLng = [dLatLng.lat, dLatLng.lng ];
    var dest = [eifel.lat + latLng[0], eifel.lng + latLng[1] ];
    log(
      'Move 1km to the north, 2km to the east of the Eifel Tower: ' +
      dest[0] +','+ dest[1] 
    );

    var dLatLng = Earth.setHeading(eifel.lat, eifel.lng, 10000, 30);
    latLng = [dLatLng.lat, dLatLng.lng ]; 
    log(
      'Move 10km from the Eifel Tower, heading 30° (North = 0; east = 90°; ...): ' +
      latLng[0] +','+ latLng[1]
    );
  }
</script>
<div id="log"></div>

  * note: 
  *   - all distances are in meter.  all angles are in degree
  *   - the d in dLat and dLng stands for delta, being a change in coordinates
  *   - x is along the longitude, y is along latitude
  */

Earth = {
    // @see http://www.space.com/17638-how-big-is-earth.html for the data
    // along the equator
  circumference_equator: 40075000,    
   // throught both poles.
   // Note: this is basically the original definition of the meter; they were 2km off on a distance from pole to equator ( http://en.wikipedia.org/wiki/History_of_the_metre )
  circumference_poles: 40008000,              
  // given a change in latitude, how many meters did you move?
  lat2Y: function(dLat) {
    return this.circumference_poles / 360 * dLat;
  },
  // given a change in longitude and a given latitude, how many meters did you move?
  lng2X: function(dLng, lat) {
    return Math.cos( this.deg2rad(lat) ) * (this.circumference_poles / 360 * dLng);
  },
  // given a distance you move due North (or South), what's the new coordinates?
  // returns a change in latitude
  y2Lat: function(y) {
    return y * 360 / this.circumference_poles;
  },
  // given a distance you move due East (or West) and a given latitude, what's the new coordinates?
  // returns a change in longitude
  x2Lng: function(x, lat) {
    return x * 360 / ( Math.cos( this.deg2rad(lat) ) * this.circumference_poles);
  },
  // (360°) degrees to radials
  deg2rad: function(deg) {
    return deg * Math.PI / 180;
  },
  // returns a change in position
  xy2LatLng: function(y, x, lat) {
    return {
      lat: this.y2Lat(y),
      lng: this.x2Lng(x, lat)
    };
  },
  // @param heading: North = 0; east = 90°; ...
  // returns a change in position
  setHeading: function(lat, lng, dist, heading) {
    var latDestination = lat +  this.y2Lat(dist * Math.cos(this.deg2rad(heading)));
    var lngDestination = lng +  this.x2Lng(dist * Math.sin(this.deg2rad(heading)), lat);
    return {
      lat: latDestination,
      lng: lngDestination
    };
  },
  // returns the absolute position
  moveByXY: function(lat, lng, x, y) {
    var dLatLng = Earth.xy2LatLng(x, y, lat);
    latLng = [dLatLng.lat, dLatLng.lng ];
    return {
      lat: lat + latLng[0], 
      lng: lng + latLng[1]
    }
  }
}