Пересечение полигонов

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

В геоинформационных системах такая операция применяется для решения множества задач:

  • поиск пересечения административных границ;
  • определение зон покрытия различных сервисов;
  • анализ наложения природных объектов;
  • расчёт общей площади пересекающихся территорий;
  • работа с кадастровыми данными;
  • пространственная фильтрация объектов на карте.

Библиотека Turf.js предоставляет готовые инструменты для выполнения подобных вычислений непосредственно в браузере или среде Node.js.


Геометрическая сущность пересечения

Предположим, существуют два полигона:

  • Полигон A — территория города.
  • Полигон B — территория природного заповедника.

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

С точки зрения теории множеств операция выглядит следующим образом:

A ∩ B

Результат содержит только общие точки обеих фигур.

Если общих областей нет, результатом становится отсутствие геометрии.


Подключение Turf.js

Для работы с пересечениями используется пакет Turf.js:

npm install @turf/turf

Импорт:

import * as turf from "@turf/turf";

Либо подключение отдельных модулей:

import { polygon } from "@turf/helpers";
import { intersect } from "@turf/intersect";

Создание исходных полигонов

Рассмотрим два перекрывающихся квадрата.

const polygon1 = turf.polygon([
    [
        [0, 0],
        [5, 0],
        [5, 5],
        [0, 5],
        [0, 0]
    ]
]);

const polygon2 = turf.polygon([
    [
        [3, 3],
        [8, 3],
        [8, 8],
        [3, 8],
        [3, 3]
    ]
]);

Визуально фигуры выглядят следующим образом:

polygon1
+-----+
|     |
|  +-----+
|  |XX   |
+--|XX   |
   +-----+
      polygon2

Область XX является пересечением.


Использование функции intersect

Основной инструмент для поиска общей области — функция intersect().

const result = turf.intersect(
    turf.featureCollection([
        polygon1,
        polygon2
    ])
);

console.log(result);

Результат:

{
  type: "Feature",
  geometry: {
    type: "Polygon",
    coordinates: [...]
  }
}

Полученный объект содержит только область наложения.


Структура возвращаемого объекта

Если полигоны пересекаются, результат имеет стандартный формат GeoJSON.

Пример:

{
    type: "Feature",
    properties: {},
    geometry: {
        type: "Polygon",
        coordinates: [
            [
                [3, 3],
                [5, 3],
                [5, 5],
                [3, 5],
                [3, 3]
            ]
        ]
    }
}

Этот полигон представляет квадрат размером 2×2 единицы.


Случай отсутствия пересечения

Не всегда фигуры имеют общую область.

const polygon1 = turf.polygon([
    [
        [0, 0],
        [2, 0],
        [2, 2],
        [0, 2],
        [0, 0]
    ]
]);

const polygon2 = turf.polygon([
    [
        [5, 5],
        [7, 5],
        [7, 7],
        [5, 7],
        [5, 5]
    ]
]);

Поиск пересечения:

const result = turf.intersect(
    turf.featureCollection([
        polygon1,
        polygon2
    ])
);

console.log(result);

Вывод:

null

Возвращаемое значение null означает отсутствие общей площади.

Поэтому перед дальнейшей обработкой рекомендуется выполнять проверку:

if (result) {
    console.log("Пересечение найдено");
} else {
    console.log("Пересечение отсутствует");
}

Вычисление площади пересечения

Часто требуется не только получить общую геометрию, но и узнать её площадь.

Сначала выполняется пересечение:

const intersection = turf.intersect(
    turf.featureCollection([
        polygon1,
        polygon2
    ])
);

Затем вычисляется площадь:

const area = turf.area(intersection);

console.log(area);

Полный пример:

if (intersection) {
    const area = turf.area(intersection);

    console.log(`Площадь: ${area}`);
}

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


Пересечение сложных многоугольников

В реальных проектах объекты редко представляют собой простые квадраты.

Пример сложных фигур:

const regionA = turf.polygon([
    [
        [0, 0],
        [8, 0],
        [8, 4],
        [5, 7],
        [0, 5],
        [0, 0]
    ]
]);

const regionB = turf.polygon([
    [
        [2, 2],
        [10, 2],
        [10, 8],
        [2, 8],
        [2, 2]
    ]
]);

Пересечение:

const overlap = turf.intersect(
    turf.featureCollection([
        regionA,
        regionB
    ])
);

Turf.js самостоятельно выполняет:

  1. поиск пересекающихся рёбер;
  2. вычисление новых вершин;
  3. построение результирующего контура;
  4. формирование корректного GeoJSON.

Разработчику не требуется реализовывать алгоритмы вычислительной геометрии вручную.


Работа с MultiPolygon

Некоторые объекты состоят из нескольких независимых областей.

Пример:

