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

Навигация

С помощью SDK вы можете работать со следующими сценариями навигации:

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

import 'package:dgis_mobile_sdk_full/dgis.dart' as sdk;

final sdk.Context sdkContext = sdk.DGis.initialize();
final sdk.NavigationManager navigationManager = sdk.NavigationManager(sdkContext);

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

import 'package:dgis_mobile_sdk_full/dgis.dart' as sdk;

final sdk.MyLocationMapObjectSource locationSource = sdk.MyLocationMapObjectSource(sdkContext);
map.addSource(locationSource);

navigationManager.mapManager.addMap(map);

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

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

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

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

import 'package:dgis_mobile_sdk_full/dgis.dart' as sdk;

final sdk.Context sdkContext = sdk.DGis.initialize();
final sdk.NavigationManager navigationManager = sdk.NavigationManager(sdkContext);

navigationManager.startFreeRoam();

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

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

import 'package:dgis_mobile_sdk_full/dgis.dart' as sdk;

final routeBuildOptions = sdk.RouteBuildOptions(
    finishPoint: sdk.RouteSearchPoint(
        coordinates: sdk.GeoPoint(
            latitude: sdk.Latitude(55.757670),
            longitude: sdk.Longitude(37.660160),
        ),
    ),
    routeSearchOptions: sdk.RouteSearchOptions.car(
        sdk.CarRouteSearchOptions(),
    ),
);

navigationManager.start(routeBuildOptions);

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

navigationManager.start(routeBuildOptions, trafficRoute);

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

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

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

navigationManager.simulationSettings.speedMode = sdk.SimulationSpeedMode.overSpeed(
  sdk.SimulationAutoWithOverSpeed(10)
);

navigationManager.startSimulation(routeBuildOptions, trafficRoute);

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

navigationManager.stop();

  

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

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

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

Создание маршрута происходит по принципам, описанным в разделе Ведение по маршруту с несколькими важными дополнениями. При создании конечной точки маршрута RouteSearchPoint обязательно указать параметры objectId и levelId.

import 'package:dgis_mobile_sdk_full/dgis.dart' as sdk;

// Также необходим объект RouteBuildOptions
final routeBuildOptions = sdk.RouteBuildOptions(
    finishPoint: sdk.RouteSearchPoint(
        coordinates: sdk.GeoPoint(
            latitude: sdk.Latitude(55.757670),
            longitude: sdk.Longitude(37.660160),
        ),
        objectId: ..., // Можно получить из DgisMapObject
        levelId: ..., // Можно получить из DirectoryObject или RenderedObjectInfo
    ),
     // routeSearchOptions должен иметь тип PedestrianRouteSearchOptions
    routeSearchOptions: sdk.RouteSearchOptions.pedestrian(
        sdk.PedestrianRouteSearchOptions(),
    ),
);

Для определения вхождения в режим навигации внутри здания можно пользоваться стандартными возможностями SDK, а именно подпиской на канал indoorChannel. Этот канал можно получить из NavigationManager.indoorDetector.

Во время движения по автомобильному маршруту навигатор периодически ищет другие способы доехать до финишной точки. При поиске альтернативных маршрутов учитываются все заданные параметры маршрута и промежуточные точки (кроме тех, которые пользователь уже посетил).

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

Альтернативный маршрут показывается на карте в виде линии с бабликом, на котором показана разница во времени движения: сколько времени сэкономит или потеряет пользователь, если перейдёт на альтернативный маршрут. Для перехода на этот маршрут пользователь может нажать на линию маршрута на экране или просто свернуть на развилке на альтернативный маршрут. Если на развилке пользователь продолжает движение по основному маршруту, альтернативный маршрут исчезает с карты.

Среди альтернативных маршрутов может быть выделен особый тип «маршрут лучше», если маршрут соответствует следующим критериям:

  • Ожидаемая длительность движения по «маршруту лучше» должна быть существенно меньше, чем по оставшейся части основного маршрута. Разница по умолчанию — 5 минут.
  • «Маршрут лучше» должен существенно отличаться от основного маршрута по геометрии (по дорогам, через которые он проходит). По умолчанию разница в длине отличающихся рёбер маршрута — 500 метров.

