Преобразование от longitude\latitude до Декартовых координат

Вот некоторые решения, все из которых проходят тестовый набор, тестовый набор и тесты включены, если вы хотите скопировать и вставить для тестирования, попробуйте This Gist .

Метод 0 (RegExp)

На основе https://stackoverflow.com/a/14428340/1877620 , но исправьте, если не существует десятичной точки.

if (typeof Number.prototype.format === 'undefined') {
    Number.prototype.format = function (precision) {
        if (!isFinite(this)) {
            return this.toString();
        }

        var a = this.toFixed(precision).split('.');
        a[0] = a[0].replace(/\d(?=(\d{3})+$)/g, '[110]amp;,');
        return a.join('.');
    }
}

Метод 1

if (typeof Number.prototype.format === 'undefined') {
    Number.prototype.format = function (precision) {
        if (!isFinite(this)) {
            return this.toString();
        }

        var a = this.toFixed(precision).split('.'),
            // skip the '-' sign
            head = Number(this < 0);

        // skip the digits that's before the first thousands separator 
        head += (a[0].length - head) % 3 || 3;

        a[0] = a[0].slice(0, head) + a[0].slice(head).replace(/\d{3}/g, ',[111]amp;');
        return a.join('.');
    };
}

Метод 2 (Разбиение на массив)

if (typeof Number.prototype.format === 'undefined') {
    Number.prototype.format = function (precision) {
        if (!isFinite(this)) {
            return this.toString();
        }

        var a = this.toFixed(precision).split('.');

        a[0] = a[0]
            .split('').reverse().join('')
            .replace(/\d{3}(?=\d)/g, '[112]amp;,')
            .split('').reverse().join('');

        return a.join('.');
    };
}

Метод 3 (цикл)

if (typeof Number.prototype.format === 'undefined') {
    Number.prototype.format = function (precision) {
        if (!isFinite(this)) {
            return this.toString();
        }

        var a = this.toFixed(precision).split('');
        a.push('.');

        var i = a.indexOf('.') - 3;
        while (i > 0 && a[i-1] !== '-') {
            a.splice(i, 0, ',');
            i -= 3;
        }

        a.pop();
        return a.join('');
    };
}

Пример использования

console.log('======== Demo ========')
console.log(
    (1234567).format(0),
    (1234.56).format(2),
    (-1234.56).format(0)
);
var n = 0;
for (var i=1; i<20; i++) {
    n = (n * 10) + (i % 10)/100;
    console.log(n.format(2), (-n).format(2));
}

Разделитель

Если нам нужен пользовательский разделитель тысяч или десятичный разделитель, используйте replace():

123456.78.format(2).replace(',', ' ').replace('.', ' ');

Набор тестов

function assertEqual(a, b) {
    if (a !== b) {
        throw a + ' !== ' + b;
    }
}

function test(format_function) {
    console.log(format_function);
    assertEqual('NaN', format_function.call(NaN, 0))
    assertEqual('Infinity', format_function.call(Infinity, 0))
    assertEqual('-Infinity', format_function.call(-Infinity, 0))

    assertEqual('0', format_function.call(0, 0))
    assertEqual('0.00', format_function.call(0, 2))
    assertEqual('1', format_function.call(1, 0))
    assertEqual('-1', format_function.call(-1, 0))
    // decimal padding
    assertEqual('1.00', format_function.call(1, 2))
    assertEqual('-1.00', format_function.call(-1, 2))
    // decimal rounding
    assertEqual('0.12', format_function.call(0.123456, 2))
    assertEqual('0.1235', format_function.call(0.123456, 4))
    assertEqual('-0.12', format_function.call(-0.123456, 2))
    assertEqual('-0.1235', format_function.call(-0.123456, 4))
    // thousands separator
    assertEqual('1,234', format_function.call(1234.123456, 0))
    assertEqual('12,345', format_function.call(12345.123456, 0))
    assertEqual('123,456', format_function.call(123456.123456, 0))
    assertEqual('1,234,567', format_function.call(1234567.123456, 0))
    assertEqual('12,345,678', format_function.call(12345678.123456, 0))
    assertEqual('123,456,789', format_function.call(123456789.123456, 0))
    assertEqual('-1,234', format_function.call(-1234.123456, 0))
    assertEqual('-12,345', format_function.call(-12345.123456, 0))
    assertEqual('-123,456', format_function.call(-123456.123456, 0))
    assertEqual('-1,234,567', format_function.call(-1234567.123456, 0))
    assertEqual('-12,345,678', format_function.call(-12345678.123456, 0))
    assertEqual('-123,456,789', format_function.call(-123456789.123456, 0))
    // thousands separator and decimal
    assertEqual('1,234.12', format_function.call(1234.123456, 2))
    assertEqual('12,345.12', format_function.call(12345.123456, 2))
    assertEqual('123,456.12', format_function.call(123456.123456, 2))
    assertEqual('1,234,567.12', format_function.call(1234567.123456, 2))
    assertEqual('12,345,678.12', format_function.call(12345678.123456, 2))
    assertEqual('123,456,789.12', format_function.call(123456789.123456, 2))
    assertEqual('-1,234.12', format_function.call(-1234.123456, 2))
    assertEqual('-12,345.12', format_function.call(-12345.123456, 2))
    assertEqual('-123,456.12', format_function.call(-123456.123456, 2))
    assertEqual('-1,234,567.12', format_function.call(-1234567.123456, 2))
    assertEqual('-12,345,678.12', format_function.call(-12345678.123456, 2))
    assertEqual('-123,456,789.12', format_function.call(-123456789.123456, 2))
}