const multipolygon = turf.multiPolygon([
    [
        [
            [0, 0],
            [2, 0],
            [2, 2],
            [0, 2],
            [0, 0]
        ]
    ],
    [
        [
            [5, 5],
            [7, 5],
            [7, 7],
            [5, 7],
            [5, 5]
        ]
    ]
]);

Второй объект:

const polygon = turf.polygon([
    [
        [1, 1],
        [6, 1],
        [6, 6],
        [1, 6],
        [1, 1]
    ]
]);

Поиск общей области:

const result = turf.intersect(
    turf.featureCollection([
        multipolygon,
        polygon
    ])
);

Результатом может стать:

Polygon

или

MultiPolygon

в зависимости от характера пересечения.


Пересечение нескольких полигонов

Иногда требуется определить область, общую для множества объектов.

Например:

const polygons = [
    polygon1,
    polygon2,
    polygon3
];

Последовательное выполнение:

let current = polygon1;

for (let i = 1; i < polygons.length; i++) {
    current = turf.intersect(
        turf.featureCollection([
            current,
            polygons[i]
        ])
    );

    if (!current) {
        break;
    }
}

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


Проверка факта пересечения

Если требуется узнать только наличие пересечения, а не строить новую геометрию, можно использовать другие функции Turf.js.

Например:

const intersects = turf.booleanIntersects(
    polygon1,
    polygon2
);

console.log(intersects);

Результат:

true

или

false

Такой подход работает быстрее, поскольку не создаёт новый объект GeoJSON.

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

Метод Возвращает
intersect Геометрию пересечения
booleanIntersects Логическое значение

Визуализация результата на карте

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

Пример для Mapbox GL JS:

map.addSource("intersection", {
    type: "geojson",
    data: result
});

map.addLayer({
    id: "intersection-layer",
    type: "fill",
    source: "intersection",
    paint: {
        "fill-color": "#ff0000",
        "fill-opacity": 0.6
    }
});

В результате общая область будет выделена отдельным цветом.

Подобная визуализация часто применяется для:

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

Практический пример: зона покрытия вышек связи

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

const towerA = turf.circle(
    [0, 0],
    10,
    { units: "kilometers" }
);

const towerB = turf.circle(
    [8, 0],
    10,
    { units: "kilometers" }
);

Поиск общей зоны:

const commonCoverage = turf.intersect(
    turf.featureCollection([
        towerA,
        towerB
    ])
);

Определение площади:

const area = turf.area(commonCoverage);

console.log(area);

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


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

Кадастровые данные часто содержат участки, частично накладывающиеся друг на друга вследствие ошибок измерений.

const parcel1 = turf.polygon([...]);
const parcel2 = turf.polygon([...]);

Поиск наложения:

const overlap = turf.intersect(
    turf.featureCollection([
        parcel1,
        parcel2
    ])
);

Проверка:

if (overlap) {
    console.log("Обнаружено пересечение участков");
}

Расчёт площади конфликта:

const overlapArea = turf.area(overlap);

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


Производительность при работе с большими наборами данных

При обработке тысяч объектов вычисление пересечений может становиться ресурсоёмкой операцией.

Распространённые методы оптимизации:

Предварительная проверка границ

Перед вызовом intersect() можно проверить пересечение ограничивающих прямоугольников.

const bbox1 = turf.bbox(polygon1);
const bbox2 = turf.bbox(polygon2);

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

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

Когда необходим только факт пересечения:

turf.booleanIntersects(a, b);

Это быстрее построения результирующей геометрии.

Пространственная индексация

Для больших коллекций объектов обычно применяются:

  • R-tree;
  • RBush;
  • QuadTree.

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


Типичные ошибки

Незамкнутый контур

Неверно:

[
    [0, 0],
    [5, 0],
    [5, 5],
    [0, 5]
]

Правильно:

[
    [0, 0],
    [5, 0],
    [5, 5],
    [0, 5],
    [0, 0]
]

Первая и последняя точки должны совпадать.


Перепутанный порядок координат

GeoJSON использует формат:

[longitude, latitude]

Правильно:

[37.62, 55.75]

Неверно:

[55.75, 37.62]

Нарушение порядка координат приводит к некорректным вычислениям.


Отсутствие проверки на null

Опасный код:

const intersection = turf.intersect(
    turf.featureCollection([
        polygon1,
        polygon2
    ])
);

const area = turf.area(intersection);

Без проверки возможна ошибка выполнения.

Безопасный вариант:

if (intersection) {
    const area = turf.area(intersection);
}

Связь пересечения с другими операциями Turf.js

Операция пересечения часто используется совместно с другими геометрическими функциями.

Операция Назначение
intersect Общая область объектов
union Объединение объектов
difference Вычитание одной области из другой
dissolve Слияние множества объектов
buffer Создание буферной зоны
area Расчёт площади
bbox Получение ограничивающего прямоугольника
booleanIntersects Проверка факта пересечения

Комбинация этих инструментов позволяет реализовывать сложные сценарии пространственного анализа непосредственно средствами JavaScript и Turf.js.