Как я могу получить широту и долготу от x, y на карте Меркатора (JPEG)?

У меня есть карта проекции Меркатора в формате JPEG, и я хотел бы знать, как связать заданную координату x, y с ее широтой и долготой. Я посмотрел на функцию Гудермана, но, честно говоря, не понимаю, как взять эту функцию и применить ее. А именно, какой вклад он ожидает? Реализация, которую я нашел (JavaScript), похоже, принимает диапазон между -PI и PI, но какова корреляция между моим значением y в пикселях и этим диапазоном?

Кроме того, я нашел эту функцию, которая принимает широту и возвращает плитку для Google Maps, которая также использует Mercator. Казалось бы, если бы я знал, как инвертировать эту функцию, я был бы довольно близок к тому, чтобы получить свой ответ.

/*<summary>Get the vertical tile number from a latitude
using Mercator projection formula</summary>*/

    private int getMercatorLatitude(double lati)
    {
        double maxlat = Math.PI;

        double lat = lati;

        if (lat > 90) lat = lat - 180;
        if (lat < -90) lat = lat + 180;

        // conversion degre=>radians
        double phi = Math.PI * lat / 180;

        double res;
        //double temp = Math.Tan(Math.PI / 4 - phi / 2);
        //res = Math.Log(temp);
        res = 0.5 * Math.Log((1 + Math.Sin(phi)) / (1 - Math.Sin(phi)));
        double maxTileY = Math.Pow(2, zoom);
        int result = (int)(((1 - res / maxlat) / 2) * (maxTileY));

        return (result);
    }

person Matthew Wensing    schedule 22.07.2009    source источник
comment
Если я правильно помню, Google использует равнопрямоугольную проекцию, а не меркатор.   -  person Stefano Borini    schedule 22.07.2009
comment
И Virtual Earth, и Google используют Меркатор.   -  person Erich Mirabal    schedule 22.07.2009
comment
Кроме того, максимальная полезная широта при использовании Меркатора составляет не + -90 градусов, а примерно + -85,05112878 градусов. Значение равно бесконечности на полюсах, поэтому вы должны ограничить его и игнорировать полюса.   -  person Erich Mirabal    schedule 22.07.2009
comment
Чтобы действительно решить задачу, вам также необходимо знать уровень масштабирования при работе с плитками.   -  person Erich Mirabal    schedule 22.07.2009
comment
Я немного не понимаю в этом вопросе. Вы хотите сделать (x, y) - ›(широта, долгота) или (широта, долгота) -› (x, y)?   -  person ntownsend    schedule 30.07.2009


Ответы (5)


Вот вам код ... Дайте мне знать, если вам нужно больше объяснений.

    /// <summary>
    /// Calculates the Y-value (inverse Gudermannian function) for a latitude. 
    /// <para><see cref="http://en.wikipedia.org/wiki/Gudermannian_function"/></para>
    /// </summary>
    /// <param name="latitude">The latitude in degrees to use for calculating the Y-value.</param>
    /// <returns>The Y-value for the given latitude.</returns>
    public static double GudermannianInv(double latitude)
    {
        double sign = Math.Sign(latitude);
        double sin = Math.Sin(latitude * RADIANS_PER_DEGREE * sign);
        return sign * (Math.Log((1.0 + sin) / (1.0 - sin)) / 2.0);
    }

    /// <summary>
    /// Returns the Latitude in degrees for a given Y.
    /// </summary>
    /// <param name="y">Y is in the range of +PI to -PI.</param>
    /// <returns>Latitude in degrees.</returns>
    public static double Gudermannian(double y)
    {
        return Math.Atan(Math.Sinh(y)) * DEGREES_PER_RADIAN;
    }
