Навигация | Mobile SDK | 2GIS Documentation
iOS SDK
Личный кабинет

Навигация

Чтобы создать навигатор, можно использовать готовый элемент интерфейса 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)