GeometryCollection

MapLibre GL JS поддерживает работу с GeoJSON-источниками, включая все стандартные типы геометрий спецификации GeoJSON, среди которых особое место занимает GeometryCollection. Этот тип представляет собой контейнер, объединяющий несколько геометрий разных типов в одном объекте, что принципиально отличает его от MultiPoint, MultiLineString и MultiPolygon, где допускается только однородный набор координат.

GeometryCollection определяется как объект с типом "GeometryCollection" и массивом геометрий в поле geometries:

{
  "type": "GeometryCollection",
  "geometries": [
    {
      "type": "Point",
      "coordinates": [30.5, 50.5]
    },
    {
      "type": "LineString",
      "coordinates": [
        [30.0, 50.0],
        [31.0, 51.0]
      ]
    }
  ]
}

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

Поддержка GeometryCollection в MapLibre GL JS

В MapLibre GL JS GeometryCollection поддерживается через GeoJSONSource. Однако важно понимать, что обработка таких объектов имеет особенности:

  • коллекция не является самостоятельным рендер-объектом;
  • каждый элемент внутри geometries интерпретируется как отдельная геометрия;
  • стилизация осуществляется на уровне слоя (layer), а не на уровне коллекции.

При добавлении источника:

map.addSource('collection-source', {
  type: 'geojson',
  data: {
    type: 'Feature',
    geometry: {
      type: 'GeometryCollection',
      geometries: [
        {
          type: 'Point',
          coordinates: [30.5, 50.5]
        },
        {
          type: 'LineString',
          coordinates: [
            [30.0, 50.0],
            [31.0, 51.0]
          ]
        }
      ]
    }
  }
});

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

Особенности рендеринга

При визуализации GeometryCollection в MapLibre GL JS проявляется важное ограничение: один слой не может одновременно корректно стилизовать разные типы геометрий.

Поведение слоёв

Если источник содержит GeometryCollection, то:

  • circle-layer отобразит только Point
  • line-layer отобразит только LineString
  • fill-layer отобразит только Polygon

Это означает, что одна коллекция фактически “разделяется” на логические подмножества в зависимости от типа слоя.

Пример фильтрации:

map.addLayer({
  id: 'points-layer',
  type: 'circle',
  source: 'collection-source',
  filter: ['==', '$type', 'Point']
});
map.addLayer({
  id: 'lines-layer',
  type: 'line',
  source: 'collection-source',
  filter: ['==', '$type', 'LineString']
});

Отличие GeometryCollection от Multi-геометрий

Ключевая концептуальная разница:

MultiPoint / MultiLineString / MultiPolygon

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

GeometryCollection

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

В контексте MapLibre GL JS предпочтение обычно отдаётся Multi-типам, поскольку они обеспечивают более предсказуемое поведение в стиле и производительности.

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

GeometryCollection увеличивает нагрузку на обработку данных по нескольким причинам:

  1. Де-нормализация данных MapLibre должен развернуть коллекцию в набор геометрий.

  2. Усложнение фильтрации Каждый элемент требует проверки $type.

  3. Рост числа render-объектов Вместо одного объекта фактически обрабатывается несколько.

При больших объёмах данных это может приводить к:

  • увеличению времени загрузки источника
  • росту затрат на перерисовку при зуме и панорамировании
  • усложнению кластеризации

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

Смешанные объекты на карте

GeometryCollection применяется, когда один логический объект состоит из нескольких типов геометрий, например:

  • точка + зона влияния (Point + Polygon)
  • маршрут + контрольные точки (LineString + Points)
  • геологические структуры (разные типы линий и областей)

Пример:

{
  "type": "Feature",
  "properties": {
    "name": "Station A"
  },
  "geometry": {
    "type": "GeometryCollection",
    "geometries": [
      {
        "type": "Point",
        "coordinates": [29.0, 49.0]
      },
      {
        "type": "Polygon",
        "coordinates": [
          [
            [28.9, 48.9],
            [29.1, 48.9],
            [29.1, 49.1],
            [28.9, 49.1],
            [28.9, 48.9]
          ]
        ]
      }
    ]
  }
}

Ограничения в фильтрации и выражениях

В слоях MapLibre GL JS фильтрация GeometryCollection работает только через стандартные GeoJSON-предикаты:

  • $type
  • geometry-type выражения
  • проверки свойств properties

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

Пример фильтра:

filter: ['==', ['geometry-type'], 'Polygon']

Взаимодействие с кластеризацией

При использовании cluster: true в GeoJSONSource GeometryCollection ведёт себя неоднозначно:

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

Это создаёт несогласованность, если коллекция используется как единый объект представления.

Преобразование GeometryCollection в Multi-типы

На практике для повышения совместимости с MapLibre GL JS часто выполняется нормализация:

Point и LineString остаются без изменений

Polygon остаётся Polygon

GeometryCollection разворачивается

Пример преобразования:

function expandGeometryCollection(feature) {
  if (feature.geometry.type !== 'GeometryCollection') return [feature];

  return feature.geometry.geometries.map((geom) => ({
    type: 'Feature',
    properties: feature.properties,
    geometry: geom
  }));
}

Такой подход позволяет:

  • упростить стилизацию
  • избежать сложных фильтров
  • улучшить производительность

Сценарии, где GeometryCollection оправдан

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

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

Ошибки при работе с GeometryCollection

Попытка стилизовать как единый объект

MapLibre не рассматривает коллекцию как единый визуальный примитив, что приводит к “частичному отображению”.

Игнорирование фильтрации по типу

Без фильтра $type возможна некорректная отрисовка всех геометрий в одном слое.

Передача вложенных коллекций

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

Влияние на архитектуру данных

Использование GeometryCollection в MapLibre GL JS обычно сигнализирует о необходимости пересмотра модели данных:

  • либо разбиение на отдельные Feature-объекты
  • либо переход к Multi-типам
  • либо предварительная нормализация на сервере

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