如何获得谷歌静态地图的界限?

use*_*958 16 google-maps map latitude-longitude bounds

如何获取已返回的谷歌静态地图的范围,例如,跟随请求

http://maps.googleapis.com/maps/api/staticmap?center=0.0,0.0&zoom=10&size=640x640&sensor=false
Run Code Online (Sandbox Code Playgroud)

据我所知,完整的地球地图是256x256图像.这意味着n个垂直像素包含x度,但n个水平像素包含2x度.对?

正如谷歌所说, 中心定义了地图的中心,与地图的所有边缘等距.据我所知,像素(或度数?)的等距离.并且每个后续缩放级别使水平和垂直尺寸的精度都加倍.所以,我可以找到每个缩放值的地图经度的delta值:

dLongitude = (HorizontalMapSizeInPixels / 256 ) * ( 360 / pow(2, zoom) );
Run Code Online (Sandbox Code Playgroud)

纬度的相同计算:

dLatitude = (VerticalMapSizeInPixels / 256 ) * ( 180 / pow(2, zoom) );
Run Code Online (Sandbox Code Playgroud)

VerticalMapSizeInPixels和Horizo​​ntalMapSizeInPixels是URL中地图大小的参数.

计算经度的delta值是好的,但对于Latitude它是错误的.我找不到Latitude的delta值,有一些delta错误.

Mar*_*elo 33

据我所知,完整的地球地图是256x256图像.

是.

这意味着n个垂直像素包含x度,但n个水平像素包含2x度.对?

不可以.一个像素将表示不同的纬度量,具体取决于纬度.赤道处的一个像素表示比极点附近的一个像素更小的纬度.

地图的角落将取决于中心,缩放级别和地图大小,您需要使用墨卡托投影来计算它们.如果您不想加载完整的API,这里是一个MercatorProjection对象:

var MERCATOR_RANGE = 256;

function bound(value, opt_min, opt_max) {
  if (opt_min != null) value = Math.max(value, opt_min);
  if (opt_max != null) value = Math.min(value, opt_max);
  return value;
}

function degreesToRadians(deg) {
  return deg * (Math.PI / 180);
}

function radiansToDegrees(rad) {
  return rad / (Math.PI / 180);
}

function MercatorProjection() {
  this.pixelOrigin_ = new google.maps.Point( MERCATOR_RANGE / 2, MERCATOR_RANGE / 2);
  this.pixelsPerLonDegree_ = MERCATOR_RANGE / 360;
  this.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * Math.PI);
};

MercatorProjection.prototype.fromLatLngToPoint = function(latLng, opt_point) {
  var me = this;

  var point = opt_point || new google.maps.Point(0, 0);

  var origin = me.pixelOrigin_;
  point.x = origin.x + latLng.lng() * me.pixelsPerLonDegree_;
  // NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
  // 89.189.  This is about a third of a tile past the edge of the world tile.
  var siny = bound(Math.sin(degreesToRadians(latLng.lat())), -0.9999, 0.9999);
  point.y = origin.y + 0.5 * Math.log((1 + siny) / (1 - siny)) * -me.pixelsPerLonRadian_;
  return point;
};

MercatorProjection.prototype.fromPointToLatLng = function(point) {
  var me = this;

  var origin = me.pixelOrigin_;
  var lng = (point.x - origin.x) / me.pixelsPerLonDegree_;
  var latRadians = (point.y - origin.y) / -me.pixelsPerLonRadian_;
  var lat = radiansToDegrees(2 * Math.atan(Math.exp(latRadians)) - Math.PI / 2);
  return new google.maps.LatLng(lat, lng);
};

//pixelCoordinate = worldCoordinate * Math.pow(2,zoomLevel)
Run Code Online (Sandbox Code Playgroud)

您可以将其保存到单独的文件中,例如"MercatorProjection.js",然后将其包含在您的应用程序中.

<script src="MercatorProjection.js"></script>
Run Code Online (Sandbox Code Playgroud)

