Навигация
Навигатор
Чтобы создать навигатор, можно использовать готовый элемент интерфейса INavigationView и класс NavigationManager.
Для этого нужно добавить на карту маркер с текущим местоположением и создать слой навигатора с помощью фабрики INavigationViewFactory и класса NavigationManager.
// Создаём фабрику объектов карты.
guard let mapFactory = try? sdk.makeMapFactory(options: .default) else {
return
}
// Добавляем слой карты в иерархию представлений.
let mapView = mapFactory.mapView
mapView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(mapView)
NSLayoutConstraint.activate([
mapView.leftAnchor.constraint(equalTo: containerView.leftAnchor),
mapView.rightAnchor.constraint(equalTo: containerView.rightAnchor),
mapView.topAnchor.constraint(equalTo: containerView.topAnchor),
mapView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
])
// Добавляем на карту маркер с текущим местоположением.
let locationSource = MyLocationMapObjectSource(
context: sdk.context,
directionBehaviour: .followSatelliteHeading,
controller: createSmoothMyLocationController()
)
let map = mapFactory.map
map.addSource(source: locationSource)
// Создаём NavigationManager.
let navigationManager = NavigationManager(platformContext: sdk.context)
// Добавляем карту в навигатор.
navigationManager.mapManager.addMap(map: map)
// Создаём фабрику UI-компонентов навигатора.
let navigationViewFactory = sdk.makeNavigationViewFactory()
// Создаём с помощью фабрики слой навигатора и размещаем его в иерархии выше слоя карты.
let navigationView = navigationViewFactory.makeNavigationView(
map: map,
navigationManager: navigationManager
)
navigationView.translatesAutoresizingMaskIntoConstraints = false
containerView.addSubview(navigationView)
NSLayoutConstraint.activate([
navigationView.leftAnchor.constraint(equalTo: containerView.leftAnchor),
navigationView.rightAnchor.constraint(equalTo: containerView.rightAnchor),
navigationView.topAnchor.constraint(equalTo: containerView.topAnchor),
navigationView.bottomAnchor.constraint(equalTo: containerView.bottomAnchor)
])
// Добавляем обработчик нажатия кнопки закрытия.
navigationView.closeButtonCallback = { [weak navigationManager] in
navigationManager?.stop()
}
Навигатор может работать в трёх режимах: свободная навигация, ведение по маршруту и симуляция ведения.
Настройки навигатора можно изменить через свойства NavigationManager.
Свободная навигация
В этом режиме маршрут следования отсутствует, но навигатор будет информировать о превышениях скорости, дорожных камерах, авариях и ремонтных работах.
Чтобы запустить навигатор в этом режиме, нужно вызвать метод start()
без параметров.
navigationManager.start()
Ведение по маршруту
В этом режиме на карте будет построен маршрут от текущего местоположения до указанной точки назначения, и пользователь будет получать инструкции по мере движения.
Чтобы запустить навигатор в этом режиме, нужно вызвать метод start()
и указать объект RouteBuildOptions - координаты точки назначения и настройки маршрута.
let routeBuildOptions = RouteBuildOptions(
finishPoint: RouteSearchPoint(
coordinates: GeoPoint(
latitude: 55.752425,
longitude: 37.613983
)
),
routeSearchOptions: routeSearchOptions
)
navigationManager.start(routeBuildOptions)
Дополнительно при вызове метода start()
можно указать объект TrafficRoute - готовый маршрут для навигации. В таком случае навигатор не будет пытаться построить маршрут от текущего местоположения, а начнёт ведение по указанному маршруту.
// Ищем маршрут.
self.routeSearchCancellable = routesFuture.sink { routes in
guard let route = routes.first else { return }
// Настройки маршрута.
let routeBuildOptions = RouteBuildOptions(
finishPoint: finishPoint,
routeSearchOptions: routeSearchOptions
)
// Запускаем навигатор.
navigationManager.start(
routeBuildOptions: routeBuildOptions,
trafficRoute: route
)
} failure: { error in
print("Не удалось найти маршрут: \\(error)")
}
Симуляция ведения по маршруту
В этом режиме навигатор не будет отслеживать реальное местоположение устройства, а запустит симулированное движение по указанному маршруту. Режим удобно использовать для отладки.
Чтобы запустить навигатор в режиме симуляции, нужно вызвать метод startSimulation()
, указав готовый маршрут (TrafficRoute) и его настройки (RouteBuildOptions).
Скорость движения можно изменить с помощью свойства SimulationSettings.speed (метры в секунду).
navigationManager.simulationSettings.speed = 30 / 3.6
navigationManager.startSimulation(
routeBuildOptions: routeBuildOptions,
trafficRoute: route
)
Остановить симуляцию можно с помощью метода stop()
.
navigationManager.stop()
Навигация внутри зданий
SDK предоставляет возможность строить маршруты внутри некоторых зданий, для которых существуют этажные планы. Например, можно проложить маршрут до конкретного магазина в торговом центре, составить сложный маршрут между несколькими точками и тд.
Этот тип навигации включен в набор стандартной поставки Full SDK, однако имеет ряд ограничений:
- Может быть активирован только в режиме пешеходной навигации
- Из-за особенностей работы современных систем позиционирования, возможности определения позиции внутри зданий сильно ограничены. Когда система определит, что устройство попало в пределы здания, слежение за геопозицей и ее отображение отключится, оставив построенный маршрут и рекомендации по проходу. Мы работаем над преодолением этих трудностей и надеемся предоставить надежный способ определения местоположения внутри зданий в будущем.
Создание маршрута
Создание маршрута происходит по принципам, описанным в разделе Ведение по маршруту с несколькими важными дополнениями. Разберем на примере:
// объект RouteBuildOptions также необходим
let routeBuildOptions = RouteBuildOptions(
finishPoint: RouteSearchPoint(
coordinates : GeoPoint(latitude: 55.752425, longitude: 37.613983),
objectId: ..., // Можно получить из DgisMapObject
levelId: ..., // Можно получить из DirectoryObject или RenderedObjectInfo
),
// routeSearchOptions должен иметь тип PedestrianRouteSearchOptions
routeSearchOptions: PedestrianRouteSearchOptions()
)
Как видно, обязательным является указание параметров objectId и levelId при создании конечной точки маршрута RouteSearchPoint
Отображение
Если вы используете стандартный набор UI контроллов навигации, создавая стандартную фабрику INavigationViewControlsFactory, как рекомендуется в начале раздела, эта возможность уже доступна и не требует предварительной конфигурации.
При использовании собственных контроллов в UI, для определения вхождения в режим навигации внутри здания можно пользоваться стандартными возможностями SDK, а именно подпиской на канал [indoorChannel](/ru/ios/sdk/reference/7.0/IndoorDetector#nav-lvl1--var indoorChannel). Этот канал можно получить из [NavigationManager'a](/ru/ios/sdk/reference/7.0/NavigationManager#nav-lvl1--var indoorDetector)