2012-10-02 87 views
9

我使用.NET從靜態地圖使用Google地圖加載地圖圖塊。谷歌地圖靜態API - 通過中心座標獲取SW和NE

我遇到的問題是,我不知道是什麼SW和NE座標返回的形象。

我發現很多不同的代碼示例,公式,但他們似乎都存在缺陷。 這是最接近正確答案的人。當我在Google Maps中輸入座標時,顯示它有點偏離。

var result = GoogleMapsAPI.GetBounds(new Coordinate(4.79635, 51.15479), 20, 512, 512); 

public static class GoogleMapsAPI 
{ 
    public static MapCoordinates GetBounds(Coordinate center, int zoom, int mapWidth, int mapHeight) 
    { 
     var scale = Math.Pow(2, zoom); 

     var SWPoint = new Coordinate(center.X - (mapWidth/2)/scale, center.Y - (mapHeight/2)/scale); 
     var NEPoint = new Coordinate(center.X + (mapWidth/2)/scale, center.Y + (mapHeight/2)/scale); 

     return new MapCoordinates() { SouthWest = SWPoint, NorthEast = NEPoint }; 
    } 
} 

public class MapCoordinates 
{ 
    public Coordinate SouthWest { get; set; } 
    public Coordinate NorthEast { get; set; } 
} 

public class Coordinate 
{ 
    public double Latitude { get; set; } 
    public double Longitude { get; set; } 

    public double X { get { return Latitude; } set { Latitude = value; } } 
    public double Y { get { return Longitude; } set { Longitude = value; } } 

    public Coordinate(double lat, double lng) 
    { 
     Latitude = lat; 
     Longitude = lng; 
    } 

    public override string ToString() 
    { 
     return X.ToString() + ", " + Y.ToString(); 
    } 
} 

來源:
How to get bounds of a google static map?
http://www.easywms.com/easywms/?q=zh-hans/node/3612

由中心加載的圖像座標:
http://maps.googleapis.com/maps/api/staticmap?center=51.15479,4.79635&zoom=20&size=512x512&sensor=false

故障SW:
https://maps.google.be/maps?q=51.154545859375,+4.796105859375&hl=en&ll=51.154763,4.796695&spn=0.000568,0.001635&sll=51.154687,4.796838&sspn=0.001136,0.00327&t=m&z=20

故障NE:
https://maps.google.be/maps?q=+51.155034140625,+4.796594140625&hl=en&ll=51.154764,4.796684&spn=0.000568,0.001635&sll=51.154599,4.796723&sspn=0.001136,0.00327&t=m&z=20

回答

4

編輯:哇,我剛剛意識到這個問題差不多兩歲了。對於那個很抱歉。

好吧,我想這裏有一些事情要做。最重要的是你沒有在你提供的鏈接中提到的墨卡託投影。您可以在Google地圖API文檔中使用code sample來查看它。我認爲你有點接近的原因是縮放比例因子在縮放級別20非常大,以至於淹沒了問題的細節。

要獲得邊界,需要取中心緯度/經度,將其轉換爲像素座標,加/減得到所需角點的像素座標,然後再轉換回緯度/經度。第一個鏈接中的代碼可以進行投影和反向投影。下面我將它翻譯成c#。

在你上面的解決方案,你正在服用經/緯度座標和加法/減法世界座標(像素COORDS /縮放),所以你將兩個不同的座標系。

我跑進試圖想出解決辦法的一個問題是,你的Coordinate類是有點混亂。希望我沒有倒退,但看起來你正在向後經緯度。這很重要,因爲除了其他原因,墨卡託投影在每個方向都不相同。您的X/Y映射也似乎向後,因爲緯度是您的北/南位置,投影時應該是Y座標,而經度是東/西位置,投影時應該是X座標。

要查找的範圍,three coordinate systems需要:經度/緯度,世界座標和像素座標。過程是Center Lat/Lon - (墨卡託投影) - >中心世界座標 - >中心像素座標 - > NE/SW像素座標 - > NE/SW世界座標 - (逆墨卡託投影) - > NE/SW緯度/ 。

您可以通過添加/減去圖像的尺寸/ 2來查找像素座標。像素座標系從左上角開始,所以爲了得到NE角,需要從x中增加寬度/ 2並從y中減去高度/ 2。對於SW角,您需要從x中減去寬度/ 2並將高度/ 2添加到y。

