2012-09-20 38 views
12

如何获得在已经回来了,例如,对于下面的请求如何获得谷歌静态地图的界限?

http://maps.googleapis.com/maps/api/staticmap?center=0.0,0.0&zoom=10&size=640x640&sensor=false 

据我所知度的谷歌静态地图界限,全地球的地图是256×256的图像。这意味着n个垂直像素包含x度,但是n个水平像素包含2x度。对?

作为谷歌says 中心定义了地图的中心,与地图的所有边等距。正如我理解的像素等距(或度数?)。随后的每个缩放级别都将水平和垂直维度的精度加倍。

dLongitude = (HorizontalMapSizeInPixels/256) * (360/pow(2, zoom)); 

的纬度相同的计算: 所以,我可以为每个变焦价值发现地图的经度的delta值

dLatitude = (VerticalMapSizeInPixels/256) * (180/pow(2, zoom)); 

VerticalMapSizeInPixels和Horizo​​ntalMapSizeInPixels在URL映射大小的参数。

很好计算经度的增量值,但是对于纬度来说它是错误的。我找不到纬度的delta值,有一些 delta错误。

+0

的可能的复制http://stackoverflow.com/questions/4730885/how-do-i-get-the-bounds-of-a-static-google-map?rq=1 – j0nes

回答

30

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

是的。

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

编号一个像素将代表纬度的不同数量的纬度。赤道上的一个像素表示比极点附近的一个像素更少的纬度。

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

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) 

您可以在保存为一个单独的文件,例如“MercatorProjection.js”,然后将其包含在您的应用程序。

<script src="MercatorProjection.js"></script> 

随着装载上述文件,下面的函数计算地图上的给定尺寸和在给定的缩放的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); 
} 

,你会这样称呼它:

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); 
+0

的精确度如何这个?我将它移植到java,我必须说我真的很满意它!我只有几米。我想知道这是算法还是我犯了一个错误。出于某种原因,我必须将getCorners中的规模与2.0的其他规模相提并论。 – clankill3r

+0

GOT IT我有一个size = 1024x1024的请求。它给了我一个我不知道的1080x1080的图像!所以我确实对一个小区域进行了检查。造成一个小区域... – clankill3r

+0

嘿@marcelo,我的代码翻译成C#出现问题。关于这个问题的更多信息[这里](http://stackoverflow.com/questions/37008037/get-sw-ne-corners-of-google-static-maps-api) – Leniaal

2

这里是由马塞洛在PHP代码,这或许可以被清理位线转换线。很棒!感谢马塞洛做出艰难的一部分。

define("MERCATOR_RANGE", 256); 

function degreesToRadians($deg) { 
    return $deg * (M_PI/180); 
} 

function radiansToDegrees($rad) { 
    return $rad/(M_PI/180); 
} 

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

class G_Point { 
    public $x,$y; 
    function G_Point($x=0, $y=0){ 
     $this->x = $x; 
     $this->y = $y; 
    } 
} 

class G_LatLng { 
    public $lat,$lng; 
    function G_LatLng($lt, $ln){ 
     $this->lat = $lt; 
     $this->lng = $ln; 
    } 
} 

class MercatorProjection { 

    private $pixelOrigin_, $pixelsPerLonDegree_, $pixelsPerLonRadian_; 

    function MercatorProjection() { 
     $this->pixelOrigin_ = new G_Point(MERCATOR_RANGE/2, MERCATOR_RANGE/2); 
     $this->pixelsPerLonDegree_ = MERCATOR_RANGE/360; 
     $this->pixelsPerLonRadian_ = MERCATOR_RANGE/(2 * M_PI); 
    } 

    public function fromLatLngToPoint($latLng, $opt_point=null) { 
     $me = $this; 

     $point = $opt_point ? $opt_point : new G_Point(0,0); 

     $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. 
     $siny = bound(sin(degreesToRadians($latLng->lat)), -0.9999, 0.9999); 
     $point->y = $origin->y + 0.5 * log((1 + $siny)/(1 - $siny)) * -$me->pixelsPerLonRadian_; 
     return $point; 
    } 

    public function fromPointToLatLng($point) { 
     $me = $this; 

     $origin = $me->pixelOrigin_; 
     $lng = ($point->x - $origin->x)/$me->pixelsPerLonDegree_; 
     $latRadians = ($point->y - $origin->y)/-$me->pixelsPerLonRadian_; 
     $lat = radiansToDegrees(2 * atan(exp($latRadians)) - M_PI/2); 
     return new G_LatLng($lat, $lng); 
    } 

    //pixelCoordinate = worldCoordinate * pow(2,zoomLevel) 
} 

function getCorners($center, $zoom, $mapWidth, $mapHeight){ 
    $scale = pow(2, $zoom); 
    $proj = new MercatorProjection(); 
    $centerPx = $proj->fromLatLngToPoint($center); 
    $SWPoint = new G_Point($centerPx->x-($mapWidth/2)/$scale, $centerPx->y+($mapHeight/2)/$scale); 
    $SWLatLon = $proj->fromPointToLatLng($SWPoint); 
    $NEPoint = new G_Point($centerPx->x+($mapWidth/2)/$scale, $centerPx->y-($mapHeight/2)/$scale); 
    $NELatLon = $proj->fromPointToLatLng($NEPoint); 
    return array(
     'N' => $NELatLon->lat, 
     'E' => $NELatLon->lng, 
     'S' => $SWLatLon->lat, 
     'W' => $SWLatLon->lng, 
    ); 
} 

用法:

$centerLat = 49.141404; 
$centerLon = -121.960988; 
$zoom = 10; 
$mapWidth = 640; 
$mapHeight = 640; 
$centerPoint = new G_LatLng($centerLat, $centerLon); 
$corners = getCorners($centerPoint, $zoom, $mapWidth, $mapHeight); 
$mapURL = "http://maps.googleapis.com/maps/api/staticmap?center={$centerLat},{$centerLon}&zoom={$zoom}&size={$mapWidth}x{$mapHeight}&scale=2&maptype=roadmap&sensor=false"; 
12

马塞洛感谢您的回答。这非常有帮助。如果有人有兴趣,这里的代码的Python版本(PHP代码的一个粗略的翻译,可能并不像Python的,因为它可以):

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, 
    } 

用法:

>>> 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' 
+2

Buggy:缩放应该定义为2 **缩放比例,而不是2 ^缩放比例,这是2和缩放比例之间的按位异或 – jmague

0

这里是翻译到德尔福/帕斯卡与一些优化,以对应更严格的帕斯卡尔语言和内存管理。

unit Mercator.Google.Maps; 

interface 

uses System.Math; 

type TG_Point = class(TObject) 
    private 
     Fx: integer; 
     Fy: integer; 
    public 
     property x: integer read Fx write Fx; 
     property y: integer read Fy write Fy; 

     constructor Create(Ax: integer = 0; Ay: integer = 0); 
end; 

type TG_LatLng = class(TObject) 
    private 
     FLat: double; 
     FLng: double; 
    public 
     property Lat: double read FLat write FLat; 
     property Lng: double read FLng write FLng; 

     constructor Create(ALat: double; ALng: double); 
end; 

type TMercatorProjection = class(TObject) 
    private 
     pixelOrigin_: TG_Point; 
     pixelsPerLonDegree_, pixelsPerLonRadian_: double; 

     function degreesToRadians(deg: double): double; 
     function radiansToDegrees(rad: double): double; 
     function bound(value: double; opt_min: double; opt_max: double): double; 
    public 
     constructor Create; 
     procedure fromLatLngToPoint(latLng: TG_LatLng; var point: TG_Point); 
     procedure fromPointToLatLng(point: TG_point; var latLng: TG_LatLng); 
     procedure getCorners(center: TG_LatLng; zoom: integer; mapWidth: integer; mapHeight: integer; 
          var NELatLon: TG_LatLng; var SWLatLon: TG_LatLng); 
end; 

implementation 

const MERCATOR_RANGE = 256; 

constructor TG_Point.Create(Ax: Integer = 0; Ay: Integer = 0); 
begin 
    inherited Create; 
    Fx := Ax; 
    Fy := Ay 
end; 

// ************** 

constructor TG_LatLng.Create(ALat: double; ALng: double); 
begin 
    inherited Create; 
    FLat := ALat; 
    FLng := ALng 
end; 

// ************** 

constructor TMercatorProjection.Create; 
begin 
    inherited Create; 

    pixelOrigin_ := TG_Point.Create(Round(MERCATOR_RANGE/2), Round(MERCATOR_RANGE/2)); 
    pixelsPerLonDegree_ := MERCATOR_RANGE/360; 
    pixelsPerLonRadian_ := MERCATOR_RANGE/(2 * PI); 
end; 

