В Leaflet полилиния (L.Polyline) представляет собой
упорядоченный набор координатных точек LatLng, соединённых
прямыми отрезками на карте. Каждая точка хранится в географических
координатах:
Структура данных полилинии может быть как простой:
L.polyline([
[51.505, -0.09],
[51.51, -0.1],
[51.52, -0.12]
]);
так и вложенной (multi-polyline):
L.polyline([
[
[51.505, -0.09],
[51.51, -0.1]
],
[
[51.52, -0.12],
[51.53, -0.13]
]
]);
Длина полилинии — сумма длин всех сегментов между последовательными точками:
[ L = {i=1}^{n-1} d(P_i, P{i+1})]
где (d(P_i, P_{i+1})) — расстояние между двумя географическими точками.
В геоинформационных задачах используется два подхода:
Плоское (евклидово) расстояние
Геодезическое расстояние
Leaflet предоставляет метод получения всех точек:
const latlngs = polyline.getLatLngs();
Результат может быть:
LatLngLatLng (для мультилиний)Поэтому перед расчётом длины требуется нормализация структуры.
function flattenLatLngs(latlngs) {
const result = [];
latlngs.forEach(item => {
if (Array.isArray(item)) {
result.push(...flattenLatLngs(item));
} else {
result.push(item);
}
});
return result;
}
Базовая формула для расстояния между двумя точками на сфере:
d = 2R ()
где:
function toRad(value) {
return (value * Math.PI) / 180;
}
function distance(lat1, lng1, lat2, lng2) {
const R = 6371000; // метры
const dLat = toRad(lat2 - lat1);
const dLng = toRad(lng2 - lng1);
const a =
Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(toRad(lat1)) *
Math.cos(toRad(lat2)) *
Math.sin(dLng / 2) *
Math.sin(dLng / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return R * c;
}
function polylineLength(polyline) {
const latlngs = flattenLatLngs(polyline.getLatLngs());
let total = 0;
for (let i = 1; i < latlngs.length; i++) {
total += distance(
latlngs[i - 1].lat,
latlngs[i - 1].lng,
latlngs[i].lat,
latlngs[i].lng
);
}
return total;
}
Leaflet core не содержит встроенного метода длины полилинии, однако
часто применяется расширение leaflet-geometryutil.
После подключения плагина появляется возможность вычисления длины:
const length = L.GeometryUtil.length(polyline);
или:
const latlngs = polyline.getLatLngs();
const length = L.GeometryUtil.length(latlngs);
Особенности:
Библиотека Turf.js предоставляет геоаналитические функции, включая измерение длины линии.
import length from '@turf/length';
const geojson = polyline.toGeoJSON();
const result = length(geojson, { units: 'meters' });
Преимущества:
При редактировании геометрии длина должна пересчитываться при каждом изменении координат.
Для Leaflet.Draw:
map.on('draw:edited', function (e) {
e.layers.eachLayer(function (layer) {
const len = polylineLength(layer);
console.log(len);
});
});
Для событий изменения точек:
polyline.on('edit', function () {
const len = polylineLength(polyline);
});
При большом количестве точек:
Подходы оптимизации:
На практике точность зависит от:
Для инженерных задач допустимо отклонение в пределах нескольких метров при использовании сферической модели, тогда как геодезические системы могут использовать эллипсоид WGS84 для повышения точности.
Leaflet работает в Web Mercator (EPSG:3857), где визуальные расстояния и географические расстояния различаются.
Поэтому:
map.project(latlng) // только для экранных координат
L.GeometryUtilgetLatLngs()Каждый подход выбирается в зависимости от требований к точности, производительности и сложности геометрии.