console.log('======== Testing ========');
test(Number.prototype.format);
test(Number.prototype.format1);
test(Number.prototype.format2);
test(Number.prototype.format3);

Тест

function benchmark(f) {
    var start = new Date().getTime();
    f();
    return new Date().getTime() - start;
}

function benchmark_format(f) {
    console.log(f);
    time = benchmark(function () {
        for (var i = 0; i < 100000; i++) {
            f.call(123456789, 0);
            f.call(123456789, 2);
        }
    });
    console.log(time.format(0) + 'ms');
}

// if not using async, browser will stop responding while running.
// this will create a new thread to benchmark
async = [];
function next() {
    setTimeout(function () {
        f = async.shift();
        f && f();
        next();
    }, 10);
}

console.log('======== Benchmark ========');
async.push(function () { benchmark_format(Number.prototype.format); });
next();

95
задан SuperElectric 10 August 2011 в 21:35
поделиться

3 ответа

Недавно я сделал нечто подобное, используя «Формула гаверсина» по данным WGS-84, которая является производной от «Закона гаверсинов» с очень удовлетворительными результатами.

Да, WGS-84 предполагает, что Земля является эллипсоидом, но я полагаю, что вы получите только около 0,5% средней ошибки, используя такой подход, как «Формула Хаверсина», что может быть приемлемым количеством ошибок в вашем случае. У вас всегда будет некоторая ошибка, если вы не говорите о расстоянии в несколько футов, и даже тогда теоретически существует кривизна Земли ... Если вам требуется более жесткий подход, совместимый с WGS-84, проверьте "Формулу Винсенти".

Я понимаю, откуда берется starblue , но хорошая разработка программного обеспечения часто сводится к компромиссам, поэтому все зависит от точности, которая требуется вам для того, что вы делаете. Например, результат, рассчитанный из "

41
ответ дан 24 November 2019 в 05:50
поделиться

Here's the answer I found:

Just to make the definition complete, in the Cartesian coordinate system:

  • the x-axis goes through long,lat (0,0), so longitude 0 meets the equator;
  • the y-axis goes through (0,90);
  • and the z-axis goes through the poles.

The conversion is:

x = R * cos(lat) * cos(lon)

y = R * cos(lat) * sin(lon)

z = R *sin(lat)

Where R is the approximate radius of earth (e.g. 6371KM).

If your trigonometric functions expect radians (which they probably do), you will need to convert your longitude and latitude to radians first. You obviously need a decimal representation, not degrees\minutes\seconds (see e.g. here about conversion).

The formula for back conversion:

   lat = asin(z / R)
   lon = atan2(y, x)

asin is of course arc sine. read about atan2 in wikipedia. Don’t forget to convert back from radians to degrees.

This page gives c# code for this (note that it is very different from the formulas), and also some explanation and nice diagram of why this is correct,

119
ответ дан 24 November 2019 в 05:50
поделиться

Зачем реализовывать то, что уже реализовано и проверено тестами?

Например, C # имеет NetTopologySuite , который является портом .NET для топологии JTS Suite.

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

Если в некоторых случаях можно использовать домашние функции, ГИС является хорошим примером область, в которой предпочтительнее использовать надежную, проверенную тестами библиотеку.

3
ответ дан 24 November 2019 в 05:50
поделиться
Другие вопросы по тегам:

Похожие вопросы: