Генерация гексагональной сетки

Гексагональная сетка в геопространственных приложениях используется для дискретизации поверхности на равные по площади ячейки с шестиугольной геометрией. В Turf.js этот инструмент реализован через функцию, которая строит регулярную сетку из шестиугольников внутри заданного ограничивающего прямоугольника (bounding box). Такой подход часто применяется в аналитике плотности событий, агрегации точек, построении heatmap-подобных структур и оптимизации пространственных запросов.

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

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

В Turf.js генерация такой структуры выполняется с учётом заданного масштаба ячейки и географических единиц измерения.


Основная функция hexGrid

Функция построения гексагональной сетки имеет следующий базовый вид:

turf.hexGrid(bbox, cellSide, options)

Параметры:

bbox Ограничивающий прямоугольник, задаваемый массивом:

[minX, minY, maxX, maxY]

Координаты обычно представлены в системе WGS84 (долгота/широта), если не используется проекция.

cellSide Размер стороны гексагона. Это ключевой параметр, определяющий плотность сетки. Чем меньше значение, тем более детализированной становится сетка.

options Объект дополнительных настроек:

  • units — единицы измерения (kilometers, miles, meters, degrees);
  • properties — свойства, которые будут добавлены ко всем ячейкам;
  • mask — полигон, ограничивающий область генерации сетки.

Геометрия шестиугольника и масштабирование

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

Для правильного шестиугольника:

  • расстояние между противоположными сторонами определяется как √3 * a;
  • расстояние между противоположными вершинами равно 2a, где a — длина стороны.

Turf.js абстрагирует эти вычисления, позволяя задавать только cellSide, а пересчёт в географические координаты выполняется внутри библиотеки с учётом выбранных единиц измерения.


Алгоритм генерации сетки

Генерация гексагональной сетки в Turf.js выполняется поэтапно:

  1. Нормализация входного bbox Координаты приводятся к внутреннему представлению, учитывающему возможные пересечения антимеридиана.

  2. Вычисление шагов сетки Определяется горизонтальный и вертикальный шаг между центрами шестиугольников. При этом используется шахматное смещение строк.

  3. Итерация по координатной плоскости Пространство покрывается сеткой точек-центров, где каждая вторая строка смещается на половину ширины ячейки.

  4. Построение геометрии шестиугольника Для каждой точки-центра формируется полигон из шести вершин.

  5. Обрезка по границам bbox или mask Если указан mask, выполняется пересечение каждого шестиугольника с полигоном маски.

  6. Формирование FeatureCollection Результат возвращается в формате GeoJSON.


Базовый пример использования

import * as turf from "@turf/turf";

const bbox = [30.0, 50.0, 32.0, 52.0];

const hexGrid = turf.hexGrid(bbox, 10, {
  units: "kilometers"
});

console.log(hexGrid);

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


Использование свойства properties

Каждая ячейка сетки может содержать дополнительные метаданные. Это важно для аналитических задач, где каждая зона должна хранить агрегированную информацию.

const grid = turf.hexGrid(bbox, 5, {
  units: "kilometers",
  properties: {
    region: "analysis-zone",
    type: "hex-cell"
  }
});

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


Маскирование области генерации

Параметр mask позволяет ограничить генерацию сетки сложным полигоном. Это особенно полезно при работе с административными границами, береговыми линиями или произвольными областями интереса.

const mask = turf.polygon([[
  [30.5, 50.5],
  [31.5, 50.5],
  [31.5, 51.5],
  [30.5, 51.5],
  [30.5, 50.5]
]]);

const grid = turf.hexGrid(bbox, 8, {
  units: "kilometers",
  mask
});

В этом случае результирующие шестиугольники будут обрезаны по границам маски, и в итоговую коллекцию попадут только пересекающиеся области.


Влияние параметра cellSide на плотность сетки

Параметр cellSide определяет разрешение сетки. При уменьшении значения:

  • увеличивается количество ячеек;
  • возрастает вычислительная нагрузка;
  • повышается детализация анализа.

При увеличении значения:

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

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


Сравнение с квадратной сеткой

Turf.js также поддерживает квадратную сетку через аналогичную функцию. Однако гексагональная структура имеет ряд отличий:

  • у квадратов 4 соседних ячейки, у гексагонов — 6;
  • расстояние до центра соседних ячеек у гексагонов более равномерное;
  • визуально гексагональная сетка менее подвержена эффекту «ступенчатости»;
  • вычисление соседей в гекс-сетке более симметрично.

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


Практические сценарии применения

Гексагональная сетка часто используется как промежуточный слой между сырыми геоданными и аналитическими моделями.

Типовые сценарии:

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

В каждом случае шестиугольники выступают как контейнеры для статистики: количества точек, суммарного веса, средней величины и других метрик.


Агрегация данных в ячейках

После генерации сетки типичным шагом является сопоставление точек с ячейками:

const points = turf.featureCollection([
  turf.point([30.1, 50.1]),
  turf.point([30.3, 50.2]),
  turf.point([31.0, 50.5])
]);

const grid = turf.hexGrid(bbox, 10, {
  units: "kilometers"
});

grid.features.forEach(cell => {
  let count = 0;

  points.features.forEach(pt => {
    if (turf.booleanPointInPolygon(pt, cell)) {
      count++;
    }
  });

  cell.properties.count = count;
});

Каждая ячейка получает дополнительное поле count, отражающее плотность точек внутри неё.


Работа с проекциями и единицами измерения

Параметр units критически влияет на интерпретацию cellSide. Turf.js поддерживает несколько систем:

  • kilometers — наиболее распространённый вариант;
  • miles — для англоязычных систем измерения;
  • meters — для высокоточной локальной аналитики;
  • degrees — для грубых географических расчетов без проекции.

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


Особенности производительности

При генерации крупных сеток важно учитывать вычислительную сложность. Количество ячеек растёт обратно пропорционально квадрату cellSide.

Практические рекомендации:

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

Геометрические особенности смещения строк

Ключевой элемент алгоритма — шахматное смещение. Каждая вторая строка гексагонов сдвигается на половину ширины ячейки. Это обеспечивает плотное заполнение без зазоров.

Такое смещение приводит к следующей структуре:

  • центр ячейки в строке N находится прямо над/под центром строки N+2;
  • соседние строки образуют треугольную решётку;
  • расстояния между центрами равномерны по всем направлениям.

Особенности обрезки по границам

При использовании mask важно учитывать, что Turf.js выполняет геометрическое пересечение полигонов. Это означает:

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

Это может влиять на статистику, если не учитывать нормализацию по площади.


Постобработка сетки

После генерации часто выполняются дополнительные операции:

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

Turf.js предоставляет набор функций, которые позволяют выполнять эти операции без перехода к внешним геоинформационным системам.


Использование в аналитических пайплайнах

Гексагональная сетка часто является промежуточным представлением в ETL-процессах геоданных. Схема обычно выглядит так:

  1. загрузка сырых координат;
  2. генерация hexGrid;
  3. пространственное присвоение точек;
  4. агрегация метрик;
  5. экспорт в формат визуализации или хранения.

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