GeometryCollection

GeometryCollection — специальный тип геометрии в OpenLayers, предназначенный для хранения нескольких геометрических объектов внутри одной общей структуры. В отличие от классов MultiPoint, MultiLineString и MultiPolygon, которые объединяют только однотипные объекты, GeometryCollection позволяет одновременно хранить точки, линии, полигоны и любые другие геометрии.

Класс находится в модуле:

import GeometryCollection from 'ol/geom/GeometryCollection.js';

Пример состава коллекции:

  • Point
  • LineString
  • Polygon
  • Circle
  • MultiPoint
  • MultiLineString
  • MultiPolygon

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


Когда используется GeometryCollection

На практике GeometryCollection применяется в ситуациях, когда несколько объектов логически образуют единое целое.

Типичные сценарии:

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

Например, условный объект аэропорта может состоять из:

  • точки диспетчерской вышки;
  • линии взлётной полосы;
  • полигона территории аэропорта.

Все эти элементы могут быть объединены в одну GeometryCollection.


Создание GeometryCollection

Конструктор принимает массив геометрий.

import GeometryCollection from 'ol/geom/GeometryCollection.js';
import Point from 'ol/geom/Point.js';
import LineString from 'ol/geom/LineString.js';
import Polygon from 'ol/geom/Polygon.js';

const collection = new GeometryCollection([
    new Point([30, 50]),
    new LineString([
        [20, 40],
        [40, 60]
    ]),
    new Polygon([
        [
            [10, 10],
            [30, 10],
            [30, 30],
            [10, 30],
            [10, 10]
        ]
    ])
]);

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


Использование внутри Feature

Чаще всего коллекция помещается в объект Feature.

import Feature from 'ol/Feature.js';

const feature = new Feature({
    geometry: collection
});

Теперь Feature представляет сразу несколько геометрических сущностей.


Получение геометрий

Метод getGeometries() возвращает массив всех элементов коллекции.

const geometries = collection.getGeometries();

console.log(geometries);

Результат:

[
    Point,
    LineString,
    Polygon
]

Полученные объекты являются полноценными экземплярами соответствующих классов.


Перебор элементов коллекции

const geometries = collection.getGeometries();

geometries.forEach((geometry) => {
    console.log(geometry.getType());
});

Вывод:

Point
LineString
Polygon

Метод getType() позволяет определить конкретный тип каждого элемента.


Получение количества геометрий

const count = collection.getGeometries().length;

console.log(count);

Результат:

3

Замена содержимого коллекции

Метод setGeometries() полностью заменяет список объектов.

import Point from 'ol/geom/Point.js';

collection.setGeometries([
    new Point([0, 0]),
    new Point([10, 10]),
    new Point([20, 20])
]);

После выполнения старая коллекция удаляется и создаётся новая структура данных.


Добавление новых объектов

Прямого метода addGeometry() в классе нет.

Для добавления необходимо:

  1. Получить массив геометрий.
  2. Добавить новый элемент.
  3. Передать обновлённый массив обратно.

Пример:

const geometries = collection.getGeometries();

geometries.push(
    new Point([100, 100])
);

collection.setGeometries(geometries);

Удаление геометрии

Аналогичным образом выполняется удаление.

const geometries = collection.getGeometries();

geometries.splice(1, 1);

collection.setGeometries(geometries);

Удаляется элемент с индексом 1.


Получение типа GeometryCollection

Любая геометрия OpenLayers поддерживает метод getType().

console.log(collection.getType());

Результат:

GeometryCollection

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


Вычисление границ коллекции

Метод getExtent() возвращает общий прямоугольник охвата всех вложенных геометрий.

const extent = collection.getExtent();

console.log(extent);

Формат результата:

[
    minX,
    minY,
    maxX,
    maxY
]

OpenLayers автоматически анализирует все вложенные объекты и вычисляет общий экстент.


Проверка пересечения с экстентом

const intersects = collection.intersectsExtent([
    0,
    0,
    100,
    100
]);

console.log(intersects);

Результат:

true

Если хотя бы одна геометрия пересекает область, метод возвращает true.


Клонирование коллекции

Метод clone() создаёт независимую копию объекта.

const copy = collection.clone();

После клонирования изменения одной коллекции не затрагивают другую.

copy.translate(100, 100);

Исходная коллекция останется без изменений.


Перемещение GeometryCollection

Метод translate() сдвигает все вложенные геометрии одновременно.

collection.translate(50, 20);

Здесь:

  • X увеличивается на 50;
  • Y увеличивается на 20.

Все объекты коллекции перемещаются синхронно.


Масштабирование GeometryCollection

