После декодирования кодируется полилиния lat/lng

Мы используем алгоритм декодирования Google Polyline для декодирования наших координат. Но в нашем случае большинство координат ошибочны после его декодирования. Мы также протестировали процесс с более глубокой точностью.

Это наш код, а также наши журналы для проверки неправильности координат:

let coordinates = [ [lat, lng], [...], ...];
console.log(coordinates[13347]); // Output: [ 13.44668, 52.47429 ]
let encoded = Polyline.encode(coordinates);
let decoded = Polyline.decode(encoded);
console.log(decoded[13347]); // Output: [ 13.44671, 52.47445 ]
console.log(coordinates.length == decoded.length)// true

В этом случае расстояние составляет 20 метров, что немало. Другие точки имеют расстояния, такие как 150 метров или даже больше.

В моем массиве координат около 250 000 координат, которые мы хотим декодировать.

Я что-то упустил, поэтому процесс декодирования/кодирования завершился неудачно?

Ответы

Ответ 1

TL; DR Добавьте следующие строки после объявления переменной coordinates:

coordinates = coordinates.map(
    pair => { return [pair[0].toFixed(5), pair[1].toFixed(5)]; }
);

Полный ответ

Похоже, вы имеете дело с ошибками округления с плавающей запятой. Вероятно, библиотека, которую вы используете, имеет неправильную реализацию алгоритма Полилиния кодирования полилинии.

В описании алгоритма мы читаем, что закодированная строка, сгенерированная алгоритмом, сохраняет различия между последовательными координатами с использованием чисел с фиксированной точностью (с 5 знаками после запятой). Поэтому важно округлить широту и долготу до 5 знаков после запятой до, вычисляя различия. Без этого шага ошибки округления могут накапливаться. В худшем случае ошибка может увеличиться примерно на 0,000005 град для каждого последующего элемента в закодированном списке.

Официальная реализация алгоритма не приводит к накопленным ошибкам округления. Тем не менее, реализация, найденная в NPM (полилиния пакета), дает неверные результаты, указывающие на недопустимое округление чисел.

Посмотрите нижеприведенные примеры:

Пример 1. Кодирование полилинии с использованием официальной реализации алгоритма

(используя google.maps.geometry.encoding.encodePath из API JavaScript Карт Google)

originalList = [];
for (var i = 0; i < 100; ++i) 
    originalList.push(
        new google.maps.LatLng(6 * i / 1000000, 0)
    );
// originalList looks like: [[0.000000,0],[0.000006,0],[0.000012,0],[0.000018,0], ..., [0.000594,0]];
// (but with LatLng objects instead of 2-element arrays)

console.log(originalList[99].lat()) // 0.000594

var encodedList = google.maps.geometry.encoding.encodePath(originalList)
var decodedList = google.maps.geometry.encoding.decodePath(encodedList)

console.log(decodedList[99].lat())  // 0.00059

Пример 2. Кодирование полилинии с использованием полилинии пакетов из НПМ

let Polyline = require('polyline');

var originalList = [];
for (var i = 0; i < 100; ++i) 
    originalList.push(
        [6 * i / 1000000, 0]
    );
// again: originalList == [[0.000000,0],[0.000006,0],[0.000012,0],[0.000018,0], ..., [0.000594,0]];

console.log(originalList[99][0]) // 0.000594

var encodedList = Polyline.encode(originalList);
var decodedList = Polyline.decode(encodedList);

console.log(decodedList[99][0])  // 0.00099

Недопустимый результат: значения 0.000594 и 0.00099 отличаются более чем на 0,000005.

Возможное исправление

Библиотека, которую вы используете, вероятно, не обходила координаты перед вычислением различий. Например, когда две последовательные точки имеют широту 0.000000 и 0.000006, разница составляет 0.000006 и округляется до 0.00001, давая ошибку 0.000004. Вы можете обойти координаты вручную, прежде чем передавать их на Polyline.encode(), например. используя функцию .toFixed(5):

let Polyline = require('polyline');

var originalList = [];
for (var i = 0; i < 100; ++i) 
    originalList.push(
        [(6 * i / 1000000).toFixed(5), 0]
    );
// before rounding: [[ 0.000000,0],[ 0.000006,0],[ 0.000012,0],[ 0.000018,0], ..., [ 0.000594,0]];
// after rounding:  [['0.00000',0],['0.00001',0],['0.00001',0],['0.00002',0], ..., ['0.00059',0]];

console.log(originalList[99][0]) // 0.00059

var encodedList = Polyline.encode(originalList);
var decodedList = Polyline.decode(encodedList);

console.log(decodedList[99][0])  // 0.00059

Ответ 2

Количественная полилиния имеет потерю:

https://developers.google.com/maps/documentation/utilities/polylinealgorithm (Polyline encoding is a *lossy* compression algorithm that allows you to store a series of coordinates as a single string

Как насчет использования вашей собственной схемы кодирования? На приведенной выше странице также показана схема кодирования, используемая Google. Возможно, вы можете искать компромисс между пространством и точностью.