加载上述文件后,以下函数计算给定大小和给定缩放的地图的SW和NE角.

function getCorners(center,zoom,mapWidth,mapHeight){
    var scale = Math.pow(2,zoom);
    var centerPx = proj.fromLatLngToPoint(center);
    var SWPoint = {x: (centerPx.x -(mapWidth/2)/ scale) , y: (centerPx.y + (mapHeight/2)/ scale)};
    var SWLatLon = proj.fromPointToLatLng(SWPoint);
    alert('SW: ' + SWLatLon);
    var NEPoint = {x: (centerPx.x +(mapWidth/2)/ scale) , y: (centerPx.y - (mapHeight/2)/ scale)};
    var NELatLon = proj.fromPointToLatLng(NEPoint);
    alert(' NE: '+ NELatLon);
}
Run Code Online (Sandbox Code Playgroud)

你会这样称呼它:

var proj = new MercatorProjection();
var G = google.maps;
var centerPoint = new G.LatLng(49.141404, -121.960988);
var zoom = 10;
getCorners(centerPoint,zoom,640,640);
Run Code Online (Sandbox Code Playgroud)


jma*_*gue 15

谢谢马塞洛的回答.这非常有帮助.万一有人会感兴趣,这里是代码的Python版本(PHP代码的粗略翻译,可能不像pythonic那样):

from __future__ import division
import math
MERCATOR_RANGE = 256

def  bound(value, opt_min, opt_max):
  if (opt_min != None): 
    value = max(value, opt_min)
  if (opt_max != None): 
    value = min(value, opt_max)
  return value


def  degreesToRadians(deg) :
  return deg * (math.pi / 180)


def  radiansToDegrees(rad) :
  return rad / (math.pi / 180)


class G_Point :
    def __init__(self,x=0, y=0):
        self.x = x
        self.y = y



class G_LatLng :
    def __init__(self,lt, ln):
        self.lat = lt
        self.lng = ln


class MercatorProjection :


    def __init__(self) :
      self.pixelOrigin_ =  G_Point( MERCATOR_RANGE / 2, MERCATOR_RANGE / 2)
      self.pixelsPerLonDegree_ = MERCATOR_RANGE / 360
      self.pixelsPerLonRadian_ = MERCATOR_RANGE / (2 * math.pi)


    def fromLatLngToPoint(self, latLng, opt_point=None) :
      point = opt_point if opt_point is not None else G_Point(0,0)
      origin = self.pixelOrigin_
      point.x = origin.x + latLng.lng * self.pixelsPerLonDegree_
      # NOTE(appleton): Truncating to 0.9999 effectively limits latitude to
      # 89.189.  This is about a third of a tile past the edge of the world tile.
      siny = bound(math.sin(degreesToRadians(latLng.lat)), -0.9999, 0.9999)
      point.y = origin.y + 0.5 * math.log((1 + siny) / (1 - siny)) * -     self.pixelsPerLonRadian_
      return point


def fromPointToLatLng(self,point) :
      origin = self.pixelOrigin_
      lng = (point.x - origin.x) / self.pixelsPerLonDegree_
      latRadians = (point.y - origin.y) / -self.pixelsPerLonRadian_
      lat = radiansToDegrees(2 * math.atan(math.exp(latRadians)) - math.pi / 2)
      return G_LatLng(lat, lng)

#pixelCoordinate = worldCoordinate * pow(2,zoomLevel)

def getCorners(center, zoom, mapWidth, mapHeight):
    scale = 2**zoom
    proj = MercatorProjection()
    centerPx = proj.fromLatLngToPoint(center)
    SWPoint = G_Point(centerPx.x-(mapWidth/2)/scale, centerPx.y+(mapHeight/2)/scale)
    SWLatLon = proj.fromPointToLatLng(SWPoint)
    NEPoint = G_Point(centerPx.x+(mapWidth/2)/scale, centerPx.y-(mapHeight/2)/scale)
    NELatLon = proj.fromPointToLatLng(NEPoint)
    return {
        'N' : NELatLon.lat,
        'E' : NELatLon.lng,
        'S' : SWLatLon.lat,
        'W' : SWLatLon.lng,
    }
