Пересечение полигонов — одна из наиболее важных операций пространственного анализа. Она позволяет определить общую область, занимаемую двумя или несколькими полигонами. Результатом является новый полигон, содержащий только те участки пространства, которые одновременно принадлежат всем исходным фигурам.
В геоинформационных системах такая операция применяется для решения множества задач:
Библиотека Turf.js предоставляет готовые инструменты для выполнения подобных вычислений непосредственно в браузере или среде Node.js.
Предположим, существуют два полигона:
Если часть заповедника находится внутри города, то пересечение этих объектов представляет собой область, принадлежащую одновременно обоим полигонам.
С точки зрения теории множеств операция выглядит следующим образом:
A ∩ B
Результат содержит только общие точки обеих фигур.
Если общих областей нет, результатом становится отсутствие геометрии.
Для работы с пересечениями используется пакет 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().
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 самостоятельно выполняет:
Разработчику не требуется реализовывать алгоритмы вычислительной геометрии вручную.
Некоторые объекты состоят из нескольких независимых областей.
Пример:
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);
Если прямоугольники не пересекаются, выполнять сложные вычисления бессмысленно.
Когда необходим только факт пересечения:
turf.booleanIntersects(a, b);
Это быстрее построения результирующей геометрии.
Для больших коллекций объектов обычно применяются:
Индекс позволяет быстро находить потенциально пересекающиеся объекты и значительно сокращает количество геометрических вычислений.
Неверно:
[
[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]
Нарушение порядка координат приводит к некорректным вычислениям.
Опасный код:
const intersection = turf.intersect(
turf.featureCollection([
polygon1,
polygon2
])
);
const area = turf.area(intersection);
Без проверки возможна ошибка выполнения.
Безопасный вариант:
if (intersection) {
const area = turf.area(intersection);
}
Операция пересечения часто используется совместно с другими геометрическими функциями.
| Операция | Назначение |
|---|---|
| intersect | Общая область объектов |
| union | Объединение объектов |
| difference | Вычитание одной области из другой |
| dissolve | Слияние множества объектов |
| buffer | Создание буферной зоны |
| area | Расчёт площади |
| bbox | Получение ограничивающего прямоугольника |
| booleanIntersects | Проверка факта пересечения |
Комбинация этих инструментов позволяет реализовывать сложные сценарии пространственного анализа непосредственно средствами JavaScript и Turf.js.