Клуб API Карт

Пересчет пиксельных координат в географические координаты на стороне сервера

Пост в архиве.

Похожая задача была описана здесь тема яндекс-клуба

Есть ли  другие алгоритмы пересчета? как вообще реализуется пересчет без использования конвертора яндекс-карт? 

 

28 комментариев

Там вроде самые точные алгоритмы описаны, сами такие используем.

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

map.events.add('click', function (e) {

                var pixels=e.get('globalPixels');

                var zoom = map.getZoom();

$.ajax({

 data:{"action":'accept',"x": pixels[0],"y": pixels[1],'zoom':zoom },

success: function(geo) {

alert('Геокоординаты точки'+geo);

}

}); 

}); 

 

чтоб при клике на карту получить глобальные пикселы карты, а потом через ajax их передать на сервер, где их обработать и как результат получить геокоординаты, без использования converter яндекс-карт. 

Вот тут модуль меркатора, который работает и туда и обратно

http://api-maps.yandex.ru/2.0.36/debug/combine.xml?modules=3*

благодарю!!! буду разбираться!!! :-)

я извиняюсь, вот дочитала до места где 

cycleRestrict = imports.util.math.cycleRestrict;

помогите достать еще и этот модуль  

return value - Math.floor((value - min) / (max - min)) * (max - min);

Спасибо!

вопрос, вот например

this.xToLongitude = function (x) {
        return cycleRestrict(x * subradius, -Math.PI, Math.PI) * c_180pi; 

}; 

 

здесь х - это координата глобального пиксела? 

т.е. то что я получаю из