person Erich Mirabal    schedule 22.07.2009
comment
Итак, если у меня есть изображение карты меркатора высотой 1588 пикселей, и я хочу знать широту, на которой y = 677, я бы вычислил 677 с точки зрения + PI to -PI и назвал бы гудерманиан (y_in_terms_of_pi)? Я понимаю, что это неправильно, но вы можете видеть, где я мысленно застрял здесь ... - person Matthew Wensing; 22.07.2009
comment
Например, на карте меркатора высотой 1588 пикселей 30.0N находится на 615 пикселей от верха. Но если я выражу 615 через линейный диапазон от PI (0) до -PI (1588), я получу 615 - ›0,70824318. И вызов вышеуказанного гудерманиана (0,70824318) дает 37,5587, а не 30,0. - person Matthew Wensing; 22.07.2009
comment
Очевидно, проблема заключается в том, чтобы «выразить 615 через линейный диапазон». Так как мне это сделать? - person Matthew Wensing; 22.07.2009
comment
В основном вам нужно сделать что-то вроде этого: lat = Gudermannian (Ymax - ((y / Height) * (Ymax - Ymin))); где Ymax и Ymin даны путем взятия обратного гудерманиана + -85,05112878 (или любых других границ максимальной и минимальной широты вашего изображения), а Height - это размер вашего изображения. Если вы выполняете мозаику, это также будет работать до тех пор, пока вы замените Ymax и Ymin на границы плитки, а высоту - на размер плитки. Имеет ли это смысл? - person Erich Mirabal; 22.07.2009
comment
def convert_y_to_lat (y): Ymax = gudermannian_inv (гудерманиан (math.pi)); Ymin = gudermannian_inv (гудерманиан (math.pi)) * -1; Высота = 1588; широта = гудерманова (Ymax - ((y / Height) * (Ymax - Ymin))); вернуть лат; convert_y_to_lat (615) возвращает 4.42964421829. Я ожидал вернуть 30.0. :-( - person Matthew Wensing; 22.07.2009
comment
Вы не можете использовать PI. Это только предел, которого вы никогда не достигнете. Вместо этого используйте значение 85,05112878 градусов (преобразованное в радианы). - person Erich Mirabal; 23.07.2009
comment
Я получаю 37,5587, когда y = 615. Для 30 градусов y должно быть 655,17. Почему вы так уверены, что 615 == 30 градусов? - person Erich Mirabal; 23.07.2009
comment
На моем mercator тайлах всего мира, масштабированных до 1588 в высоту, пиксель 615 (сверху) пересекает Испанию где-то недалеко от Картахены и Сицилии возле Катании, которая находится примерно на 37 градусах 32 минуты северной широты, поэтому я не думаю, что 30.0 является правильным. - person Roger; 11.02.2014

Google и т. Д. Используют «сферический Меркатор», проекцию Меркатора, использующую сферическую модель Земли, а не более медленные и более сложные эллиптические уравнения.

Преобразования доступны как часть кода OpenLayers:

http://docs.openlayers.org/library/spherical_mercator.html

person Tim Sylvester    schedule 22.07.2009

Ответ Эриха Мирабала был полностью правильным (если не полностью).

Я только что протестировал его, используя «теоретический тайл Меркатора 256x256» (единственная тайловая версия карты мира от Google).

tile0

Вот еще немного кода (JavaScript, но легко понять) для пояснения.

Я живу в Австралии, на широте около -33 °.

convertRange(
    GudermannianInv(-33), 
    [Math.PI, - Math.PI], 
    [0, 256]
);

152.88327883810192

Если вы отсчитаете 152 пикселя вниз от вершины плитки, вы найдете Австралию. Я также убедился, что этот ответ верен, сравнив результат с заведомо исправными функциями.

Конечно, мы можем отменить этот расчет:

Gudermannian(
    convertRange(
        152.88, 
        [0, 256], 
        [Math.PI, - Math.PI]
));

И нам возвращается -32.99613291758226.

Сложность не в функции Гудермана, а в преобразовании между двумя шкалами.

К счастью, я был довольно ленив и ненавидел подобные проблемы с масштабированием, и у меня уже была небольшая функция, которая могла бы сделать это беспорядочное преобразование за меня.

    /**
     * convert number from _n_ of r1[0] .. r1[1] to _n_ of r2[0] .. r2[1]
     * @example `convertRange( 5, [0, 10], [0, 100] ) === 50`
     *
     * @param {number} value
     * @param {array<number>} r1 old range
     * @param {array<number>} r2 new range
     * @returns {number} value adjusted for new range
     */
    function convertRange( value, r1, r2 ) {
        return ( value - r1[0] )
             * ( r2[1] - r2[0] )
             / ( r1[1] - r1[0] )
             +   r2[0];
    }

И, естественно, версии исходных функций JavaScript:

function Gudermannian(y) {
    return Math.atan(Math.sinh(y)) * (180 / Math.PI)
}

function GudermannianInv(latitude)
{
    var sign = Math.sign(latitude);
    var sin  = Math.sin(
                          latitude 
                        * (Math.PI / 180) 
                        * sign
    );
    return sign * (
        Math.log(
            (1 + sin) / (1 - sin)
        ) / 2
    );
}
person Orwellophile    schedule 17.10.2016

Я сделал что-то похожее. Особенно, если у вас есть изображение из какой-то части мира. Обрезанная карта или просто неполная карта мира: https://stackoverflow.com/a/10401734/730823

person Raphael    schedule 02.05.2012

Важное замечание при выполнении инверсии заключается в том, что не существует такой вещи, как «карта меркатора», как в случае с большинством других картографических проекций. Каждая существующая карта меркатора отличается в зависимости от входного значения phi. Согласно Википедии, Google использует 85.051129, а другие поставщики карт используют 85.05113. Следовательно, входные значения для гудерманиана должны масштабироваться на основе, например, GudermannianInv (85.05113).

person J Tileson    schedule 28.11.2015