Run Code Online (Sandbox Code Playgroud)

用法:

>>> import MercatorProjection
>>> centerLat = 49.141404
>>> centerLon = -121.960988
>>> zoom = 10
>>> mapWidth = 640
>>> mapHeight = 640
>>> centerPoint = MercatorProjection.G_LatLng(centerLat, centerLon)
>>> corners = MercatorProjection.getCorners(centerPoint, zoom, mapWidth, mapHeight)
>>> corners
{'E': -65.710988,
'N': 74.11120692972199,
'S': 0.333879313530149,
'W': -178.210988}
>>> mapURL = "http://maps.googleapis.com/maps/api/staticmap?center=%f,%f&zoom=%d&size=%dx%d&scale=2&maptype=roadmap&sensor=false"%(centerLat,centerLon,zoom,mapWidth,mapHeight)
>>> mapURL
http://maps.googleapis.com/maps/api/staticmap?center=49.141404,-121.960988&zoom=10&size=640x640&scale=2&maptype=roadmap&sensor=false'
Run Code Online (Sandbox Code Playgroud)

  • 越野车:缩放应定义为2**比例,而不是2 ^比例,这是2和比例之间的按位异或 (2认同)

小智 5

简单Python版本

在解决类似问题上花费了很长时间并使用此线程寻求帮助后,这里是 Marcelo(和 Jmague)代码的简化 Python 版本:

import math
import requests

def latLngToPoint(mapWidth, mapHeight, lat, lng):

    x = (lng + 180) * (mapWidth/360)
    y = ((1 - math.log(math.tan(lat * math.pi / 180) + 1 / math.cos(lat * math.pi / 180)) / math.pi) / 2) * mapHeight

    return(x, y)

def pointToLatLng(mapWidth, mapHeight, x, y):

    lng = x / mapWidth * 360 - 180

    n = math.pi - 2 * math.pi * y / mapHeight
    lat = (180 / math.pi * math. atan(0.5 * (math.exp(n) - math.exp(-n))))

    return(lat, lng)

def getImageBounds(mapWidth, mapHeight, xScale, yScale, lat, lng):

    centreX, centreY = latLngToPoint(mapWidth, mapHeight, lat, lng)

    southWestX = centreX - (mapWidth/2)/ xScale
    southWestY = centreY + (mapHeight/2)/ yScale
    SWlat, SWlng = pointToLatLng(mapWidth, mapHeight, southWestX, southWestY)

    northEastX = centreX + (mapWidth/2)/ xScale
    northEastY = centreY - (mapHeight/2)/ yScale
    NElat, NElng = pointToLatLng(mapWidth, mapHeight, northEastX, northEastY)

    return[SWlat, SWlng, NElat, NElng]

lat = 37.806716
lng = -122.477702
zoom = 16
picHeight = 640 #Resulting image height in pixels (x2 if scale parameter is set to 2)
picWidth = 640

mapHeight = 256 #Original map size - specific to Google Maps
mapWidth = 256

xScale = math.pow(2, zoom) / (picWidth/mapWidth)
yScale = math.pow(2, zoom) / (picHeight/mapWidth)

corners = getImageBounds(mapWidth, mapHeight, xScale, yScale, lat, lng)
Run Code Online (Sandbox Code Playgroud)

在这里,我使用 x 和 y 表示像素值,并使用 lat lng 表示纬度和经度。lat、lng、zoom、picHeight 和 picWidth 都可以根据您的特定用例进行更改。更改比例/地图类型等不会影响此计算。

我使用此代码平铺静态地图图像,没有间隙/重叠。如果您想了解更多它的使用/它如何在这个意义上工作,我的GitHub上有更多信息。