Update User Location
Update user location
This tutorial shows how to update user location via drive session and get feedback from it.
Get started
Before updating user location to drive session, 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.
| class LocationObserver : public tn::drive::api::PositionEventListener
{
public:
void onPositionIndicatorUpdated(const tn::drive::models::v1::Indicator& indicator) override
{
// ...
}
};
|
Register the location observer to drive session.
| const auto locationObserver = tn::make_shared<LocationObserver>();
driveSession->addPositionEventListener(locationObserver);
|
Unregister the location observer before shutdown drive session.
| driveSession->removePositionEventListener(locationObserver);
driveSession->shutdown();
|
Construct a location input and feed it to the drive session.
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 drive session.
For some important location updates, you are recommended to set epoch_flag to true
to ensure it will get handled in the drive session.
| tn::drive::models::v1::VehicleLocation inputLocation;
// when epoch_flag is set to true, the location input will be handled in drive session
// 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();
driveSession->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);
// 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