Линейные объекты являются одной из наиболее распространённых геометрий в геоинформационных системах. Автомобильные дороги, железнодорожные пути, трубопроводы, линии электропередач, туристические маршруты и границы участков часто представлены в виде линий или ломаных.
Расчёт длины линии позволяет решать широкий спектр задач:
В OpenLayers вычисление длины может выполняться как для уже существующих объектов, так и для геометрий, создаваемых пользователем в режиме рисования.
Для представления линии используется класс
LineString.
Пример создания линии:
import LineString from 'ol/geom/LineString.js';
const line = new LineString([
[0, 0],
[100, 100],
[200, 50]
]);
Каждая вершина задаётся парой координат.
Структура объекта:
LineString
├─ Point 1
├─ Point 2
└─ Point 3
Линия может содержать любое количество сегментов.
Базовый способ вычисления длины линии — использование метода
getLength().
const length = line.getLength();
console.log(length);
Метод возвращает сумму длин всех сегментов линии.
Для координат:
const line = new LineString([
[0, 0],
[3, 4]
]);
console.log(line.getLength());
результат будет:
5
поскольку расстояние между точками вычисляется по теореме Пифагора:
genui{“math_block_widget_always_prefetch_v2”:{“content”:“d=”}}
Для ломаной линии длина определяется как сумма длин всех сегментов.
Пример:
const line = new LineString([
[0, 0],
[3, 4],
[6, 8]
]);
console.log(line.getLength());
Расчёт:
Сегмент 1 = 5
Сегмент 2 = 5
Общая длина = 10
OpenLayers выполняет эти вычисления автоматически.
Важно понимать, что getLength() возвращает длину в
единицах используемой проекции.
Например:
map.getView().getProjection().getCode();
Результат:
EPSG:3857
В большинстве случаев длина будет возвращаться в метрах.
const length = line.getLength();
console.log(length);
1250.8
означает примерно:
1250.8 метров
Если координаты представлены в градусах:
const line = new LineString([
[37.61, 55.75],
[38.00, 55.90]
]);
то результат getLength() будет выражен в градусах, а не
в метрах.
console.log(line.getLength());
0.417...
Такое значение практически бесполезно для реальных измерений расстояний.
Поэтому для географических координат используются геодезические вычисления.
Для получения реального расстояния по поверхности Земли применяется
модуль ol/sphere.
Импорт:
import { getLength } from 'ol/sphere.js';
Пример:
const length = getLength(line);
console.log(length);
Полученный результат будет возвращён в метрах.
Пусть имеется линия между двумя точками:
const line = new LineString([
[37.6176, 55.7558],
[30.3351, 59.9343]
]);
Перед вычислением необходимо указать проекцию данных:
const distance = getLength(line, {
projection: 'EPSG:4326'
});
console.log(distance);
Результат:
около 634000 метров
или:
634 км
Вычисление выполняется по эллипсоиду Земли и значительно точнее простого расчёта в плоской системе координат.
Обычно пользователю неудобно работать с большими числами метров.
Например:
12543.458732
Гораздо удобнее выводить расстояния в километрах.
Пример:
function formatLength(length) {
if (length > 1000) {
return (length / 1000).toFixed(2) + ' км';
}
return length.toFixed(2) + ' м';
}
Использование:
const length = getLength(line);
console.log(formatLength(length));
Результат:
12.54 км
Часто линия хранится внутри векторного слоя.
Получение объекта:
const feature = vectorSource.getFeatures()[0];
Извлечение геометрии:
const geometry = feature.getGeometry();
Вычисление длины:
const length = geometry.getLength();
console.log(length);
Полный пример:
const feature = vectorSource.getFeatures()[0];
const line = feature.getGeometry();
const length = line.getLength();
console.log(length);
Некоторые объекты состоят из нескольких линий.
Для этого используется класс MultiLineString.
import MultiLineString from 'ol/geom/MultiLineString.js';
Создание:
const geometry = new MultiLineString([
[
[0, 0],
[100, 0]
],
[
[0, 0],
[0, 50]
]
]);
Для расчёта общей длины:
import { getLength } from 'ol/sphere.js';
const total = getLength(geometry);
console.log(total);
OpenLayers суммирует длины всех линий.
Очень распространённый сценарий — отображение длины линии во время её создания пользователем.
Подключение инструмента рисования:
import Draw from 'ol/interaction/Draw.js';
Создание взаимодействия:
const draw = new Draw({
source: vectorSource,
type: 'LineString'
});
map.addInteraction(draw);
После начала рисования можно подписаться на изменение объекта.
draw.on('drawstart', function(event) {
const feature = event.feature;
feature.getGeometry().on('change', function(e) {
const geometry = e.target;
const length = getLength(geometry);
console.log(length);
});
});
Во время движения курсора длина будет постоянно пересчитываться.
Создадим элемент страницы:
<div id="length"></div>
Обновление значения:
const output = document.getElementById('length');
feature.getGeometry().on('change', function(e) {
const length = getLength(e.target);
output.innerHTML = formatLength(length);
});
Теперь пользователь видит актуальную длину строящейся линии.
На практике часто создаётся отдельный инструмент измерений.
Основная последовательность:
Такой подход используется в большинстве веб-картографических приложений.
Для вывода результата непосредственно на карте применяется класс
Overlay.
Создание контейнера:
<div id="tooltip"></div>
Создание оверлея:
import Overlay from 'ol/Overlay.js';
const overlay = new Overlay({
element: document.getElementById('tooltip')
});
map.addOverlay(overlay);
Обновление позиции:
overlay.setPosition(
geometry.getLastCoordinate()
);
Вывод значения:
tooltip.innerHTML = formatLength(length);
В результате длина отображается рядом с последней точкой линии.
| Метод | Результат |
|---|---|
geometry.getLength() |
Плоское расстояние |
sphere.getLength() |
Геодезическое расстояние |
| Быстродействие | Выше у getLength() |
| Точность на больших расстояниях | Выше у sphere.getLength() |
| Работа с EPSG:4326 | Предпочтительно использовать sphere.getLength() |
Для большинства карт на основе географических координат рекомендуется
применять именно функции из модуля ol/sphere.
Если необходимо вычислить длину тысяч линий:
const features = vectorSource.getFeatures();
следует избегать постоянного пересчёта.
Неэффективный вариант:
features.forEach(feature => {
console.log(
getLength(feature.getGeometry())
);
});
при каждом обновлении карты.
Лучше вычислить значения один раз:
features.forEach(feature => {
const length = getLength(
feature.getGeometry()
);
feature.set('length', length);
});
После этого использовать сохранённое свойство:
console.log(
feature.get('length')
);
Такой подход существенно снижает нагрузку на браузер.
Перед вызовом метода полезно удостовериться, что объект действительно является линией.
const geometry = feature.getGeometry();
Проверка:
if (
geometry.getType() === 'LineString'
) {
console.log(
geometry.getLength()
);
}
Для нескольких типов:
const type = geometry.getType();
if (
type === 'LineString' ||
type === 'MultiLineString'
) {
const length = getLength(geometry);
console.log(length);
}
Это предотвращает ошибки при работе с точками и полигонами.
При использовании инструмента редактирования длина может обновляться автоматически.
feature.getGeometry().on(
'change',
function(event) {
const length = getLength(
event.target
);
console.log(length);
}
);
После перемещения любой вершины значение будет пересчитано.
const roadLength =
getLength(roadGeometry);
Используется для подсчёта общей протяжённости дорог.
const pipeLength =
getLength(pipeGeometry);
Позволяет оценивать объёмы строительства и обслуживания.
const routeLength =
getLength(routeGeometry);
Применяется для отображения длины треков.
const borderLength =
getLength(borderGeometry);
Используется для вычисления длины границ земельных участков.
const measureLength =
getLength(measureGeometry);
Основа интерактивных измерительных модулей веб-карт.
Использовать geometry.getLength():
Использовать sphere.getLength():
Грамотное сочетание обоих подходов позволяет создавать быстрые и одновременно точные инструменты измерения расстояний в приложениях на базе OpenLayers.