Измерение площадей

Измерение площадей — одна из наиболее востребованных функций веб-картографических приложений. Она используется в кадастровых системах, геоинформационных платформах, инженерных проектах, экологическом мониторинге, сельском хозяйстве и логистике. Библиотека OpenLayers предоставляет инструменты для построения полигонов на карте и вычисления их площади как в процессе рисования, так и после завершения редактирования.

Основой измерения площади является создание геометрии типа Polygon, состоящей из замкнутого набора координат. После построения полигона его площадь может быть вычислена различными способами в зависимости от требований к точности.


Геометрия Polygon

Для определения площади используется геометрия Polygon.

Пример создания полигона вручную:

import Polygon from 'ol/geom/Polygon.js';

const polygon = new Polygon([
    [
        [0, 0],
        [1000, 0],
        [1000, 1000],
        [0, 1000],
        [0, 0]
    ]
]);

Каждый полигон содержит один или несколько линейных колец.

Структура координат:

[
    [
        [x1, y1],
        [x2, y2],
        [x3, y3],
        ...
    ]
]

Первое и последнее значения должны совпадать, образуя замкнутую область.


Метод getArea()

Самый простой способ вычисления площади — использование метода getArea().

const area = polygon.getArea();

console.log(area);

Метод возвращает площадь в квадратных единицах текущей проекции.

Например, если координаты представлены в метрах, результат будет выражен в квадратных метрах.

const area = polygon.getArea();

console.log(`${area} м²`);

Особенности вычислений в проекции Web Mercator

Большинство карт OpenLayers работают в проекции EPSG:3857 (Web Mercator).

const view = new View({
    center: [0, 0],
    zoom: 5
});

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

Например:

const area = polygon.getArea();

Для небольших участков ошибка обычно незначительна.

Для измерения земельных участков, зданий, парковок и других локальных объектов такого вычисления зачастую достаточно.


Геодезическое измерение площади

При работе с большими территориями предпочтительно использовать геодезические расчёты.

OpenLayers предоставляет функцию getArea() из модуля сферической геометрии.

import {getArea} from 'ol/sphere.js';

Пример:

const area = getArea(polygon);

console.log(area);

В этом случае вычисление выполняется с учётом кривизны Земли.

Такой подход обеспечивает значительно более высокую точность при измерении:

  • государств;
  • областей;
  • лесных массивов;
  • водоёмов;
  • сельскохозяйственных территорий.

Сравнение методов

Площадь по геометрии

polygon.getArea();

Особенности:

  • высокая скорость;
  • простота использования;
  • подходит для локальных объектов;
  • зависит от проекции.

Геодезическая площадь

import {getArea} from 'ol/sphere.js';

getArea(polygon);

Особенности:

  • учитывается форма Земли;
  • выше точность;
  • рекомендуется для крупных объектов;
  • немного больше вычислительных затрат.

Добавление слоя для измерений

Перед началом измерения обычно создаётся отдельный векторный слой.

import VectorSource from 'ol/source/Vector.js';
import VectorLayer from 'ol/layer/Vector.js';

const source = new VectorSource();

const vectorLayer = new VectorLayer({
    source: source
});

map.addLayer(vectorLayer);

Все создаваемые пользователем полигоны будут храниться в данном источнике данных.


Интерактивное рисование полигона

Для измерения площади пользователь должен иметь возможность нарисовать контур объекта.

Используется взаимодействие Draw.

import Draw from 'ol/interaction/Draw.js';

const draw = new Draw({
    source: source,
    type: 'Polygon'
});

map.addInteraction(draw);

После активации режима пользователь последовательно указывает вершины полигона.


Получение площади после завершения рисования

Событие drawend позволяет обработать завершение построения фигуры.

draw.on('drawend', function(event) {

    const polygon = event.feature.getGeometry();

    const area = polygon.getArea();

    console.log(area);

});

После замыкания контура вычисляется площадь созданной области.


Использование сферического расчёта после рисования

Для повышения точности:

import {getArea} from 'ol/sphere.js';

draw.on('drawend', function(event) {

    const geometry = event.feature.getGeometry();

    const area = getArea(geometry);

    console.log(area);

});

Полученное значение будет выражено в квадратных метрах.


Форматирование площади

Неудобно отображать большие числа без преобразования единиц измерения.

Пример функции форматирования:

function formatArea(area) {

    if (area > 1000000) {
        return (area / 1000000).toFixed(2) + ' км²';
    }

    return area.toFixed(2) + ' м²';
}

Использование:

const areaText = formatArea(area);

console.log(areaText);

Результаты:

542.12 м²

или

14.57 км²

Динамическое измерение во время рисования

Во многих приложениях площадь отображается ещё до завершения построения полигона.

Для этого отслеживаются изменения геометрии.

draw.on('drawstart', function(event) {

    const geometry = event.feature.getGeometry();

    geometry.on('change', function(e) {

        const polygon = e.target;

        const area = polygon.getArea();

        console.log(area);

    });

});

После добавления каждой новой вершины значение автоматически пересчитывается.


Отображение результатов через Overlay

Для вывода площади непосредственно на карте используется объект Overlay.

Создание HTML-элемента:

const measureElement =
    document.createElement('div');

measureElement.className = 'measure';

Создание оверлея:

import Overlay from 'ol/Overlay.js';

const measureOverlay = new Overlay({
    element: measureElement
});

map.addOverlay(measureOverlay);

Обновление текста:

measureElement.innerHTML =
    formatArea(area);

Изменение позиции:

measureOverlay.setPosition(
    polygon.getInteriorPoint().getCoordinates()
);

Подпись будет отображаться внутри измеряемой области.


Использование внутренней точки полигона

Для корректного размещения подписи применяется метод:

polygon.getInteriorPoint()

Пример:

const point =
    polygon.getInteriorPoint();

const coordinates =
    point.getCoordinates();

Полученные координаты практически всегда находятся внутри фигуры независимо от её формы.


Измерение площади существующего объекта

Необязательно рисовать полигон вручную.

Если объект уже находится на карте:

const feature =
    source.getFeatures()[0];

const polygon =
    feature.getGeometry();

const area =
    polygon.getArea();

Подход широко применяется при загрузке данных из внешних источников.


Измерение площадей объектов GeoJSON

После загрузки GeoJSON можно вычислять площади всех объектов.

source.getFeatures().forEach(feature => {

    const geometry =
        feature.getGeometry();

    const area =
        geometry.getArea();

    console.log(area);

});

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

  • земельные участки;
  • районы города;
  • административные границы;
  • природные зоны.

Суммарная площадь нескольких объектов

Иногда необходимо получить общую площадь набора полигонов.

let totalArea = 0;

source.getFeatures().forEach(feature => {

    totalArea +=
        feature.getGeometry().getArea();

});

console.log(totalArea);

Результат:

1254300

После форматирования:

console.log(
    formatArea(totalArea)
);

Пересчёт площади после редактирования

Если полигон можно изменять, площадь должна обновляться автоматически.

Для этого используется взаимодействие Modify.

import Modify from 'ol/interaction/Modify.js';

const modify = new Modify({
    source: source
});

map.addInteraction(modify);

После изменения геометрии:

modify.on('modifyend', function(event) {

    event.features.forEach(feature => {

        const area =
            feature.getGeometry().getArea();

        console.log(area);

    });

});

Очистка результатов измерения

Удаление всех измеренных объектов:

source.clear();

Удаление отдельных объектов:

source.removeFeature(feature);

После удаления рекомендуется очищать подписи площади:

measureElement.innerHTML = '';

Настройка стиля измеряемого полигона

Для лучшей визуализации измеряемые области обычно выделяются специальным стилем.

import Style from 'ol/style/Style.js';
import Stroke from 'ol/style/Stroke.js';
import Fill from 'ol/style/Fill.js';

const style = new Style({

    stroke: new Stroke({
        color: '#ff6600',
        width: 2
    }),

    fill: new Fill({
        color: 'rgba(255,102,0,0.2)'
    })

});

Применение:

vectorLayer.setStyle(style);

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


Производительность при большом количестве измерений

При работе с тысячами полигонов рекомендуется:

  • избегать постоянного пересчёта площадей;
  • кэшировать вычисленные значения;
  • выполнять пересчёт только после изменения геометрии;
  • использовать геодезические вычисления только там, где действительно необходима высокая точность;
  • удалять временные измерительные объекты после завершения работы.

Практический пример полного измерения площади

import Draw from 'ol/interaction/Draw.js';
import {getArea} from 'ol/sphere.js';

const draw = new Draw({
    source: source,
    type: 'Polygon'
});

map.addInteraction(draw);

draw.on('drawend', function(event) {

    const polygon =
        event.feature.getGeometry();

    const area =
        getArea(polygon);

    alert(
        formatArea(area)
    );

});

Последовательность работы:

  1. Пользователь начинает рисование.
  2. Формируется геометрия типа Polygon.
  3. После завершения срабатывает событие drawend.
  4. Выполняется вычисление площади.
  5. Значение форматируется.
  6. Результат выводится пользователю.

Такой механизм лежит в основе большинства инструментов измерения площадей в приложениях, построенных на OpenLayers.