РЕДАКТИРОВАТЬ: Вау, я только что понял, что этому вопросу почти два года. Извини за это.
Итак, я думаю, что здесь происходит несколько вещей. Самое главное, что вы не делаете проекцию Меркатора, упомянутую в предоставленных вами ссылках. Вы можете увидеть его в действии с помощью примера кода в Google документы API карт. Я думаю, причина, по которой вы приближаетесь, заключается в том, что коэффициент масштабирования настолько велик на уровне масштабирования 20, что заглушает детали проблемы.
Чтобы получить границы, вам нужно взять центральную широту/долготу, преобразовать его в пиксельные координаты, добавить/вычесть, чтобы получить пиксельные координаты нужных вам углов, а затем преобразовать обратно в широту/долготу. Код в первой ссылке может выполнять проекцию и обратную проекцию. Ниже я перевел его на С#.
В приведенном выше решении вы берете координаты широты/долготы и добавляете/вычитаете мировые координаты (пиксельные координаты/масштаб), поэтому вы объединяете две разные системы координат.
Проблема, с которой я столкнулся, пытаясь понять это, заключается в том, что ваш класс Coordinate
немного сбивает с толку. Надеюсь, у меня нет этого в обратном направлении, но похоже, что вы вводите широту и долготу в обратном направлении. Это важно, потому что, помимо прочего, проекция Меркатора отличается в каждом направлении. Ваше сопоставление X/Y также кажется обратным, потому что широта — это ваше положение север/юг, которое должно быть координатой Y при проецировании, а долгота — это ваше положение восток/запад, которое должно быть координатой X при проецировании.
Чтобы найти границы, необходимы три системы координат: долгота/широта, Мировые координаты и координаты пикселей. Процесс таков: широта/долгота центра - (Проекция Меркатора) -> Мировые координаты центра -> Координаты центра пикселей -> Пиксельные координаты СВ/ЮЗ -> Мировые координаты СВ/ЮЗ - (обратная проекция Меркатора) -> СВ/ЮЗ широта/долгота .
Вы находите координаты пикселей, добавляя/вычитая размеры изображения/2. Однако система координат в пикселях начинается с верхнего левого угла, поэтому, чтобы получить северо-восточный угол, вам нужно прибавить ширину/2 к x и вычесть высоту/2 из y. Для юго-западного угла вам нужно вычесть ширину/2 из x и добавить высоту/2 к y.
Вот код проекции (как часть вашего класса 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 для получения более подробных комментариев.
Я проверил это, вручную приблизив границы, а затем сравнив с ответом, который дал код. Мои ручные приближения для северо-восточного угла были (51.15501, 4.796695), и код выдал (51.155005..., 4.797038...) что кажется довольно близким. Приблизительный угол юго-запада был (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);
Я знаю, что код не самый лучший, но я надеюсь, что он понятен.
person
peterjb
schedule
25.09.2014