Избегание определенных зон

Работа с зонами избегания в приложениях на основе HERE Maps API for JavaScript строится вокруг управления пространственными ограничениями: полигонами, географическими областями и правилами маршрутизации, которые исключают определённые участки карты из расчётов или пользовательского взаимодействия. В реальных задачах это используется для обхода опасных территорий, частных зон, зон с ограниченным доступом, экологических территорий, строительных площадок или просто нежелательных маршрутов.

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

Основные типы ограничений:

  • исключение областей из маршрутизации (routing avoidance)
  • блокировка взаимодействия с зонами на карте
  • геофенсинг (географические триггеры при входе/выходе)
  • комбинированные правила (например, избегать зоны + избегать типов дорог)

Каждый из этих типов реализуется на разных уровнях: от клиентского JavaScript до серверного расчёта маршрутов через Routing API.


Геозоны на основе полигонов

Базовая сущность любой зоны избегания — полигон. В JavaScript SDK он строится через геометрические примитивы.

const points = [
  { lat: 52.51, lng: 13.40 },
  { lat: 52.52, lng: 13.41 },
  { lat: 52.51, lng: 13.42 }
];

const polygon = new H.map.Polygon(new H.geo.Polygon(
  new H.geo.LineString(points.map(p => ({ lat: p.lat, lng: p.lng })))
), {
  style: {
    strokeColor: 'red',
    lineWidth: 2,
    fillColor: 'rgba(255,0,0,0.2)'
  }
});

map.addObject(polygon);

Ключевой момент: визуализация зоны не означает её автоматическое влияние на маршруты — это разные слои логики.


Исключение зон при построении маршрутов

Для реального избегания зон используется Routing API v8, который поддерживает параметр avoid[areas]. Он позволяет передавать географические области, которые должны быть исключены из маршрута.

Пример логики формирования запроса:

const routingParameters = {
  transportMode: 'car',
  origin: '52.5200,13.4050',
  destination: '52.5300,13.4200',
  'avoid[areas]': '52.515,13.405;52.515,13.415;52.525,13.415'
};

Здесь координаты задают полигональную область, которую маршрут должен обойти.

Важно:

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

Динамическое создание зон пользователем

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

const drawingTool = new H.map.Rect(new H.geo.Rect());

map.addEventListener('tap', function (evt) {
  const coord = map.screenToGeo(evt.currentPointer.viewportX, evt.currentPointer.viewportY);

  drawingTool.getGeometry().pushPoint(coord);

  if (drawingTool.getGeometry().getPointCount() > 2) {
    const polygon = new H.map.Polygon(drawingTool.getGeometry(), {
      style: {
        fillColor: 'rgba(0,0,255,0.2)',
        strokeColor: '#0000ff'
      }
    });

    map.addObject(polygon);
  }
});

После завершения редактирования координаты полигона обычно:

  • сериализуются в GeoJSON
  • отправляются на сервер маршрутизации
  • сохраняются в пользовательском профиле

Геофенсинг и логика событий

Избегание зон часто расширяется до геофенсинга — реакции на вход/выход из области.

function isPointInPolygon(point, polygon) {
  return H.geo.Point.prototype.withinPolygon.call(point, polygon);
}

map.addEventListener('pointermove', function (evt) {
  const coord = map.screenToGeo(evt.currentPointer.viewportX, evt.currentPointer.viewportY);

  if (isPointInPolygon(coord, restrictedZone)) {
    console.warn('Пользователь в запрещённой зоне');
  }
});

Практическое применение:

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

Исключение типов дорог и комбинированные ограничения

Помимо географических зон, Routing API поддерживает параметрические ограничения:

  • avoid[features]=tollRoads
  • avoid[features]=highways
  • avoid[features]=ferries

Комбинирование с полигонами позволяет строить сложную модель:

const params = {
  transportMode: 'truck',
  origin: '52.52,13.40',
  destination: '52.60,13.50',
  'avoid[areas]': encodedPolygon,
  'avoid[features]': 'tollRoads,highways'
};

Так формируется многоуровневая система ограничений:

  1. географические запреты
  2. типы инфраструктуры
  3. транспортные правила

GeoJSON как основной формат хранения зон

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

{
  "type": "Feature",
  "geometry": {
    "type": "Polygon",
    "coordinates": [
      [
        [13.40, 52.51],
        [13.41, 52.52],
        [13.42, 52.51],
        [13.40, 52.51]
      ]
    ]
  },
  "properties": {
    "type": "restricted",
    "name": "construction_zone"
  }
}

Причины использования GeoJSON:

  • совместимость с GIS-инструментами
  • простота сериализации
  • поддержка вложенных структур (MultiPolygon, holes)
  • интеграция с серверной геоаналитикой

Сложные случаи: мультиполигоны и «дыры»

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

Типичные сложности:

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

Пример мультиполигона:

const multiPolygon = new H.geo.MultiPolygon([
  polygon1,
  polygon2
]);

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

  • объединение пересечений
  • разбиение на простые области
  • упрощение геометрии

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

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

Оптимизационные подходы:

  • пространственные индексы (R-tree)
  • кластеризация зон по регионам
  • предварительная фильтрация по bounding box
  • упрощение геометрии (Douglas-Peucker)

На клиенте не рекомендуется выполнять проверку десятков тысяч точек полигона без упрощения — это приводит к деградации UI.


Интерактивное редактирование зон

Для административных интерфейсов часто используется режим редактирования:

  • перетаскивание вершин
  • добавление/удаление точек
  • визуальная подсветка пересечений
polygon.enableEditing();

polygon.addEventListener('geometrychange', function () {
  const updatedCoords = polygon.getGeometry().getExterior().getLatLngAltArray();
  console.log(updatedCoords);
});

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


Синхронизация клиентских и серверных ограничений

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

Типичная схема:

  1. клиент рисует полигон
  2. отправка GeoJSON на backend
  3. нормализация и хранение
  4. передача в Routing API при каждом запросе
  5. кэширование маршрутов с учётом зон

Несинхронизированные данные приводят к расхождению:

  • маршрут на карте отличается от фактического расчёта
  • пользователь видит «безопасный» путь, который сервер не подтверждает

Обработка пересечений маршрута с запрещённой зоной

Иногда требуется не просто избегать зоны, а детектировать пересечение.

function routeIntersectsPolygon(routeLineString, polygon) {
  return H.geo.Polyline.prototype.intersects.call(routeLineString, polygon);
}

Используется для:

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

Комбинация с реальным временем

При интеграции с потоковыми данными (например, пробки или аварии) зоны избегания могут становиться временными:

  • динамическое создание полигона на основе инцидента
  • TTL (time-to-live) для зоны
  • автоматическое удаление после события

Это превращает систему в адаптивную гео-модель, где ограничения меняются в реальном времени без ручного вмешательства.