Simplify геометрии

Снижение геометрической сложности пространственных данных является одним из ключевых факторов производительности при работе с WebGL-картами. В MapLibre GL JS обработка сложных GeoJSON-объектов напрямую влияет на скорость отрисовки, потребление памяти и плавность взаимодействия с картой. Особенно критичными становятся линии и полигоны с большим количеством вершин, характерные для административных границ, береговых линий и инженерных сетей.

Каждый объект, передаваемый в источник данных MapLibre GL JS, интерпретируется как набор вершин, которые затем проходят через несколько стадий GPU-пайплайна. Чем больше вершин:

  • увеличивается время загрузки и парсинга GeoJSON
  • возрастает нагрузка на CPU при подготовке буферов
  • растёт объём данных в видеопамяти
  • снижается FPS при интерактивных изменениях (pan/zoom/rotate)

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

Алгоритм упрощения геометрии Douglas–Peucker

Основным подходом к упрощению линий и полигонов является алгоритм Дугласа–Пекера. Его идея заключается в рекурсивном удалении точек, которые отклоняются от аппроксимирующей линии меньше заданного порога.

Пусть есть линия, заданная точками:

[ P_1, P_2, , P_n]

Алгоритм:

  1. Строится отрезок между первой и последней точкой.
  2. Находится точка с максимальным расстоянием от этого отрезка.
  3. Если расстояние больше допуска ε, точка сохраняется, и процесс повторяется для двух частей.
  4. Если нет — все промежуточные точки удаляются.

Главный параметр:

  • tolerance (ε) — допустимое отклонение

Чем больше tolerance, тем сильнее упрощение и меньше деталей.


Упрощение GeoJSON с помощью Turf.js

В экосистеме MapLibre GL JS часто используется библиотека Turf.js для предварительной обработки геометрии. Основная функция — simplify.

import { simplify } from '@turf/turf';

const simplified = simplify(geojsonData, {
  tolerance: 0.01,
  highQuality: false,
  mutate: true
});

Ключевые параметры:

  • tolerance — степень упрощения (в градусах или метрах в зависимости от проекции)
  • highQuality — более медленный, но точный режим
  • mutate — изменяет исходный объект вместо создания нового

Использование Turf оправдано при подготовке данных до передачи в MapLibre, особенно если данные статичны или редко обновляются.


Предобработка данных перед добавлением в источник MapLibre

Наиболее эффективная стратегия — упрощение геометрии до загрузки в GeoJSONSource.

map.addSource('regions', {
  type: 'geojson',
  data: simplifiedGeojson
});

map.addLayer({
  id: 'regions-fill',
  type: 'fill',
  source: 'regions',
  paint: {
    'fill-color': '#4a90e2',
    'fill-opacity': 0.4
  }
});

Такой подход снижает нагрузку на:

  • парсер GeoJSON внутри MapLibre
  • генерацию вершинных буферов
  • пересчёт геометрии при изменении стиля

Особенно важно это при данных, превышающих десятки мегабайт.


Упрощение в зависимости от уровня масштаба

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

Принцип:

  • низкий zoom → сильное упрощение
  • средний zoom → умеренное упрощение
  • высокий zoom → полная геометрия

Пример реализации:

const sources = {
  low: simplifiedLow,
  mid: simplifiedMid,
  high: originalGeojson
};

И переключение по zoom:

map.on('zoom', () => {
  const z = map.getZoom();

  if (z < 5) {
    map.getSource('regions').setData(sources.low);
  } else if (z < 10) {
    map.getSource('regions').setData(sources.mid);
  } else {
    map.getSource('regions').setData(sources.high);
  }
});

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


Генерация упрощённых геометрий на этапе создания тайлов

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

Инструменты:

  • Tippecanoe
  • tilemaker
  • ogr2ogr

Пример Tippecanoe:

tippecanoe -o data.mbtiles \
  -zg \
  --drop-densest-as-needed \
  --extend-zooms-if-still-dropping \
  input.geojson

Ключевые механизмы:

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

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


Векторные источники MapLibre и поведение при масштабировании

При использовании vector tiles (vector source) упрощение геометрии происходит на стороне тайл-сервера. MapLibre лишь интерпретирует готовые данные.

map.addSource('countries', {
  type: 'vector',
  url: 'mapbox://tileset-id'
});

Каждый тайл содержит уже упрощённую версию геометрии, соответствующую своему zoom level. Это позволяет:

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

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

При работе с часто изменяющимися GeoJSON-источниками можно применять потоковое упрощение перед setData.

function updateData(rawGeojson) {
  const zoom = map.getZoom();

  let tolerance;

  if (zoom < 6) tolerance = 0.05;
  else if (zoom < 10) tolerance = 0.01;
  else tolerance = 0;

  const optimized = simplify(rawGeojson, {
    tolerance,
    highQuality: false,
    mutate: true
  });

  map.getSource('dynamic').setData(optimized);
}

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


Работа с полигонами высокой сложности

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

  • растёт стоимость triangulation
  • увеличивается время fill-rasterization
  • ухудшается интерактивность hover-обработчиков

Практика упрощения:

  • отдельно упрощать внешние и внутренние кольца
  • сохранять топологию (не допускать самопересечений)
  • использовать меньший tolerance для мелких объектов

Пример:

const simplified = simplify(largePolygon, {
  tolerance: 0.002,
  highQuality: true
});

Ограничения и типичные ошибки

Неправильное упрощение может приводить к искажениям:

  • потеря топологической связности между соседними полигонами
  • исчезновение узких географических объектов (реки, дамбы)
  • деформация границ при слишком высоком tolerance
  • артефакты при пересечениях MultiPolygon

Особенно критично упрощать согласованно, если несколько слоёв должны совпадать по границам.


Комбинирование подходов в архитектуре карты

На практике используется многослойная стратегия:

  • векторные тайлы для базовых слоёв
  • Turf.js для динамических GeoJSON-слоёв
  • pre-simplified datasets для статических объектов
  • zoom-based переключение геометрий

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