2012-09-20 67 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))