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