Клуб API Карт

Как считать координаты тайлов?

Андрей
7 января 2017, 18:52

Я пытаюсь сделать http-метод, выдающий данные для активных областей. Вот как тут https://tech.yandex.ru/maps/doc/jsapi/2.1/dg/concepts/hotspots/hotspot-area-docpage/ . Всё моё приложение работает в координатах (широта/долгота), и мне нужно перевести их в номер тайла в соответствующем масштабе.

Я нигде не нашёл алгоритма перевода координат в номера тайлов и позицию на тайле. Вот тут написано только то, как карта режется на тайлы https://tech.yandex.ru/maps/doc/theory/concepts/coordinates-docpage/ , но не дано ничего более конкретного.

Я попробовал посчитать наиболее простым способом (например, для Москвы 55,546875 сш - это (90-55,546875)=34,453125 градусов от полюса, от верха карты. Если взять z=8, то есть 256 тайлов, и 34,453125÷180×256 = 49 - номер тайла по вертикали). Но оказалось, что реальный номер тайла - 80. Кажется, это связано с проекцией. Нужно проецировать точки на цилиндр и счиать тайлы уже на нём? Или как-то ещё?

6 комментариев
Геокоординаты -> глобальные пиксели -> номер тайла 
В этом проекте есть все формулы для расчётов 
https://github.com/dimik/geohosting-server/tree/master/lib
dimik,
а это действительно стандартный способ задания активных областей в яндекс-картах? мне нужно нажимать на определённые точки нарисованной линии и привязывать к ним данные. я вообще в ту сторону думаю?
Обновлено 7 января 2017, 22:22
dimik,
я почитал код. мне показалось сомнительным использование длины экватора для вычисления кол-ва пикселов на метр для широты. во-первых, у нас эллипсоид, а не шар. во-вторых, в проекции меркатора невозможно нарисовать полюса - они получаются бесконечно далеко, а длина меридиана будет бесконечной, а не полэкватора. то есть, если взять, например, 89 градусов сш, то там уже отрицательный тайл должен получиться.


https://github.com/dimik/geohosting-server/blob/d6c13367c8a39651becc7048d9b366acc4ce8190/lib/projection/geo-to-global-pixels.js#L37


сам код я запустить не смог, видимо, надо настраивать nodejs как-то правильно. позапускал определённые фрагменты, переведя их на go, так что мог допустить ошибки


хотя, вот тут описано точно так же
https://yandex.ru/blog/mapsapi/6654/56a9a310b15b79e31e0d7387


наверное, подойдёт, хотя лучше было бы знать географические координаты верхнего левого угла. поэкспериментирую ещё.
Андрей,
всё, разобрался, спасибо. Как-то сходу не понял, что карта квадратная, и общее кол-во пикселов по X и по Y одинаковое
Андрей,
если ты разобрался, подскажи тогда формулу.
Я нашёл как получить номер тайла в EPSG:3857 (сфера)
int long2tilex(double lon, int z) //(lon=долгота и z=масштаб)
{  return (int)(floor((lon + 180.0) / 360.0 * pow(2.0, z)));  }
int lat2tiley(double lat, int z)//lat=широта
{ return (int)(floor((1.0 - log( tan(lat * M_PI/180.0) + 1.0 / cos(lat * M_PI/180.0)) / M_PI) / 2.0 * pow(2.0, z))); }
Мне бы такие же формулы но для EPSG:3395, эллипсоид
Разобрался, сам долго искал, может кому пригодится, код на С/С++
у тайла 3 номера, Z, X, Y
int lat2tileY_Yandex(double lat, int z)//lat=широта в градусах, z=масштаб
{
lat = lat * M_PI / 180.0; //радианы = градусы * ПИ / 180
double a = 6378137;
double k = 0.0818191908426;
double z1 = tan(M_PI / 4 + lat / 2) / pow(tan(M_PI / 4 + asin(k * sin(lat)) / 2) , k);
int pix_Y = round((20037508.342789 - a * log(z1)) * 53.5865938 / pow(2, 23 - z));
return (pix_Y / 256);
}
int long2tileX_Yandex(double lon, int z)//lon=долгота в градусах, z=масштаб
{
lon = lon * M_PI / 180.0; //радианы = градусы * ПИ / 180
double a = 6378137;
double k = 0.0818191908426;
int pix_X = round((20037508.342789 + a * lon) * 53.5865938 / pow(2.0 , 23 - z));
return (pix_X / 256);
}