Минимизация вершин

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

Минимизация вершин (Vertex Simplification) — это процесс уменьшения количества координат в геометрическом объекте при сохранении его визуальной формы и геометрической целостности.

Основные цели минимизации:

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

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

Каждая вершина представляет собой пару координат:

[71.428, 51.128]

Для простой линии достаточно нескольких точек:

[
    [0, 0],
    [1, 1],
    [2, 2]
]

Однако реальные данные могут выглядеть иначе:

[
    [0, 0],
    [0.01, 0.01],
    [0.02, 0.02],
    [0.03, 0.03],
    ...
]

Если объект содержит тысячи точек, возникают дополнительные расходы:

Передача данных

GeoJSON необходимо скачать с сервера.

Например:

Количество вершин Размер объекта
100 ~5 КБ
1000 ~50 КБ
10000 ~500 КБ
100000 несколько МБ

Обработка браузером

После загрузки браузер:

  1. Парсит JSON.
  2. Создает внутренние структуры данных.
  3. Передает информацию в WebGL.
  4. Выполняет рендеринг.

Каждая дополнительная вершина увеличивает вычислительные затраты.

Обновление источников

При вызове:

source.setData(data);

Mapbox GL JS вынужден заново обрабатывать всю геометрию.

Чем больше вершин, тем дольше выполняется операция.


Где применяется минимизация

Чаще всего упрощают следующие типы объектов:

Полилинии

Маршруты:

{
    type: "LineString",
    coordinates: [...]
}

Полигоны

Границы районов:

{
    type: "Polygon",
    coordinates: [...]
}

MultiPolygon

Контуры стран и областей:

{
    type: "MultiPolygon",
    coordinates: [...]
}

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


Принцип сохранения формы

Минимизация не означает случайное удаление точек.

Например, имеется линия:

A --- B --- C --- D --- E

Если точки B и D лежат почти на одной прямой, их можно удалить:

A -------- C -------- E

Визуально линия останется практически такой же.

Идея состоит в том, чтобы сохранить значимые изгибы и убрать точки, не влияющие на форму объекта.


Алгоритм Дугласа — Пекера

Наиболее распространенным методом упрощения геометрии является алгоритм Douglas-Peucker.

Его работа основана на поиске наиболее значимых точек.

Последовательность действий:

  1. Берутся первая и последняя вершины.
  2. Между ними проводится прямая.
  3. Находится точка с максимальным отклонением.
  4. Если отклонение превышает допустимый порог, точка сохраняется.
  5. Процесс повторяется рекурсивно.

Схематично:

A -------------------- E
       C
      /
     /

Если точка C значительно отклоняется от прямой AE, она остается в геометрии.

Если отклонение несущественно:

A -------------------- E

точка удаляется.


Параметр допуска (Tolerance)

Главный параметр минимизации — допустимая погрешность.

Малый допуск:

tolerance = 1

Сохраняет большинство вершин.

Большой допуск:

tolerance = 20

Удаляет значительное количество точек.

Пример:

Исходная линия:

1000 вершин

После упрощения:

Допуск 1  -> 850 вершин
Допуск 5  -> 300 вершин
Допуск 20 -> 80 вершин

Увеличение допуска уменьшает размер данных, но снижает точность формы.


Минимизация перед загрузкой в Mapbox GL JS

Наиболее эффективный подход — выполнять упрощение на сервере или этапе подготовки данных.

Например:

const geojson = loadData();
const simplified = simplify(geojson);

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

Так браузер получает уже оптимизированные данные.

Преимущества:

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

Использование библиотеки Simplify.js

Популярным инструментом является библиотека Simplify.js.

Подключение:

<script src="simplify.js"></script>

Исходные точки:

const points = [
    { x: 0, y: 0 },
    { x: 10, y: 5 },
    { x: 20, y: 10 },
    { x: 30, y: 11 },
    { x: 40, y: 12 }
];

Упрощение:

const result = simplify(points, 2, true);

Параметры:

simplify(points, tolerance, highQuality);

Где:

  • points — массив точек;
  • tolerance — уровень упрощения;
  • highQuality — режим повышенной точности.

Упрощение GeoJSON

Пример обработки объекта GeoJSON:

function simplifyCoordinates(coords, step = 2) {
    return coords.filter((_, index) => index % step === 0);
}

Использование:

const simplified = {
    ...feature,
    geometry: {
        ...feature.geometry,
        coordinates: simplifyCoordinates(
            feature.geometry.coordinates
        )
    }
};

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


Векторные тайлы и автоматическая минимизация

Mapbox GL JS активно использует векторные тайлы.

Каждый тайл содержит геометрию только для своей области карты.

При генерации тайлов обычно применяется упрощение геометрии.

Преимущества:

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

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

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


Генерализация по уровням масштабирования

Распространенный подход — хранение нескольких версий объекта.

Например:

Масштаб Количество вершин
4 100
8 500
12 2000
16 10000

На маленьком масштабе отображается грубая форма.

На большом масштабе подключается подробная геометрия.

Такой механизм называется масштабно-зависимой генерализацией.


Влияние минимизации на производительность

Рассмотрим условный пример.

Исходный набор данных:

500 объектов
по 4000 вершин каждый

Общее количество:

2 000 000 вершин

После упрощения:

500 объектов
по 700 вершин

Получается:

350 000 вершин

Снижение нагрузки:

≈ 82 %

В результате:

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

Опасности чрезмерной минимизации

Слишком агрессивное упрощение может привести к искажению данных.

Например:

Исходный контур:

/\/\/\/\/\/\/\

После сильного упрощения:

-----------

Проблемы:

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

Особенно критично это для:

  • кадастровых участков;
  • инженерных сетей;
  • навигационных маршрутов;
  • геодезических данных.

Минимизация полигонов

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

Исходный объект:

[
    [0, 0],
    [5, 0],
    [10, 0],
    [10, 10],
    [0, 10],
    [0, 0]
]

После упрощения:

[
    [0, 0],
    [10, 0],
    [10, 10],
    [0, 10],
    [0, 0]
]

Первая и последняя точки должны оставаться одинаковыми.

Если это правило нарушается, полигон становится некорректным.


Динамическая минимизация на клиенте

Иногда геометрия поступает в полном объеме, а упрощение выполняется непосредственно в браузере.

Например, в зависимости от масштаба карты:

map.on("zoomend", () => {
    const zoom = map.getZoom();

    if (zoom < 8) {
        loadSimplifiedData();
    } else {
        loadDetailedData();
    }
});

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


Сохранение топологии

Простое удаление точек может разрушить связи между объектами.

Например:

Полигон A
Полигон B

имеют общую границу.

Если упрощать их независимо:

A | B

линии могут перестать совпадать.

Возникают:

  • щели;
  • наложения;
  • разрывы.

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


Метрики оценки качества упрощения

После минимизации часто оценивают качество результата.

Основные показатели:

Количество удаленных вершин

10000 → 1500

Размер файла

5 МБ → 800 КБ

Время рендеринга

120 мс → 25 мс

Геометрическая ошибка

Определяется отклонением новой геометрии от исходной.

Чем меньше ошибка, тем выше точность.


Практические рекомендации для Mapbox GL JS

Для больших GeoJSON-файлов:

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

Для высоконагруженных карт:

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

Для интерактивных приложений:

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

Для максимальной производительности:

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