Переключение между этажами

В экосистеме HERE Technologies работа с внутренними пространствами зданий реализована через модель Venue / Indoor Mapping, где геометрия строится не как единая карта, а как набор уровней (floors), связанных общей структурой объекта. Каждый этаж рассматривается как отдельный слой данных, синхронизированный с географической привязкой здания и его POI-структурой.

В HERE Maps API поддержка этажности реализуется через механизм фильтрации пространственных объектов по атрибуту уровня (level, floorIndex, floorNumber), а также через управление видимостью слоёв в рендерере карты.


Модель данных этажей

Внутренняя структура многоэтажного объекта обычно включает:

  • Venue (объект здания) — контейнер всей геометрии
  • Levels (этажи) — независимые геометрические слои
  • Spaces (помещения) — полигоны внутри этажей
  • Features (объекты) — POI, зоны, технические элементы

Каждый уровень содержит метаданные:

  • идентификатор этажа
  • индекс высоты (z-index / elevation)
  • порядковый номер (floor number)
  • геометрические данные (polygons / multipolygons)
  • связи с навигационным графом

Фильтрация отображения основана на сопоставлении активного уровня и атрибутов объектов.


Загрузка indoor-данных

Работа с этажами начинается с включения indoor-слоя и загрузки venue-структуры:

const platform = new H.service.Platform({
  apikey: 'API_KEY'
});

const defaultLayers = platform.createDefaultLayers();

const map = new H.Map(
  document.getElementById('map'),
  defaultLayers.vector.normal.map,
  {
    center: { lat: 52.5200, lng: 13.4050 },
    zoom: 18,
    pixelRatio: window.devicePixelRatio
  }
);

После инициализации карты подключается сервис venue:

const venueService = platform.getVenueService();

const provider = new H.venues.Service(providerOptions);
const venues = new H.venues.Venues(provider);
map.addLayer(venues);

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


Принцип переключения этажей

Переключение этажей реализуется через изменение активного фильтра уровня отображения. Визуально это эквивалентно включению/выключению подмножества геометрии, относящейся к конкретному floorId.

Основные подходы:

  • установка активного floor index
  • фильтрация feature layer по атрибуту floor
  • использование venue controller
  • управление стилями слоя

Управление активным этажом через Venue Controller

В большинстве реализаций используется контроллер управления venue:

const venueProvider = venues.getProvider();

venueProvider.addEventListener('tap', (evt) => {
  const venue = evt.target;

  const floorSelector = venue.getFloorSelector();

  floorSelector.setActiveFloor(2);
});

Метод setActiveFloor изменяет текущий отображаемый уровень, скрывая остальные этажи.


Получение списка этажей

Перед переключением этажей выполняется запрос структуры здания:

const floors = venue.getFloors();

floors.forEach(floor => {
  console.log(floor.id, floor.level, floor.name);
});

Типичная структура объекта floor:

  • id — уникальный идентификатор
  • level — числовой индекс (например, -1, 0, 1, 2)
  • name — человекочитаемое название (Ground, First Floor)
  • geometryBounds — ограничивающий прямоугольник

Логика фильтрации геометрии

При смене этажа выполняется фильтрация всех feature-слоёв:

function applyFloorFilter(activeFloor) {
  venueProvider.setStyle(function (feature) {
    const featureFloor = feature.getProperty('floor');

    if (featureFloor === activeFloor) {
      return { opacity: 1 };
    }

    return { opacity: 0, visible: false };
  });
}

Такой подход обеспечивает:

  • мгновенное скрытие лишних уровней
  • сохранение геометрии в памяти
  • отсутствие повторной загрузки данных

События смены этажей

Система генерирует события при изменении активного уровня:

venueProvider.addEventListener('floorchange', (event) => {
  const previous = event.previousFloor;
  const current = event.activeFloor;

  console.log(previous, current);
});

События используются для синхронизации UI и внешних компонентов, например:

  • панели выбора этажей
  • индикаторов лифта
  • навигационных подсказок

Интеграция с UI-переключателем этажей

Типовой UI-компонент строится на основе списка floors:

function createFloorUI(floors) {
  const container = document.createElement('div');

  floors.forEach(floor => {
    const button = document.createElement('button');
    button.textContent = floor.name;

    button.oncl ick = () => {
      venue.getFloorSelector().setActiveFloor(floor.level);
    };

    container.appendChild(button);
  });

  return container;
}

UI синхронизируется с состоянием venue:

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

Многослойная визуализация

При отображении нескольких этажей одновременно используется режим partial visibility:

floorSelector.setVisibleFloors([0, 1]);

В этом режиме:

  • нижние этажи отображаются полупрозрачно
  • активный этаж выделяется контрастом
  • поддерживается вертикальная глубина (z-order)

Стиль и визуальная иерархия этажей

Стилизация этажей зависит от атрибутов:

  • floorColor
  • highlighted
  • accessibilityLevel
  • usageType

Пример динамического стиля:

venueProvider.setStyle(function (feature) {
  const isActive = feature.getProperty('active');

  return {
    fillColor: isActive ? '#4CAF50' : '#BDBDBD',
    strokeColor: '#333333',
    lineWidth: 1
  };
});

Координация этажей с навигацией

Внутренняя навигация учитывает этажность как часть графа:

  • переход между этажами через лифты
  • лестницы как edge между уровнями
  • эскалаторы как направленные переходы

При расчёте маршрута учитывается:

  • текущий floor
  • целевой floor
  • точки вертикального перехода

Оптимизация загрузки многоэтажных объектов

При работе с большим количеством уровней применяется:

  • ленивое подгружение floors
  • кеширование геометрии
  • декомпозиция здания на чанки
  • предзагрузка соседних этажей
venueProvider.setLoadingStrategy({
  preloadAdjacentFloors: true,
  cacheSize: 50
});

Синхронизация камеры с этажом

При смене уровня часто выполняется автоматическое позиционирование камеры:

function focusFloor(floor) {
  const bounds = floor.geometryBounds;

  map.getViewModel().setLookAtData({
    bounds: bounds,
    tilt: 45,
    zoom: 20
  });
}

Это позволяет:

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

Обработка перекрытий и вертикальной глубины

В сложных зданиях используется z-index stacking:

  • объекты разных этажей имеют независимые слои
  • перекрытия разрешаются через elevation priority
  • визуальный порядок определяется активным floor context

Работа с несколькими зданиями

При наличии нескольких venue в области:

  • каждый venue имеет собственный floor controller
  • переключение этажей изолировано
  • глобальный фильтр применяется только к активному зданию
venues.on('venuefocus', (evt) => {
  const activeVenue = evt.venue;
  activeVenue.getFloorSelector().reset();
});

Поведение при отсутствии indoor-данных

Если здание не содержит floor metadata:

  • переключение этажей отключается
  • отображается только ground-level geometry
  • UI floor selector не активируется
  • события floorchange не генерируются