В вычислительной геометрии оболочка множества точек представляет собой полигон, который охватывает все точки набора. В контексте геопространственных данных различают два ключевых варианта: выпуклая оболочка и вогнутая оболочка. Вогнутая оболочка позволяет формировать границу, повторяющую реальную форму распределения точек, включая углубления и внутренние изгибы, тогда как выпуклая оболочка всегда стремится к минимальному выпуклому многоугольнику.
В Turf.js вогнутая оболочка реализуется через алгоритмы, основанные на построении триангуляции Делоне и последующем отсечении длинных рёбер, что позволяет получить более «естественную» форму области распределения точек.
Вогнутая оболочка отличается рядом характеристик:
Ключевым фактором является параметр, определяющий допустимую длину рёбер, формирующих контур. Именно он управляет степенью «вогнутости» результата.
В Turf.js используется подход, основанный на триангуляции Делоне:
Такой подход обеспечивает баланс между точностью и вычислительной сложностью, сохраняя приемлемую производительность при работе с большими наборами геоданных.
Основной инструмент построения вогнутой оболочки — функция
turf.concave.
import * as turf from "@turf/turf";
const points = turf.featureCollection([
turf.point([0, 0]),
turf.point([1, 2]),
turf.point([2, 1]),
turf.point([3, 3]),
turf.point([5, 1]),
turf.point([4, 4])
]);
const options = {
maxEdge: 2,
units: "kilometers"
};
const hull = turf.concave(points, options);
points Набор точек в формате
FeatureCollection<Point>. Минимально требуется три
точки, однако устойчивые результаты формируются при большем количестве
элементов.
options.maxEdge Максимально допустимая длина ребра, включаемого в оболочку. Этот параметр управляет детализацией:
options.units Единицы измерения длины. Поддерживаются километры, мили и другие геодезические единицы, используемые в Turf.js.
Поведение алгоритма напрямую зависит от порогового значения:
Эта зависимость делает параметр ключевым инструментом настройки геометрической точности.
В Turf.js выпуклая оболочка строится через
turf.convex.
const convexHull = turf.convex(points);
Различия между подходами:
Выпуклая оболочка используется как базовый геометрический предел, тогда как вогнутая — как приближённая к реальности граница.
Входные данные для построения оболочки должны соответствовать GeoJSON-структуре:
{
type: "FeatureCollection",
features: [
{
type: "Feature",
geometry: {
type: "Point",
coordinates: [lng, lat]
}
}
]
}
Выходная структура представляет собой полигон:
{
type: "Feature",
geometry: {
type: "Polygon",
coordinates: [
[
[lng, lat],
[lng, lat],
...
]
]
}
}
Алгоритм чувствителен к точкам, находящимся далеко от основной массы данных. Такие точки могут:
Для стабилизации результата применяется предварительная фильтрация данных:
При работе с координатами в Turf.js важно учитывать, что расстояния вычисляются на сфере. Это приводит к следующим особенностям:
Использование параметра units обеспечивает корректное
масштабирование расстояний.
Вогнутая оболочка часто применяется в связке с другими геооперациями:
turf.buffer для расширения границ области;turf.booleanPointInPolygon для проверки
принадлежности;turf.clusters для предварительной группировки;turf.truncate для нормализации координат.Пример комбинированного анализа:
const clustered = turf.clustersDbscan(points, 1, { units: "kilometers" });
const clusterPoints = clustered.features.filter(f => f.properties.cluster === 1);
const hull = turf.concave(turf.featureCollection(clusterPoints), {
maxEdge: 1.5,
units: "kilometers"
});
Существуют системные ограничения, характерные для реализации:
В случаях, когда построение вогнутой оболочки невозможно,
возвращается null.
Основной фактор производительности — триангуляция Делоне. Её сложность в среднем составляет O(n log n), однако дополнительные операции фильтрации рёбер увеличивают фактическое время выполнения.
Оптимизации:
Вогнутая оболочка не является точным геометрическим объектом в строгом математическом смысле. Это приближённая структура, описывающая плотность распределения точек. Она используется как инструмент анализа формы, а не как абсолютная граница.
На практике результат интерпретируется как: