Skip to content

Update User Location

Update user location

This tutorial shows how to update user location via navigation service and get feedback from it.

Get started

Before updating user location to navigation service, make sure GPS location is available, and it's recommended to use a dead reckoning module to get a high-precision location for some scenarios like tunnels.

Update location

Make a customized location observer.

1
2
3
4
5
6
7
8
class LocationObserver : public tn::drive::api::PositionEventListener
{
public:
    void onPositionIndicatorUpdated(const tn::drive::models::v1::Indicator& indicator) override
    {
        // ...
    }
};

Register the location observer to navigation service.

const auto locationObserver = tn::make_shared<LocationObserver>();
navigationService->addPositionEventListener(locationObserver);

Unregister the location observer before shutdown navigation service.

navigationService->removePositionEventListener(locationObserver);
navigationService->shutdown();

Construct a location input and feed it to the navigation service. Location inputs are recommended to be provided at a frequency no greater than 15 Hz. Too frequent inputs will cause some of them to be ignored by the navigation service. For some important location updates, you are recommended to set epoch_flag to true to ensure it will get handled in the navigation service.

tn::foundation::VehicleLocation inputLocation;
// when epoch_flag is set to true, the location input will be handled in navigation service
// for example a location input with high confidence
inputLocation.epoch_flag = true;

// elapsed time could be used as a key to match input and output locations
inputLocation.elapsed_time = std::chrono::duration<uint32_t, std::milli>(std::chrono::steady_clock::now() - getSystemStartTimePoint());

// bearing is strongly recommended to be set to increase map matching quality
inputLocation.bearing = getVehicleBearing();

// speed is strongly recommended to be set to increase map matching quality
inputLocation.speed = getVehicleSpeed();

// GPS location is must to have for an input location
inputLocation.coordinate = getVehicleGpsLocation();

// get location provider from foundation system
auto locationProvider = system->locationProvider();
locationProvider->updateLocation(inputLocation);

Handle map matching feedback

Handle map matching feedback.

void LocationObserver::onPositionIndicatorUpdated(const tn::drive::models::v1::Indicator& indicator)
{
    // location information is always available
    const auto location = indicator.location.matched_location;
    showVehicleLocationOnMap(location);

    if (indicator.matched_road.has_value())
    {
        const auto& roadInfo = indicator.matched_road.value();
        showSpeedLimit(roadInfo.speed_limit);

        const auto parking_lot = roadInfo.parking_lot;
        if (parking_lot)
        {
            // do something in the parking lot ...
        }

        // show combined road name if there are multiple names for the road
        showRoadNames(roadInfo.combined_name);

        // show the best name for the road even if there are multiple names for the road
        const auto roadName = parseRoadName(roadInfo.road_name);
        showRoadName(roadName);
    }

    if (indicator.regional.has_value())
    {
        const auto& regionalInfo = indicator.regional.value();
        showLocalTime(regionalInfo.time_zone);
    }

    // use map matching feedback to adjust dead reckoning locations
    if (indicator.feedback.has_value())
    {
        const auto& feedback = indicator.feedback.value();
        if (feedback.on_road)
        {
            // handle fields valid only on road, including:
            // oneway, right_hand, ferry, in_service_area, in_parking_lot, in_tunnel, 
            // lane_count, dist_from_bifurcation_behind, dist_to_bifurcation_ahead
            // NOTICE: these fields may not be related to matched road

            // omit code here ...
        }

        // feedback location may be different from map matched location
        const auto location = feedback.location;

        // use timestamp to match location input and output
        const auto elapsed_time = feedback.timestamp;
    }
}

Parse name string for road names

Name string is an encoded format to represent various names in one unified format. To decode the string, check the string format and use corresponding utility functions to get the real name.

std::string parseRoadName(const tn::mapcontent::models::v1::NameString& name)
{
    std::string parsedName;

    switch (name.format)
    {
        case tn::mapcontent::models::v1::NameString::Format::Name:
        case tn::mapcontent::models::v1::NameString::Format::ExitName:
        case tn::mapcontent::models::v1::NameString::Format::ExitNumber:
        {
            const auto ordinaryName = tn::mapcontent::models::v1::NameString::Utility::asOrdinaryName(name);
            parsedName = (ordinaryName.has_value() ? ordinaryName->orthography.content : "");
            break;
        }
        case tn::mapcontent::models::v1::NameString::Format::RoadNumber:
        {
            const auto roadNumber = tn::mapcontent::models::v1::NameString::Utility::asRoadNumberName(name);
            parsedName = (roadNumber.has_value() ? roadNumber->ordinary.orthography.content : "");
            break;
        }
        default:
            break;
    }

    return parsedName;
}

Next steps