Buffer, union, intersection

Буферизация геометрии в веб-картографии — одна из базовых операций пространственного анализа, позволяющая строить зоны влияния объектов на заданном расстоянии. В контексте Mapbox GL JS такие вычисления выполняются не самим движком рендеринга, а внешними геопространственными библиотеками, чаще всего Turf.js, после чего результат отображается как GeoJSON-слой.

Буфер (buffer) — это область вокруг геометрического объекта, сформированная на фиксированном расстоянии. Для точки это круг, для линии — полоса, для полигона — расширенная граница.

В Turf.js операция реализуется через turf.buffer.

Основной принцип работы

Буфер строится в географических координатах с учётом выбранной метрики расстояния:

  • километры
  • метры
  • мили
  • градусы (не рекомендуется для реальных измерений)
import * as turf from '@turf/turf';

const point = turf.point([71.4304, 51.1284]);

const buffered = turf.buffer(point, 5, { units: 'kilometers' });

Результат — GeoJSON-полигон, который можно напрямую отобразить в Mapbox GL JS.

Отображение буфера в Mapbox GL JS

map.addSource('buffer', {
  type: 'geojson',
  data: buffered
});

map.addLayer({
  id: 'buffer-fill',
  type: 'fill',
  source: 'buffer',
  paint: {
    'fill-color': '#3b82f6',
    'fill-opacity': 0.3
  }
});

Буфер часто используется для:

  • расчёта зон доступности
  • анализа покрытия сервисов
  • визуализации радиуса поиска
  • проверки пересечения объектов

Особенности геодезической буферизации

В Turf.js буфер строится с учётом сферической модели Земли. Это означает:

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

Для высокоточной аналитики важно учитывать:

  • искажения проекции Web Mercator
  • плотность вершин при аппроксимации окружности

Объединение геометрий (union)

Операция union объединяет несколько полигонов в один, устраняя внутренние границы.

В Turf.js используется turf.union.

Базовый пример

const poly1 = turf.polygon([[
  [71.0, 51.0],
  [72.0, 51.0],
  [72.0, 52.0],
  [71.0, 52.0],
  [71.0, 51.0]
]]);

const poly2 = turf.polygon([[
  [71.5, 51.5],
  [72.5, 51.5],
  [72.5, 52.5],
  [71.5, 52.5],
  [71.5, 51.5]
]]);

const merged = turf.union(poly1, poly2);

Особенности операции union

  • работает только с полигонами и мультиполигонами
  • корректно обрабатывает перекрытия и касания
  • при отсутствии пересечения может возвращать FeatureCollection с несколькими объектами (в зависимости от версии Turf)

Отображение результата

map.addSource('union', {
  type: 'geojson',
  data: merged
});

map.addLayer({
  id: 'union-fill',
  type: 'fill',
  source: 'union',
  paint: {
    'fill-color': '#10b981',
    'fill-opacity': 0.4
  }
});

Практическое применение union

Операция применяется в задачах:

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

Пересечение геометрий (intersection)

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

В Turf.js используется turf.intersect.

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

const poly1 = turf.polygon([[
  [71.0, 51.0],
  [72.0, 51.0],
  [72.0, 52.0],
  [71.0, 52.0],
  [71.0, 51.0]
]]);

const poly2 = turf.polygon([[
  [71.5, 51.5],
  [72.5, 51.5],
  [72.5, 52.5],
  [71.5, 52.5],
  [71.5, 51.5]
]]);

const overlap = turf.intersect(poly1, poly2);

Поведение функции

  • возвращает Polygon или MultiPolygon
  • возвращает null, если пересечения нет
  • учитывает топологию, а не только координатное совпадение

Отображение пересечения в Mapbox GL JS

if (overlap) {
  map.addSource('intersection', {
    type: 'geojson',
    data: overlap
  });

  map.addLayer({
    id: 'intersection-fill',
    type: 'fill',
    source: 'intersection',
    paint: {
      'fill-color': '#ef4444',
      'fill-opacity': 0.5
    }
  });
}

Применение intersection

Операция используется для:

  • определения пересечения зон доставки
  • анализа конфликтующих территорий
  • поиска общих областей интереса
  • пространственного анализа рисков

Комбинирование buffer, union и intersection

В реальных задачах эти операции часто используются совместно.

Пример сценария: анализ зоны покрытия

  1. Создаётся буфер вокруг точек объектов
  2. Буферы объединяются через union
  3. Сравниваются с другой зоной через intersection
const bufferA = turf.buffer(pointA, 3, { units: 'kilometers' });
const bufferB = turf.buffer(pointB, 3, { units: 'kilometers' });

const combined = turf.union(bufferA, bufferB);

const overlapZone = turf.intersect(combined, referenceArea);

Типовая архитектура вычислений

В Mapbox GL JS важно разделять:

  • слой данных (GeoJSON)
  • слой отображения (fill, line, circle)
  • слой вычислений (Turf.js)

Mapbox GL JS не выполняет геоаналитику самостоятельно, поэтому архитектурно:

  • Mapbox GL JS отвечает за визуализацию
  • Turf.js — за геометрию
  • внешний бэкенд — за тяжёлые расчёты при больших данных

Геометрическая сложность операций

Buffer

Сложность зависит от:

  • числа сегментов окружности
  • длины линии
  • количества вершин полигона

При увеличении precision растёт:

  • количество координат
  • нагрузка на рендеринг WebGL
  • размер GeoJSON

Union

Наиболее тяжёлая операция из трёх:

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

Intersection

Оптимизируется за счёт:

  • предварительного bounding box теста
  • отсечения непересекающихся объектов
  • локального анализа пересечений рёбер

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

При десятках или сотнях объектов прямое использование union/intersection в браузере становится узким местом.

Используются подходы:

  • тайлинг данных (vector tiles)
  • предагрегация на сервере
  • spatial indexing (R-tree)
  • кластеризация перед буферизацией

В Mapbox GL JS часто применяется:

map.addSource('points', {
  type: 'geojson',
  data: largeFeatureCollection,
  cluster: true
});

После кластеризации буфер строится уже не для всех точек, а для центроидов кластеров.


Тонкости визуализации результатов

При отображении результатов buffer/union/intersection важно учитывать:

  • порядок слоёв (z-index)
  • прозрачность fill-opacity
  • обводку для сложных границ
'fill-outline-color': '#111827'

Также полезно использовать:

  • разные цвета для операций
  • hover-эффекты через feature-state
  • динамическое обновление источника через setData

Обновление геометрии в реальном времени

Mapbox GL JS позволяет динамически пересчитывать результат:

source.setData(newBufferedGeometry);

Это используется в сценариях:

  • интерактивное изменение радиуса буфера
  • перетаскивание объектов
  • фильтрация пересечений по параметрам

Практическая связка с пользовательским вводом

Буферизация часто привязывается к событиям карты:

map.on('click', (e) => {
  const pt = turf.point([e.lngLat.lng, e.lngLat.lat]);
  const buf = turf.buffer(pt, 2, { units: 'kilometers' });

  map.getSource('buffer').setData(buf);
});

Аналогично union и intersection могут пересчитываться при добавлении новых объектов или изменении фильтров.


Итоговые принципы использования операций

  • buffer используется для создания зон влияния
  • union применяется для слияния пересекающихся областей
  • intersection позволяет выделить общие области между слоями данных

Комбинация этих операций формирует основу пространственного анализа в веб-картах, где Mapbox GL JS выступает как визуальный слой, а геометрические вычисления выполняются внешними библиотеками и логикой приложения