map.events.add('click', function (e) {

                var pixels=e.get('globalPixels'),

x = pixels[0];


}


 

Именно она. Пиксельные координаты везде одинаковые

что-то у меня не выходит, что нужно

из модуля,  что Вы мне скинули, я списала: 

public static function cycleRestrict($value,$min,$max) {

        return floor((($value - $min)/($max - $min))*($max - $min));

    }

 

    public static function pixelToGeo($pixelX,$pixelY) {

        $e = 0.0818191908426;

        $e2 = $e * $e;

        $e4 = $e2 * $e2;

        $e6 = $e4 * $e2;

        $e8 = $e4 * $e4;

        $radius = 6378137;

        $subradius = 1 / $radius;

        $d2 = $e2 / 2 + 5 * $e4 / 24 + $e6 / 12 + 13 * $e8 / 360;

        $d4 = 7 * $e4 / 48 + 29 * $e6 / 240 + 811 * $e8 / 11520;

        $d6 = 7 * $e6 / 120 + 81 * $e8 / 1120;

        $d8 = 4279 * $e8 / 161280;

 

        $c_pi180 = M_PI / 180;

        $c_180pi = 180 / M_PI;

        $geoX = self::cycleRestrict($pixelX * $subradius, -M_PI, M_PI) * $c_180pi;

        $xphi = M_PI * 0.5 - 2 * atan(1 / exp($pixelY * $subradius));

        $geoY = $xphi + $d2 * sin(2 * $xphi) + $d4 * sin(4 * $xphi) + $d6 * sin(6 * $xphi) + $d8 * sin(8 * $xphi);

        $geoY = $geoY * $c_180pi;

        return array('x' => $geoX, 'y' => $geoY);

    }

 map.events.add('click', function (e) {

                var pixels=e.get('globalPixels'),

$.ajax({

                    type:'POST',

                    data:{"action":'accept',"x": pixels[0],"y": pixels[1] },

                    datatype:'html',

                    success: function(res) {

                        map.balloon.open(coords, {

                            contentBody:

                                '

Координаты щелчка: ' + coords.join(', ') + '

'+

                                '

Глобальные пикселы '+pixels.join(', ')+'

'+

                                '

Ответ с сервера
'+res+'

'

                        });

                    }

                });


}

Координаты щелчка: 47.918725916901664, 33.42612788639918 // то, что должны получить

Глобальные пикселы 155412.16352403397, 91420.96006116038  // входные параметры
Ответ с сервера 
 171,88733853925 0,82675418263993 // что отдала функция преорбразования с сервера

а нужно получить выведенные координаты щелчка, где я прошляпила ? 
и еще вопрос, а почему нигде в формулах не учитывается величина зума (как мне показалось из документации яндекса, то тоже должно зависеть)? 
 

Потому что результатом работы функции являются пиксельные координаты на "нулевом зуме", надо доможнить на 2<

Но циферки в любом случае как-то не срастаются :(

$pixelX = ($pixelX * 2) << $zoom;

$pixelY = ($pixelY * 2) << $zoom; 

так? так а в чем принцип смещения на значение зума?  

битовый сдвиг по сути равняется возведению в степень. Вот только так делаете вы - делать нельзя.

Битовому сдвигу подведждены только целые числа, и pixelX*2 будет в начале округлен, потом возведен степень.

Вот только возводить надо исключительно "двойку" и лучше в скобочках. 

И чет я сам совсем запутался в этих формулах - раньше в одном месте были, теперь уже в двух.

 

globalPixelXToGeo = function (x, zoom) {

            return cycleRestrict(Math.PI * x / Math.pow(2, zoom + 7) - Math.PI, -Math.PI, Math.PI) * (180 / Math.PI);

        };

+ yToLatitude(halfEquator - vector[1] / pixelsPerMeter) ;

 

см http://api-maps.yandex.ru/2.0.36/debug/combine.xml?modules=3(

Вот что у меня было в коде, из вышеизложенного кода 

public static function fromGlobalsPixels($vectorX, $vectorY, $zoom) {

        $coef = 2 >> $zoom;

        $vectorX = $vectorX * $coef;

        $vectorY = $vectorY * $coef;

        $radius = 6378137;

        $equator = 2 * M_PI * $radius;

        $subequator = 1 / $equator;

        $halfEquator = $equator / 2;

        $currentZoom = 0;

        $c_180pi = 180 / M_PI;

        $pixelsPerMeter = 256 * $subequator;

 

        if ($zoom != $currentZoom) {

            $pixelsPerMeter = pow(2, $zoom + 8) * $subequator;

            $currentZoom = $zoom;

        }

 

        $vectorX = self::cycleRestrict(M_PI * $vectorX / pow(2, $zoom + 7) - M_PI, -M_PI, M_PI) * $c_180pi;

        $vectorY = self::yToLatitude($halfEquator - $vectorY / $pixelsPerMeter);

        return array('x' => $vectorX, 'y' => $vectorY);

    }

 

 

    public static function xToLongtitude($vectorX, $zoom) {

        $c_180pi = 180 / M_PI;

        return self::cycleRestrict(M_PI * $vectorX / pow(2, $zoom + 7) - M_PI, -M_PI, M_PI) * $c_180pi;

    }

 

    public static function yToLatitude($vectorY) {

 

        $e = 0.0818191908426;

        $e2 = $e * $e;

        $e4 = $e2 * $e2;

        $e6 = $e4 * $e2;

        $e8 = $e4 * $e4;

        $radius = 6378137;

        $subradius = 1 / $radius;

        $d2 = $e2 / 2 + 5 * $e4 / 24 + $e6 / 12 + 13 * $e8 / 360;

        $d4 = 7 * $e4 / 48 + 29 * $e6 / 240 + 811 * $e8 / 11520;

        $d6 = 7 * $e6 / 120 + 81 * $e8 / 1120;

        $d8 = 4279 * $e8 / 161280;

        $c_180pi = 180 / M_PI;

        $xphi = M_PI * 0.5 - 2 * atan(1 / exp($vectorY * $subradius));

        $geoY = $xphi + $d2 * sin(2 * $xphi) + $d4 * sin(4 * $xphi) + $d6 * sin(6 * $xphi) + $d8 * sin(8 * $xphi);

        $geoY = $geoY * $c_180pi;

        return $geoY;

    }


Координаты щелчка: 47.90303007897467, 33.38492915593044 // что должны получить

Глобальные пикселы 155382.16352403397, 91437.96006117242 // входные данные

Ответ с сервера

Геокоординаты: 0   85,08405905011 

опять неудача.
Хотя вот без домножения на $coef, оч близко вышла координата Y.

И еще вопрос, в дебагере браузера, включив http://api-maps.yandex.ru/2.0-stable/?load=package.full&lang=ru-RU&mode=debug, искала исходники...выпадают модули, но с релизом 2.0.35...(а у вас 2.0.36)
может в этом расхождение? 



 

Не, разницы между 2.0.35,26 и даже 2.1 в этом месте нету.

Но вижу ошибку- $coef = 2 >> $zoom - оно просто 0 даст. Надо pow(2,-zoom), или 2<

исправила на 

        $coef = 2 << $zoom;

        $vectorX =  $vectorX/$coef;

        $vectorY =  $vectorY/$coef;
но эффекта не дало все равно((

Координаты щелчка: 47.91041695223366, 33.40690181218043

Глобальные пикселы 155398.16352403397, 91429.96006116032 
Геокоординаты: 0 85,078802204116 

Я теперь ничего не понимаю. То поделить, то умножить. Хочу понять, какая логика вообще заложена при переведении координат с учетом зума?

Какую роль несет переменная   $pixelsPerMeter? 
 

зачем вообще переводить глобальные пикселы, которые я вытащила, если отсюда, из того что я нашла ниже в модуле, оно уже "отформатировала" нужные пикселы? 

toGlobalPixels: function(point, zoom) {
        if (project.DEBUG) {
            if (!point) {
                throw new Error("Cartesian.toGlobalPixels: не передан параметр point");
            }
            if (typeof zoom == "undefined") {
                throw new Error("Cartesian.toGlobalPixels: не передан параметр zoom");
            }
        }
        var bounds = this._bounds,
            worldSize = Math.pow(2, zoom + 8),
            x = point[latLongOrder ? 1 : 0],
            y = point[latLongOrder ? 0 : 1];
       
        return [
            ((x - bounds[0][0]) / this._xRange) * worldSize,
            ((bounds[1][1] - y) / this._yRange) * worldSize
        ]; 

    }, 

Заметила, что

 

$vectorY = self::yToLatitude($halfEquator - $vectorY / $pixelsPerMeter); // значение выдает тютилька в тютильку, если не делать никакого домножения/деления
а вот с этой частью
$vectorY = self::yToLatitude($halfEquator - $vectorY / $pixelsPerMeter); ...огромное расхождение, координаты не совпадают

Ошибка в cycleRestrict, и $coef не нужен (зум тут и так есть, в том числе в $pixelsPerMeter)

 

    public static function cycleRestrict($value, $min, $max)

    {

        return $value - floor(($value - $min) / ($max - $min)) * ($max - $min);

    }

 

    public static function fromGlobalsPixels($vectorX, $vectorY, $zoom)

    {

 

        $coef = 1; //2 >> $zoom;

 

        $vectorX = $vectorX * $coef;

 

        $vectorY = $vectorY * $coef;

 

        $radius = 6378137;

 

        $equator = 2 * M_PI * $radius;

 

        $subequator = 1 / $equator;

 

        $halfEquator = $equator / 2;

 

        $c_180pi = 180 / M_PI;

 

 

        $pixelsPerMeter = pow(2, $zoom + 8) * $subequator;

 

 

        $vectorX = self::cycleRestrict(M_PI * $vectorX / pow(2, $zoom + 7) - M_PI, -M_PI, M_PI) * $c_180pi;

 

        $vectorY = self::yToLatitude($halfEquator - $vectorY / $pixelsPerMeter);

 

        return array('x' => $vectorX, 'y' => $vectorY);

 

    }

 

ура! точно-точно, все выходит, огромное человеческое спасибо

а есть формула преобразования локальных пиксельных координат в глобальные? 
чтоб ну например
выходные данные (локал)
742,493
а на выходе получить такое (глобал)
 55404.16352403397 91443.96006117242

А что такое локальные пиксели и откуда беруться?

    $('#maptest1').live('click', function (e) {

        var projection = map.options.get('projection'),

            zoom = map.getZoom();

        // получаю глобальные пикселы из локальных пикселей

        var globalCoordinate = map.converter.pageToGlobal([e.pageX, e.pageY]);

}

e.pageX, e.pageY - вот это и есть локальные, при клике по карте

Минус координаты дива карты, плюс текущий globalPixelCenter

а зум не играет никакой роли тогда? 

var globalPixelCenter = map.getGlobalPixelCenter();

var containerSize = map.container.getSize(); 

 var g1 = e.pageX - containerSize[0] + globalPixelCenter[0];

var g2 = e.pageY - containerSize[1] + globalPixelCenter[1];

вышло, но не точное

Координаты центра в пикселах 155470.66352403397, 91421.96006117242

Размеры контейнера карты 700, 300, Zoom 10

**Локальные пиксельные координаты 665,483

===Глобальные пикселы (что должны получить!!)155410.66352403397 91425.96006117242

Ответ: 155435.66352403397 91604.96006117242

то, что глобальный пиксельный центр используется 100% видно по числам, особенно по значениям после запятой

я теперь засомневалась какую величину я отнимаю,  containerSize верно?

Прошу прощения отчасти за off-topic, но:

 

каков масштаб ("цена") grad/pix фрагмента карты  для z=14 по широте (для статического API)?

Попытался определить экспериментально и получил 0.0000242625

Близко ли к это к реальному?

Про "цену" долготе - не спрашиваю, поск-ку это зависитот широты (как 1/cos(LAT), полагаю)

С уважением,

dummy