Разбиение полигонов в Turf.js — это набор геопространственных операций, направленных на получение нескольких независимых геометрий из исходного полигона. В отличие от простых булевых операций, таких как пересечение или объединение, задача разбиения требует построения новых границ, корректной обработки самопересечений и поддержания валидности GeoJSON-структуры.
В Turf.js нет единственной универсальной функции «splitPolygon», поэтому разбиение реализуется через комбинацию булевых операций, работы с линиями, сетками и вспомогательной геометрией. Основные подходы зависят от характера разреза: по линии, по сетке, по маске или по произвольной кривой.
Полигон в Turf.js представлен как GeoJSON-объект типа
Polygon или MultiPolygon. Любое разбиение
сводится к преобразованию исходной области в множество новых
областей:
Ключевым ограничением является то, что Turf.js оперирует двумерной моделью на сфере (WGS84), поэтому все операции геометрически приближённые.
Наиболее распространённый сценарий — разрез полигона линией. Логика строится на пересечении полигона с «разделяющей» геометрией и последующем формировании двух и более частей.
В Turf.js для этого используются комбинации:
@turf/intersect — вычисление пересечения;@turf/difference — вычитание одной геометрии из
другой;@turf/line-intersect — поиск точек пересечения;@turf/buffer) для
стабилизации операций.Идея заключается в том, чтобы создать «режущую» область, превращённую в полигон, и последовательно вычитать её из исходного объекта.
import difference from "@turf/difference";
import polygon from "@turf/helpers";
const poly = polygon([[
[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]
]]);
// Разделяющая линия, расширенная до полигона
const cutter = polygon([[
[5, -5], [6, -5], [6, 15], [5, 15], [5, -5]
]]);
const part1 = difference(poly, cutter);
В этой схеме линия преобразуется в узкую полосу-полигон, которая «вырезает» часть области. Для получения второй половины выполняется обратная операция.
const part2 = difference(poly, difference(poly, cutter));
Такой подход нестабилен при сложных формах, но часто используется как быстрый прототип.
Более строгий метод — моделирование разреза через две полуплоскости. Линия разреза задаётся как бесконечная плоскость, ограниченная рамками карты.
Алгоритм:
intersection исходного полигона с каждым из
полигонов.import intersect from "@turf/intersect";
// условные "левый" и "правый" полигоны
const leftHalf = {
type: "Polygon",
coordinates: [[
[-100, -100],
[5, -100],
[5, 100],
[-100, 100],
[-100, -100]
]]
};
const rightHalf = {
type: "Polygon",
coordinates: [[
[5, -100],
[100, -100],
[100, 100],
[5, 100],
[5, -100]
]]
};
const partA = intersect(poly, leftHalf);
const partB = intersect(poly, rightHalf);
Этот метод обеспечивает более контролируемую геометрию, особенно при разрезах через центр сложных фигур.
Сеточное разбиение используется для тайлинга, пространственной индексации и анализа плотности данных.
Идея состоит в создании регулярной сетки прямоугольников и пересечении каждого элемента с исходным полигоном.
Сетка создаётся вручную через шаг по координатам:
const cells = [];
for (let x = 0; x < 10; x += 2) {
for (let y = 0; y < 10; y += 2) {
cells.push({
type: "Polygon",
coordinates: [[
[x, y],
[x + 2, y],
[x + 2, y + 2],
[x, y + 2],
[x, y]
]]
});
}
}
import intersect from "@turf/intersect";
const clippedCells = cells
.map(cell => intersect(poly, cell))
.filter(Boolean);
Результатом является набор фрагментов исходного полигона, разбитого по регулярной сетке.
Для больших геометрий часто используется разбиение через
bbox (bounding box).
import bbox from "@turf/bbox";
import bboxPolygon from "@turf/bbox-polygon";
const bounds = bbox(poly);
const tile = bboxPolygon([
bounds[0],
bounds[1],
bounds[2],
bounds[3]
]);
Далее область делится на несколько тайлов путём разбиения bbox на сетку меньших прямоугольников. Такой подход применяется в картографических системах и при генерации векторных тайлов.
При разбиении по сложным линиям (например, маршрутам или изолиниям) используется промежуточное построение точек пересечения и реконструкция полигонов.
Алгоритм:
Turf.js предоставляет базовые инструменты:
lineIntersectlineSplitpolygonToLinelineToPolygon (в отдельных расширениях)Пример поиска пересечений:
import lineIntersect from "@turf/line-intersect";
const intersections = lineIntersect(polygonToLine(poly), cutterLine);
Дальнейшая реконструкция требует сортировки точек по направлению линии и построения новых контуров.
При разбиении полигона с внутренними отверстиями возникает дополнительная сложность: отверстия должны быть корректно распределены между частями.
Правило:
В Turf.js это часто решается через повторную проверку
booleanPointInPolygon для контрольных точек.
import booleanPointInPolygon from "@turf/boolean-point-in-polygon";
const belongs = booleanPointInPolygon(holeCenter, part);
Разбиение полигонов в Turf.js подвержено типичным геометрическим проблемам:
Для стабилизации применяются:
@turf/simplify для уменьшения количества точек;Комбинированный подход, который чаще всего используется на практике:
intersect.import intersect from "@turf/intersect";
const left = intersect(poly, leftHalfPlane);
const right = intersect(poly, rightHalfPlane);
const result = [left, right].filter(Boolean);
Этот подход предпочтителен для предсказуемых разрезов и хорошо масштабируется.
Разбиение полигонов используется в задачах:
В каждом случае выбор метода определяется компромиссом между точностью геометрии и вычислительной стоимостью операций.