這裏是C#中的投影代碼(如您的GoogleMapsAPI類的一部分),翻譯從上面的JavaScript的第一個鏈接:

static GoogleMapsAPI() 
{ 
    OriginX = TileSize/2; 
    OriginY = TileSize/2; 
    PixelsPerLonDegree = TileSize/360.0; 
    PixelsPerLonRadian = TileSize/(2 * Math.PI); 
} 

public static int TileSize = 256; 
public static double OriginX, OriginY; 
public static double PixelsPerLonDegree; 
public static double PixelsPerLonRadian; 

public static double DegreesToRadians(double deg) 
{ 
    return deg * Math.PI/180.0; 
} 

public static double RadiansToDegrees(double rads) 
{ 
    return rads * 180.0/Math.PI; 
} 

public static double Bound(double value, double min, double max) 
{ 
    value = Math.Min(value, max); 
    return Math.Max(value, min);  
} 

//From Lat, Lon to World Coordinate X, Y. I'm being explicit in assigning to 
//X and Y properties. 
public static Coordinate Mercator(double latitude, double longitude) 
{ 
    double siny = Bound(Math.Sin(DegreesToRadians(latitude)), -.9999, .9999); 

    Coordinate c = new Coordinate(0,0); 
    c.X = OriginX + longitude*PixelsPerLonDegree; 
    c.Y = OriginY + .5 * Math.Log((1 + siny)/(1 - siny)) * -PixelsPerLonRadian; 

    return c; 
} 

//From World Coordinate X, Y to Lat, Lon. I'm being explicit in assigning to 
//Latitude and Longitude properties. 
public static Coordinate InverseMercator(double x, double y) 
{  
    Coordinate c = new Coordinate(0, 0); 

    c.Longitude = (x - OriginX)/PixelsPerLonDegree; 
    double latRadians = (y - OriginY)/-PixelsPerLonRadian; 
    c.Latitude = RadiansToDegrees(Math.Atan(Math.Sinh(latRadians))); 

    return c; 
} 

您可以檢查更詳細的評論原來的JavaScript代碼。

我通過手動近似邊界然後與代碼給出的答案進行比較來測試它。我對NE角的手動近似值是(51.15501,4.796695),代碼吐出了(51.155005..., 4.797038...),看起來非常接近。 SW角近似爲(51.154572,4.796007),代碼吐出了(51.154574..., 4.796006...)

這是一個有趣的,我希望這可以幫助!

編輯:意識到我並沒有包括新GetBounds功能:

public static MapCoordinates GetBounds(Coordinate center, int zoom, int mapWidth, int mapHeight) 
{ 
    var scale = Math.Pow(2, zoom); 

    var centerWorld = Mercator(center.Latitude, center.Longitude); 
    var centerPixel = new Coordinate(0, 0); 
    centerPixel.X = centerWorld.X * scale; 
    centerPixel.Y = centerWorld.Y * scale; 

    var NEPixel = new Coordinate(0, 0); 
    NEPixel.X = centerPixel.X + mapWidth/2.0; 
    NEPixel.Y = centerPixel.Y - mapHeight/2.0; 

    var SWPixel = new Coordinate(0, 0); 
    SWPixel.X = centerPixel.X - mapWidth/2.0; 
    SWPixel.Y = centerPixel.Y + mapHeight/2.0; 

    var NEWorld = new Coordinate(0, 0); 
    NEWorld.X = NEPixel.X/scale; 
    NEWorld.Y = NEPixel.Y/scale; 

    var SWWorld = new Coordinate(0, 0); 
    SWWorld.X = SWPixel.X/scale; 
    SWWorld.Y = SWPixel.Y/scale; 

    var NELatLon = InverseMercator(NEWorld.X, NEWorld.Y); 
    var SWLatLon = InverseMercator(SWWorld.X, SWWorld.Y); 

    return new MapCoordinates() { NorthEast = NELatLon, SouthWest = SWLatLon }; 
} 

只記得,以確保你有在那裏的緯度和經度右:

var result = GoogleMapsAPI.GetBounds(new Coordinate(51.15479, 4.79635), 20, 512, 512); 

我知道代碼不是最大的,但我希望它很清楚。

+0

非常感謝你寫得很好的答案,可惜的確是2年太晚了:) – FrieK

+0

感謝您的投票:) – peterjb

+0

除非我將'Math.Pow(2,zoom)'乘以我還比較了其他來源,並嘗試了所有的小變化。任何想法,爲什麼? – clankill3r