Если среди обнаруженных альтернативных маршрутов находится «маршрут лучше», на карте дополнительно отображается отдельный UI-элемент, при нажатии на который пользователь может перейти на движение по «маршруту лучше» или явно отказаться от него. Этот элемент исчезает с экрана через определённое время (по умолчанию 30 секунд), но линия маршрута продолжает отображаться на карте до проезда развилки.

В один и тот же момент времени только один маршрут может быть предложен пользователю как «маршрут лучше». Поиск нового «маршрута лучше» начинается либо после явного отказа пользователя от предыдущего (при нажатии на UI-элемент), либо после проезда развилки с ним.

Чтобы изменить параметры поиска альтернативных маршрутов, используйте свойство AlternativeRoutesProviderSettings у объекта NavigationManager:

navigationManager.alternativeRoutesProviderSettings.alternativeRoutesEnabled = true;

Чтобы начать ведение по альтернативному маршруту, используйте AlternativeRouteSelector:

navigationManager.alternativeRouteSelector.selectAlternativeRoute(route);

В процессе навигации вы можете получать динамическую информацию о маршруте через свойство uiModel в NavigationManager и отображать её в UI навигатора. В классе Model представлены следующие параметры:

  • состояние навигатора (state и stateChannel);
  • текущая геопозиция, с которой работает навигатор (location и locationChannel);
  • флаг использования текущей геопозиции для навигации (locationAvailable и locationAvailableChannel);
  • информация о маршруте с манёврами (route и routeChannel);
  • дорожные события и пробочные данные на маршруте (dynamicRouteInfo и dynamicRouteInfoChannel);
  • текущая позиция пользователя на маршруте (routePosition и routePositionChannel);
  • флаг превышения скорости (exceedingMaxSpeedLimit и exceedingMaxSpeedLimitChannel);
  • флаг нахождения «маршрута лучше» (betterRoute и betterRouteChannel);
  • расстояние (distance) и время (duration) до конца маршрута;
  • флаг режима свободной навигации (isFreeRoam).

Информация о маршруте в Model изменяется динамически относительно текущей позиции пользователя на маршруте. Чтобы получать актуальную позицию, подпишитесь на канал routePositionChannel и затем используйте это значение для получения других данных о маршруте. Подробнее о работе с каналами см. в разделе Потоки значений.

Например, получите следующую информацию:

  • Расстояние (distance) и время (duration) от текущей точки до конца маршрута:

    // Канал для получения позиции на маршруте
    final positionChannel = navigationManager.uiModel.routePositionChannel;
    
    final subscription = positionChannel.listen((routePosition) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
    
        // Расстояние до конца маршрута в метрах
        final distance = navigationManager.uiModel.distance();
    
        // Время до конца маршрута в секундах
        final duration = navigationManager.uiModel.duration();
    
        ...
        });
    });
    
  • Дорожные события и данные о пробках (dynamicRouteInfo). Данные о дорожных событиях хранятся в контейнере RoadEventRouteAttribute, откуда элемент можно получить по позиции на маршруте.

    Например, чтобы получить следующее ближайшее дорожное событие на маршруте:

    // Канал для получения позиции на маршруте
    final positionChannel = navigationManager.uiModel.routePositionChannel;
    
    final subscription = positionChannel.listen((routePosition) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
    
        // Получить ближайшее дорожное событие относительно текущей позиции
        final dynamicInfo = navigationManager.uiModel.dynamicRouteInfo;
        final nearestEvent = dynamicInfo.roadEvents?.findNearForward(routePosition);
    
        ...
        });
    });
    
  • Текущее состояние навигатора. Вы можете получать его через подписку на канал stateChannel или отдельно (state):

    // Получить состояние навигатора вне канала
    final currentState = navigationManager.uiModel.state;
    
    // Канал для получения состояния навигатора
    final stateChannel = navigationManager.uiModel.stateChannel;
    
    final subscription = stateChannel.listen((state) {
    WidgetsBinding.instance.addPostFrameCallback((_) {
        ...
        });
    });
    

    Навигатор может находиться в одном из следующих состояний:

    • disabled — неактивен (начальное состояние);
    • navigation — в режиме ведения по маршруту;
    • routeSearch — в поиске нового маршрута;
    • finished — завершил ведение по маршруту (конечная точка достигнута).