На прошедшем субботнике товаришь из onboard.ru задался вопросом - как же ему отобразить на его Яндекс картах наложение terrain от гугла.
Давным давно я сам задавался этой проблемой когда вводил поддержку яндекс карт
Докладчику из onboard я пообещал помочь.
Но что самое смешное - оказалочь что мой главный помощьник -
Также благодарю создателя SasGis за уточнение математики. Уж кто-то, а он - первопроходец.
Итак - Google тайлы на яндекс картах - SOLVED
--разрыв страницы--?
Итак все мы знаем что координаты у яндекса и гугла совпадают, но перепутаны.
За подробностями - в топик вортекса.
Но если кратко - у яндекса другой сжатие по вертикали.
Ниже приведеный код позволяет отобразить тайлы гугла с учетом этого сжатия.
Все просто, и за разьяснениями в коменты наверное
для начала создадим свой ITile -
нам надо - получить тайл, и получить его вертикальный оффсет, относительно тайла яндекса
function Yandex_myTile (indataSource) {
var myPos = new YMaps.Point(),
dataSource=indataSource,
dy=0,
element = document.createElement(window.XMLHttpRequest ? "IMG" : "DIV"),
originalSize = new YMaps.Point(256);
element.style.position='absolute';
element.style.display='none';
this.onAddToMap = function (map, parentContainer) {
this.onRemoveFromMap();
parentContainer.appendChild(element);
}
this.onRemoveFromMap = function () {
if(element.parentNode)
element.parentNode.removeChild(element);
element.src='';
}
this.setPosition = function (position) {
myPos.moveTo(position);
element.style.left = myPos.x + 'px';
py=myPos.y+dy;// СДВИГАЕМ ТАЙЛ НА ПОЛУЧЕНЫЙ ОФСЕТ
element.style.top = py + 'px';
}
this.getPosition = function () {
var p = myPos.copy();
return p;
}
this.pushTo=function(a)
{
var e=element;
if (window.XMLHttpRequest)
{
e.style.display="none";
e.onload =function(){this.style.display='block'};
e.src=a;
}
else// будем уважать секратарш на IE6
{
e.style.filter="progid:DX
e.style.display="";
e.src=a;
}
}
this.load = function (tile, zoom) {
element.style.display='none';
var src=dataSource.getTileUrl(tile,zoom);
dy=dataSource.yoffset; // СМОТРИМ СЮДА! НАМ НУЖЕН ЭТОТ ОФСЕТ
this.pushTo(src);
this.setPosition(this.getPosition());
}
this.error = function () {
}
this.abort = function () {
}
this.scale = function (coeff) {
var newSize = originalSize.copy().scale(coeff);
element.style.width = newSize.x + 'px';
element.style.height = newSize.y + 'px';
}
}
Далее нам требуется создать наш яндексTileDataSource ( предложение к разрабочикам - почему бы GoogleTileSource не добавить в стандартный АПИ? )
var tileDataSource = new YMaps.TileDataSource(urlTemplate, true, false);
tileDataSource.map=this.map;
tileDataSource.getTile=function(){return new Yandex_myTile(this);}
// первая мат функция
tileDataSource.tileToMercator = function ( d ) {
return {x:(Math.round(d.x / 53.5865938 - 20037508.342789)), y: (Math.round(20037508.342789 - d.y / 53.5865938))};
}
//вторая мат функция
tileDataSource.mercatorToGeo = function(p) {
// Предвычисленные коэффициенты согласно WGS84
var ab = 0.00335655146887969400,
bb = 0.00000657187271079536,
cb = 0.00000001764564338702,
db = 0.00000000005328478445;
Rn = 6378137;
var xphi = Math.PI/2 - 2 * Math.atan(1 / Math.exp(p.y/Rn));
var latitude = xphi + ab * Math.sin(2 * xphi) + bb * Math.sin(4 * xphi) + cb * Math.sin(6 * xphi) + db * Math.sin(8 * xphi);
var longitude = p.x/Rn;
return new YMaps.GeoPoint(longitude * 180 / Math.PI, latitude * 180 / Math.PI, true);
}
//третья мат функция
tileDataSource.fromLatLngToPixel = function(a, b)
{
var c = 256 * Math.pow(2, b);
var Mw = c / 2;
var Ow = c / 360;
var Pw = c / (2 * Math.PI);
var x = Math.round(Mw + a.getLng() * Ow);
var y = Math.min(Math.max(Math.sin(a.getLat() / 180 * Math.PI), -0.9999), 0.9999);
y = Mw + 0.5 * Math.log((1 + y) / (1 - y)) * (-Pw);
y = Math.round(y);
return new YMaps.Point(x, y);
};
//и само получение тайла, самое интересное
tileDataSource.getTileUrl=function(tile,zoom)
{
var n = this.map.worker.api; //(это инстанс яндекс карт )
//преобразуем тайл в пикселы на 23(?) зуме
var p=n.tileCoordinates.toPixels(tile,new YMaps.Point(0,0), zoom);
//переводим пиксели в координаты гугла
var geo = this.mercatorToGeo( this.tileToMercator(p));
//переводим координаты в тайлпиксели гугла
var geopt = this.fromLatLngToPixel(geo, zoom);
//преобразуем тайл-пиксели яндекса в текущий зим
var yaopt={x:0,y:0};
yaopt.x=p.x>>(23-zoom);
yaopt.y=p.y>>(23-zoom);
//нам интересна разница!
this.yoffset=(yaopt.y-geopt.y);
//в случае больших сдвигов - компенсируем
var off=128;
while(this.yoffset>off)
{
tile.y--;
this.yoffset-=256;
}
while(this.yoffset<-off)
{
tile.y++;
this.yoffset+=256;
}
return myparent.tileURL+"x="+til
}
this.layer = new YMaps.Layer(tileDataSource);
Вот и все, боться больше нечего :)