Convex hull

Геометрическое представление множества точек в пространстве координат часто требует выделения минимальной выпуклой области, содержащей все элементы набора. Такая область определяется как выпуклый многоугольник, внутри которого лежат все исходные точки, а любые отрезки между точками множества не выходят за его границы. В геоинформационных системах это используется для оценки пространственного охвата объектов, анализа кластеров, построения зон влияния и упрощённого визуального представления распределения данных.

В контексте веб-картографии на основе MapLibre GL JS подобная геометрия применяется при обработке GeoJSON-источников, когда требуется получить обобщённую границу набора точек и отобразить её поверх карты в виде полигонального слоя.

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

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

Такая структура используется для:

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

Алгоритмические подходы к построению

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

Алгоритм Джарвиса (Jarvis March) Итеративно обходит точки, выбирая следующую крайнюю точку по углу поворота. Эффективен при малом числе точек оболочки, но имеет сложность O(nh), где n — количество точек, h — количество точек на оболочке.

Алгоритм Грэхема (Graham Scan) Сортирует точки по полярному углу относительно опорной точки и строит оболочку с использованием стека. Имеет сложность O(n log n).

Quickhull Использует стратегию «разделяй и властвуй», аналогичную quicksort. Практически эффективен на случайных данных и часто применяется в библиотечных реализациях.

В веб-картографии обычно используются готовые реализации, скрывающие внутреннюю сложность вычислений.

Использование Turf.js для вычисления оболочки

В экосистеме MapLibre GL JS часто применяется библиотека Turf.js, предоставляющая функции геопространственного анализа. Для построения выпуклой оболочки используется функция turf.convex.

import maplibregl from "maplibre-gl";
import * as turf from "@turf/turf";

const map = new maplibregl.Map({
  container: "map",
  style: "https://demotiles.maplibre.org/style.json",
  center: [30.3, 59.9],
  zoom: 10
});

const points = turf.featureCollection([
  turf.point([30.25, 59.94]),
  turf.point([30.28, 59.92]),
  turf.point([30.33, 59.91]),
  turf.point([30.31, 59.96]),
  turf.point([30.27, 59.97])
]);

const hull = turf.convex(points);

Функция принимает FeatureCollection<Point> и возвращает Polygon, представляющий выпуклую оболочку.

Если набор точек вырожден (например, содержит менее трёх уникальных координат), результат может быть null, что требует обработки на уровне логики приложения.

Интеграция с MapLibre GL JS

После вычисления геометрии результат добавляется в качестве GeoJSON-источника. MapLibre GL JS отображает его через слои fill и line.

map.on("load", () => {
  map.addSource("points", {
    type: "geojson",
    data: points
  });

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

  map.addLayer({
    id: "hull-fill",
    type: "fill",
    source: "hull",
    paint: {
      "fill-color": "#3b82f6",
      "fill-opacity": 0.25
    }
  });

  map.addLayer({
    id: "hull-outline",
    type: "line",
    source: "hull",
    paint: {
      "line-color": "#1d4ed8",
      "line-width": 2
    }
  });

  map.addLayer({
    id: "points-layer",
    type: "circle",
    source: "points",
    paint: {
      "circle-radius": 5,
      "circle-color": "#ef4444"
    }
  });
});

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

Динамическое обновление данных

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

function updateHull(newFeatures) {
  const fc = turf.featureCollection(newFeatures);
  const newHull = turf.convex(fc);

  const hullSource = map.getSource("hull");
  hullSource.setData(newHull);
}

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

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

let timeout;

function scheduleUpdate(features) {
  clearTimeout(timeout);
  timeout = setTimeout(() => {
    const fc = turf.featureCollection(features);
    const newHull = turf.convex(fc);

    if (newHull) {
      map.getSource("hull").setData(newHull);
    }
  }, 200);
}

Работа с большими наборами данных

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

  • стоимость сортировки (O(n log n));
  • геометрические операции пересечения;
  • пересылка данных между WebGL-слоем и JavaScript.

Оптимизация включает:

  • предварительную агрегацию точек;
  • использование кластеризации (cluster: true в GeoJSON source);
  • фильтрацию выбросов;
  • периодическое пересчитывание вместо постоянного обновления.

MapLibre GL JS поддерживает кластеризацию на уровне источника:

map.addSource("points", {
  type: "geojson",
  data: points,
  cluster: true,
  clusterMaxZoom: 14,
  clusterRadius: 50
});

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

Геометрические особенности и пограничные случаи

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

Типичные особенности:

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

При обработке GeoJSON важно учитывать корректность координатной системы. MapLibre GL JS использует EPSG:4326 для GeoJSON и EPSG:3857 для рендеринга, преобразование выполняется автоматически.

Взаимодействие с пользовательскими событиями карты

Интерактивные сценарии часто предполагают добавление точек по клику на карту и немедленное обновление оболочки.

const dynamicPoints = [];

map.on("click", (e) => {
  const point = turf.point([e.lngLat.lng, e.lngLat.lat]);
  dynamicPoints.push(point);

  const fc = turf.featureCollection(dynamicPoints);
  const hull = turf.convex(fc);

  map.getSource("points").setData(fc);

  if (hull) {
    map.getSource("hull").setData(hull);
  }
});

При использовании инструментов рисования, совместимых с MapLibre GL JS (например, @mapbox/mapbox-gl-draw), источником данных могут служить редактируемые слои, из которых извлекаются координаты для пересчёта геометрии.

Производственные сценарии применения

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

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

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

Ограничения вычислительной модели

Использование выпуклой оболочки в клиентских приложениях связано с рядом ограничений:

  • отсутствие учёта плотности внутри области;
  • чувствительность к выбросам;
  • ограниченная точность при большом числе точек без оптимизации;
  • необходимость пересчёта при каждом изменении данных;
  • зависимость от производительности JavaScript-окружения.

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

Геометрия оболочки остаётся базовым инструментом пространственного анализа в MapLibre GL JS, обеспечивая быстрый способ перехода от дискретных точек к непрерывному полигональному представлению, интегрируемому в рендеринговый pipeline веб-карты.