Навигация | Mobile SDK | 2GIS Documentation
Android SDK

Навигация

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

Для этого нужно добавить в MapView элементы NavigationView и DefaultNavigationControls.

<ru.dgis.sdk.map.MapView
    android:id="@+id/mapView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >
    <ru.dgis.sdk.navigation.NavigationView
        android:id="@+id/navigationView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <ru.dgis.sdk.navigation.DefaultNavigationControls
            android:layout_width="match_parent"
            android:layout_height="match_parent"/>
    </ru.dgis.sdk.navigation.NavigationView>
</ru.dgis.sdk.map.MapView>

После этого нужно добавить на карту маркер с текущим местоположением и создать объект NavigationManager.

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    sdkContext = DGis.initialize(applicationContext, apiKeys)

    // Регистрируем источник геопозиции
    locationProvider = ManagerLocationSource(applicationContext)
    registerPlatformLocationSource(sdkContext, locationProvider)

    setContentView(R.layout.activity_navigation)

    findViewById<MapView>(R.id.mapView).apply { mapView ->
        lifecycle.addObserver(mapView)

        mapView.getMapAsync { map ->
            // Добавляем маркер с текущим местоположением
            map.addSource(
                MyLocationMapObjectSource(
                    sdkContext,
                    MyLocationDirectionBehaviour.FOLLOW_SATELLITE_HEADING,
                    createSmoothMyLocationController()
                )
            )
        }
    }

    // Создаём объект NavigationManager
    navigationManager = NavigationManager(sdkContext)

    findViewById<NavigationView>(R.id.navigationView).apply {
        // Привязываем созданный объект NavigationManager к элементу интерфейса NavigationView
        navigationManager = this@NavigationActivity.navigationManager
    }

    // Запускаем навигатор в режиме свободной навигации
    navigationManager.start()
}

Навигатор может работать в трёх режимах: свободная навигация, ведение по маршруту и симуляция ведения.

Настройки навигатора можно изменить через свойства NavigationManager.

В этом режиме маршрут следования отсутствует, но навигатор будет информировать о превышениях скорости, дорожных камерах, авариях и ремонтных работах.

Чтобы запустить навигатор в этом режиме, нужно вызвать метод start() без параметров.

navigationManager.start()

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

Чтобы запустить навигатор в этом режиме, нужно вызвать метод start() и указать объект RouteBuildOptions - координаты точки назначения и настройки маршрута.

val routeBuildOptions = RouteBuildOptions(
    finishPoint = RouteSearchPoint(
        coordinates = GeoPoint(latitude = 55.752425, longitude = 37.613983)
    ),
    routeSearchOptions = CarRouteSearchOptions(
        avoidTollRoads = true,
        avoidUnpavedRoads = false,
        avoidFerry = false,
        routeSearchType = RouteSearchType.JAM
    )
)

navigationManager.start(routeBuildOptions)

Дополнительно при вызове метода start() можно указать объект TrafficRoute - готовый маршрут для навигации (см. раздел Построение маршрута). В таком случае навигатор не будет пытаться построить маршрут от текущего местоположения, а начнёт ведение по указанному маршруту.

navigationManager.start(routeBuildOptions, trafficRoute)

В этом режиме навигатор не будет отслеживать реальное местоположение устройства, а запустит симулированное движение по указанному маршруту. Режим удобно использовать для отладки.

Чтобы запустить навигатор в режиме симуляции, нужно вызвать метод startSimulation(), указав готовый маршрут (TrafficRoute) и его настройки (RouteBuildOptions).

Скорость движения можно изменить с помощью свойства SimulationSettings.speed (метры в секунду).

navigationManager.simulationSettings.speed = 30 / 3.6
navigationManager.startSimulation(routeBuildOptions, trafficRoute)

Остановить симуляцию можно с помощью метода stop().

navigationManager.stop()

Чтобы включить показ дорожного трафика, нужно добавить на карту источник данных TrafficSource.

val trafficSource = TrafficSource(sdkContext)
map.addSource(trafficSource)

В рамках SDK можно использовать произвольный источник геопозиции. Для этого нужно реализовать интерфейс LocationSource.

public class CustomLocationSource: LocationSource {
    override fun activate(listener: LocationChangeListener?) {
        // Включение источника геопозиции
    }

    override fun deactivate() {
        // Выключение источника геопозиции
    }

    override fun setDesiredAccuracy(accuracy: DesiredAccuracy?) {
        // Изменение требуемого уровня точности
    }
}

Чтобы зарегистрировать созданный источник в SDK, нужно вызвать функцию registerPlatformLocationSource().

val customSource = CustomLocationSource()
registerPlatformLocationSource(sdkContext, customSource)

Основная точка входа в интерфейс - функция activate(). Когда SDK потребуется геопозиция, в эту функцию будет передан объект LocationChangeListener. После этого, чтобы сообщить текущую геопозицию, нужно передать в него массив объектов Location (от более старой позиции к более новой), используя метод onLocationChanged().

val location = Location(...)
val newLocations = arrayOf(location)
listener.onLocationChanged(newLocations)

Чтобы сообщить изменение доступности источника, можно вызвать метод onAvailabilityChanged().

Дополнительно можно менять логику определения геопозиции в зависимости от требуемой точности. Требуемая точность передаётся в функцию setDesiredAccuracy() в виде объекта DesiredAccuracy.

Когда источник геопозиции больше не требуется, будет вызвана функция deactivate().

  

SDK предоставляет возможность строить маршруты внутри некоторых зданий, для которых существуют этажные планы. Например, можно проложить маршрут до конкретного магазина в торговом центре, составить сложный маршрут между несколькими точками и тд.

Этот тип навигации включен в набор стандартной поставки Full SDK, однако имеет ряд ограничений:

  • Может быть активирован только в режиме пешеходной навигации
  • Из-за особенностей работы современных систем позиционирования, возможности определения позиции внутри зданий сильно ограничены. Когда система определит, что устройство попало в пределы здания, слежение за геопозицей и ее отображение отключится, оставив построенный маршрут и рекомендации по проходу. Мы работаем над преодолением этих трудностей и надеемся предоставить надежный способ определения местоположения внутри зданий в будущем.

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

// объект RouteBuildOptions также необходим
val routeBuildOptions = RouteBuildOptions(
    finishPoint = RouteSearchPoint(
        coordinates = GeoPoint(latitude = 55.752425, longitude = 37.613983),
        objectId = ..., // Можно получить из DgisMapObject
        levelId = ..., // Можно получить из DirectoryObject или RenderedObjectInfo
    ),
    // routeSearchOptions должен иметь тип PedestrianRouteSearchOptions
    routeSearchOptions = PedestrianRouteSearchOptions()
)

Как видно, обязательным является указание параметров objectId и levelId при создании конечной точки маршрута RouteSearchPoint

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

При использовании собственных контроллов в UI, для определения вхождения в режим навигации внутри здания можно пользоваться стандартными возможностями SDK, а именно подпиской на канал indoorChannel. Этот канал можно получить из [NavigationManager'a](/ru/android/sdk/reference/7.0/ru.dgis.sdk.navigation.NavigationManager#nav-lvl1--val indoorDetector)