При работе с геоданными в Mapbox GL JS часто используются объекты, содержащие большое количество координат. Полилинии дорожных сетей, контуры зданий, границы административных регионов, береговые линии и другие геометрии могут состоять из тысяч или даже десятков тысяч вершин. Избыточное количество точек приводит к увеличению размера данных, росту потребления памяти и снижению производительности визуализации.
Минимизация вершин (Vertex Simplification) — это процесс уменьшения количества координат в геометрическом объекте при сохранении его визуальной формы и геометрической целостности.
Основные цели минимизации:
Каждая вершина представляет собой пару координат:
[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 | несколько МБ |
После загрузки браузер:
Каждая дополнительная вершина увеличивает вычислительные затраты.
При вызове:
source.setData(data);
Mapbox GL JS вынужден заново обрабатывать всю геометрию.
Чем больше вершин, тем дольше выполняется операция.
Чаще всего упрощают следующие типы объектов:
Маршруты:
{
type: "LineString",
coordinates: [...]
}
Границы районов:
{
type: "Polygon",
coordinates: [...]
}
Контуры стран и областей:
{
type: "MultiPolygon",
coordinates: [...]
}
Особенно заметна польза при работе с государственными и кадастровыми данными.
Минимизация не означает случайное удаление точек.
Например, имеется линия:
A --- B --- C --- D --- E
Если точки B и D лежат почти на одной прямой, их можно удалить:
A -------- C -------- E
Визуально линия останется практически такой же.
Идея состоит в том, чтобы сохранить значимые изгибы и убрать точки, не влияющие на форму объекта.
Наиболее распространенным методом упрощения геометрии является алгоритм Douglas-Peucker.
Его работа основана на поиске наиболее значимых точек.
Последовательность действий:
Схематично:
A -------------------- E
C
/
/
Если точка C значительно отклоняется от прямой AE, она остается в геометрии.
Если отклонение несущественно:
A -------------------- E
точка удаляется.
Главный параметр минимизации — допустимая погрешность.
Малый допуск:
tolerance = 1
Сохраняет большинство вершин.
Большой допуск:
tolerance = 20
Удаляет значительное количество точек.
Пример:
Исходная линия:
1000 вершин
После упрощения:
Допуск 1 -> 850 вершин
Допуск 5 -> 300 вершин
Допуск 20 -> 80 вершин
Увеличение допуска уменьшает размер данных, но снижает точность формы.
Наиболее эффективный подход — выполнять упрощение на сервере или этапе подготовки данных.
Например:
const geojson = loadData();
const simplified = simplify(geojson);
map.addSource("roads", {
type: "geojson",
data: simplified
});
Так браузер получает уже оптимизированные данные.
Преимущества:
Популярным инструментом является библиотека 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:
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 %
В результате:
Слишком агрессивное упрощение может привести к искажению данных.
Например:
Исходный контур:
/\/\/\/\/\/\/\
После сильного упрощения:
-----------
Проблемы:
Особенно критично это для:
Для полигонов необходимо сохранять замкнутость контура.
Исходный объект:
[
[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 мс
Определяется отклонением новой геометрии от исходной.
Чем меньше ошибка, тем выше точность.
Для больших GeoJSON-файлов:
Для высоконагруженных карт:
Для интерактивных приложений:
setData;Для максимальной производительности: