編輯:哇,我剛剛意識到這個問題差不多兩歲了。對於那個很抱歉。
好吧,我想這裏有一些事情要做。最重要的是你沒有在你提供的鏈接中提到的墨卡託投影。您可以在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);
我知道代碼不是最大的,但我希望它很清楚。
非常感謝你寫得很好的答案,可惜的確是2年太晚了:) – FrieK
感謝您的投票:) – peterjb
除非我將'Math.Pow(2,zoom)'乘以我還比較了其他來源,並嘗試了所有的小變化。任何想法,爲什麼? – clankill3r