EDIT: Wow, tôi vừa nhận ra câu hỏi này đã gần hai tuổi. Xin lỗi vì điều đó.
OK vì vậy tôi nghĩ có một vài điều đang diễn ra tại đây. Điều quan trọng nhất là bạn không thực hiện phép chiếu Mercator được đề cập trong các liên kết bạn đã cung cấp. Bạn có thể thấy nó hoạt động với code sample trong tài liệu API bản đồ google. Tôi nghĩ rằng lý do bạn đang nhận được phần nào là gần gũi là yếu tố quy mô là quá lớn ở mức độ zoom 20 rằng nó bị chết đuối ra các chi tiết của vấn đề.
Để có giới hạn, bạn cần lấy vĩ độ/vĩ độ trung tâm, chuyển nó thành tọa độ điểm ảnh, cộng/trừ để lấy tọa độ điểm ảnh của các góc bạn muốn và sau đó chuyển đổi lại thành vĩ độ/lon. Mã trong liên kết đầu tiên có thể thực hiện phép chiếu và phép chiếu nghịch đảo. Dưới đây tôi đã dịch nó thành C#.
Trong giải pháp trên, bạn đang dùng tọa độ vĩ độ/vĩ độ và cộng/trừ các tọa độ thế giới (coords pixel/tỷ lệ), vì vậy bạn đang kết hợp hai hệ tọa độ khác nhau.
Một vấn đề mà tôi gặp phải trong khi cố gắng tìm ra điều này là lớp học Coordinate
của bạn hơi khó hiểu. Hy vọng rằng tôi không có điều này ngược, nhưng có vẻ như bạn đang đặt trong vĩ độ và kinh độ về phía sau. Điều này rất quan trọng vì phép chiếu Mercator khác nhau theo từng hướng, trong số các lý do khác. Ánh xạ X/Y của bạn cũng có vẻ ngược, vì Latitude là vị trí Bắc/Nam của bạn, nên là toạ độ Y khi được chiếu và Kinh độ là vị trí Đông/Tây của bạn, nên là tọa độ X khi được chiếu.
Để tìm các giới hạn, cần three coordinate systems: Kinh độ/vĩ độ, tọa độ thế giới và tọa độ pixel. Quá trình này là Trung tâm Latinh - (Mercator Projection) -> Center World Coordinates -> Center Pixel Coordinates -> NE/SW Pixel Coordinates -> NE/SW World Coordinates - (Nghịch đảo Mercator Projection) -> NE/SW Lat/Lon .
Bạn tìm tọa độ pixel bằng cách cộng/trừ kích thước của hình ảnh/2. Hệ tọa độ pixel bắt đầu từ góc trên bên trái, do đó, để có góc NE bạn cần thêm chiều rộng/2 từ x và trừ chiều cao/2 từ y. Đối với góc SW bạn cần phải trừ chiều rộng/2 từ x và thêm chiều cao/2 đến y.
Dưới đây là mã chiếu (như là một phần của lớp GoogleMapsAPI của bạn) trong C#, dịch từ liên kết đầu tiên ở trên 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;
}
Bạn có thể kiểm tra mã javascript gốc để lấy ý kiến chi tiết hơn.
Tôi đã thử nghiệm nó bằng cách xấp xỉ các ranh giới theo cách thủ công và sau đó so sánh với câu trả lời mà mã đã đưa ra. Khoảng cách thủ công của tôi cho góc NE là (51.15501, 4.796695) và mã nhổ ra (51.155005..., 4.797038...) có vẻ khá gần. Góc gần đúng của SW là (51.154572, 4.796007), mã nhổ ra (51.154574..., 4.796006...).
Đây là một điều thú vị, tôi hy vọng điều này sẽ hữu ích!
EDIT: Nhận ra tôi đã không bao gồm các chức năng mới 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 };
}
Chỉ cần nhớ để chắc chắn rằng bạn đã có Latitude và Longitude trong đó phải:
var result = GoogleMapsAPI.GetBounds(new Coordinate(51.15479, 4.79635), 20, 512, 512);
tôi biết mã không phải là lớn nhất, nhưng tôi hy vọng nó là rõ ràng.
Cảm ơn bạn rất nhiều vì câu trả lời bằng văn bản, thật đáng buồn là 2 năm quá muộn :) – FrieK
Cảm ơn bạn đã bỏ phiếu :) – peterjb
Tôi rất nhiều trừ khi tôi nhân 'Math.Pow (2, zoom)' với 2. Tôi cũng so sánh với các nguồn khác và thử tất cả các biến thể nhỏ. Bất kỳ ý tưởng tại sao đó là? – clankill3r