Метод scale() изменяет размеры всех геометрий.

collection.scale(2);

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

Указание собственного центра:

collection.scale(
    2,
    2,
    [0, 0]
);

Поворот GeometryCollection

Метод rotate() выполняет вращение всей коллекции.

collection.rotate(
    Math.PI / 4,
    [0, 0]
);

Параметры:

  1. угол в радианах;
  2. центр вращения.

В данном случае выполняется поворот на 45 градусов.


Упрощение геометрии

Метод simplify() доступен и для коллекции.

const simplified =
    collection.simplify(10);

OpenLayers применяет упрощение ко всем вложенным геометриям, если это поддерживается их типом.


Работа с событиями изменений

Все геометрии OpenLayers наследуются от класса Observable.

Поэтому можно отслеживать изменения коллекции.

collection.on('change', () => {
    console.log('Geometry changed');
});

При любом изменении геометрии событие будет вызвано автоматически.


Изменение вложенных объектов

Событие возникает не только при изменении самой коллекции, но и при изменении её элементов.

const point = new Point([10, 20]);

const collection =
    new GeometryCollection([point]);

collection.on('change', () => {
    console.log('Collection updated');
});

point.setCoordinates([50, 50]);

Результат:

Collection updated

Коллекция отслеживает изменения своих дочерних геометрий.


GeometryCollection и GeoJSON

Стандарт GeoJSON содержит собственный тип:

{
  "type": "GeometryCollection",
  "geometries": []
}

OpenLayers умеет автоматически преобразовывать такие данные в объект GeometryCollection.

Пример GeoJSON:

{
  "type": "GeometryCollection",
  "geometries": [
    {
      "type": "Point",
      "coordinates": [30, 50]
    },
    {
      "type": "LineString",
      "coordinates": [
        [20, 20],
        [40, 40]
      ]
    }
  ]
}

Чтение:

import GeoJSON from 'ol/format/GeoJSON.js';

const format = new GeoJSON();

const geometry =
    format.readGeometry(geojsonData);

Тип результата:

geometry instanceof GeometryCollection

Экспорт в GeoJSON

const format = new GeoJSON();

const json =
    format.writeGeometryObject(
        collection
    );

Полученный объект:

{
  "type": "GeometryCollection",
  "geometries": [...]
}

Отличие от MultiPoint

MultiPoint

Хранит только точки.

new MultiPoint([
    [10, 20],
    [30, 40]
]);

GeometryCollection

Хранит любые типы геометрий.

new GeometryCollection([
    new Point([10, 20]),
    new LineString([
        [0, 0],
        [100, 100]
    ])
]);

Отличие от MultiLineString

MultiLineString содержит исключительно линии.

new MultiLineString([
    [
        [0, 0],
        [10, 10]
    ],
    [
        [20, 20],
        [30, 30]
    ]
]);

В GeometryCollection могут одновременно присутствовать:

[
    Point,
    LineString,
    Polygon
]

Отличие от MultiPolygon

MultiPolygon предназначен для набора полигонов.

new MultiPolygon([
    polygon1,
    polygon2
]);

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


Производительность

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

Накладные расходы

Каждый элемент коллекции остаётся полноценным объектом OpenLayers.

Например:

new GeometryCollection([
    point1,
    point2,
    point3,
    ...
]);

Каждая геометрия имеет:

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

Из-за этого коллекция обычно потребляет больше памяти, чем специализированные классы MultiPoint, MultiLineString или MultiPolygon.

Скорость обработки

Операции:

getExtent()
translate()
rotate()
scale()
simplify()

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

Сложность большинства таких операций приблизительно пропорциональна количеству элементов коллекции.


Практический пример

Объект наблюдательного поста:

import GeometryCollection from 'ol/geom/GeometryCollection.js';
import Point from 'ol/geom/Point.js';
import LineString from 'ol/geom/LineString.js';
import Polygon from 'ol/geom/Polygon.js';

const tower = new Point([100, 100]);

const road = new LineString([
    [50, 50],
    [150, 150]
]);

const territory = new Polygon([
    [
        [20, 20],
        [180, 20],
        [180, 180],
        [20, 180],
        [20, 20]
    ]
]);

const observationPost =
    new GeometryCollection([
        tower,
        road,
        territory
    ]);

Структура позволяет рассматривать весь объект как единую геометрическую сущность, сохраняя возможность работы с каждой составляющей отдельно. Благодаря поддержке трансформаций, сериализации в GeoJSON, отслеживания изменений и совместимости со всеми механизмами OpenLayers, GeometryCollection служит универсальным контейнером для сложных составных геометрий, содержащих объекты различных типов.