// Translate degrees to radians 
function TMercatorProjection.degreesToRadians(deg: double): double; 
begin 
    Result := deg * (PI/180); 
end; 

// Translate radians to degrees 
function TMercatorProjection.radiansToDegrees(rad: double): double; 
begin 
    Result := rad/(PI/180); 
end; 

// keep value insid defined bounds 
function TMercatorProjection.bound(value: double; opt_min: double; opt_max: double): double; 
begin 
    if Value < opt_min then Result := opt_min 
    else if Value > opt_max then Result := opt_max 
    else Result := Value; 
end; 

procedure TMercatorProjection.fromLatLngToPoint(latLng: TG_LatLng; var point: TG_Point); 
var 
    siny: double; 
begin 
    if Assigned(point) then 
    begin 
     point.x := Round(pixelOrigin_.x + latLng.lng * 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(sin(degreesToRadians(latLng.lat)), -0.9999, 0.9999); 
     point.y := Round(pixelOrigin_.y + 0.5 * ln((1 + siny)/(1 - siny)) * -pixelsPerLonRadian_); 
    end; 
end; 

procedure TMercatorProjection.fromPointToLatLng(point: TG_point; var latLng: TG_LatLng); 
var 
    latRadians: double; 
begin 
    if Assigned(latLng) then 
    begin 
     latLng.lng := (point.x - pixelOrigin_.x)/pixelsPerLonDegree_; 
     latRadians := (point.y - pixelOrigin_.y)/-pixelsPerLonRadian_; 
     latLng.lat := radiansToDegrees(2 * arctan(exp(latRadians)) - PI/2); 
    end; 
end; 

//pixelCoordinate = worldCoordinate * pow(2,zoomLevel) 

procedure TMercatorProjection.getCorners(center: TG_LatLng; zoom: integer; mapWidth: integer; mapHeight: integer; 
        var NELatLon: TG_LatLng; var SWLatLon: TG_LatLng); 
var 
    scale: double; 
    centerPx, SWPoint, NEPoint: TG_Point; 
begin 
    scale := power(2, zoom); 

    centerPx := TG_Point.Create(0, 0); 
    try 
     fromLatLngToPoint(center, centerPx); 
     SWPoint := TG_Point.Create(Round(centerPx.x-(mapWidth/2)/scale), Round(centerPx.y+(mapHeight/2)/scale)); 
     NEPoint := TG_Point.Create(Round(centerPx.x+(mapWidth/2)/scale), Round(centerPx.y-(mapHeight/2)/scale)); 
     try 
      fromPointToLatLng(SWPoint, SWLatLon); 
      fromPointToLatLng(NEPoint, NELatLon); 
     finally 
      SWPoint.Free; 
      NEPoint.Free; 
     end; 
    finally 
     centerPx.Free; 
    end; 
end; 

end. 

用例:

  with TMercatorProjection.Create do 
      try 
       CLatLon := TG_LatLng.Create(Latitude, Longitude); 
       SWLatLon := TG_LatLng.Create(0,0); 
       NELatLon := TG_LatLng.Create(0,0); 
       try 
        getCorners(CLatLon, Zoom, 
           MapWidth, MapHeight, 
           SWLatLon, NELatLon); 
       finally 
        ShowMessage('SWLat='+FloatToStr(SWLatLon.Lat)+' | SWLon='+FloatToStr(SWLatLon.Lng)); 
        ShowMessage('NELat='+FloatToStr(NELatLon.Lat)+' | NELon='+FloatToStr(NELatLon.Lng)); 

        SWLatLon.Free; 
        NELatLon.Free; 
        CLatLon.Free; 
       end; 
      finally 
       Free; 
      end; 
0

对于大缩放因子(> = 8),其中在y轴上的地图比例尺的不均匀性可以忽略不计,有更容易的方法,在那里我们只是考虑像素/(纬度)分辨率的1/cos(纬度)校正。 x = 0时,zoom = 0的初始分辨率为360度/ 360度。

def get_static_map_bounds(lat, lng, zoom, sx, sy): 
    # lat, lng - center 
    # sx, sy - map size in pixels 

    # 256 pixels - initial map size for zoom factor 0 
    sz = 256 * 2 ** zoom 

    #resolution in degrees per pixel 
    res_lat = cos(lat * pi/180.) * 360./sz 
    res_lng = 360./sz 

    d_lat = res_lat * sy/2 
    d_lng = res_lng * sx/2 

    return ((lat-d_lat, lng-d_lng), (lat+d_lat, lng+d_lng))