[traffxml] Add router-based decoder, still crude, ugly and buggy

To use it, redefine DefaultTraffDecoder in traffxml/traff_decoder.hpp

Signed-off-by: mvglasow <michael -at- vonglasow.com>
This commit is contained in:
mvglasow
2025-05-24 21:08:58 +03:00
parent bd178932c1
commit 9afb28aaa1
7 changed files with 474 additions and 10 deletions

View File

@@ -296,6 +296,7 @@ Framework::Framework(FrameworkParams const & params, bool loadMaps)
[this]() -> power_management::PowerManager const & { return m_powerManager; }), [this]() -> power_management::PowerManager const & { return m_powerManager; }),
static_cast<RoutingManager::Delegate &>(*this)) static_cast<RoutingManager::Delegate &>(*this))
, m_trafficManager(m_featuresFetcher.GetDataSource(), , m_trafficManager(m_featuresFetcher.GetDataSource(),
[this]() -> storage::CountryInfoGetter const & { return GetCountryInfoGetter(); },
[this](string const & id) -> string { return m_storage.GetParentIdFor(id); }, [this](string const & id) -> string { return m_storage.GetParentIdFor(id); },
bind(&Framework::GetMwmsByRect, this, _1, false /* rough */), bind(&Framework::GetMwmsByRect, this, _1, false /* rough */),
kMaxTrafficCacheSizeBytes, m_routingManager.RoutingSession()) kMaxTrafficCacheSizeBytes, m_routingManager.RoutingSession())
@@ -388,6 +389,8 @@ Framework::Framework(FrameworkParams const & params, bool loadMaps)
if (loadMaps) if (loadMaps)
LoadMapsSync(); LoadMapsSync();
m_trafficManager.Start();
} }
Framework::~Framework() Framework::~Framework()

View File

@@ -56,13 +56,13 @@ TrafficManager::CacheEntry::CacheEntry(time_point<steady_clock> const & requestT
, m_lastAvailability(traffic::TrafficInfo::Availability::Unknown) , m_lastAvailability(traffic::TrafficInfo::Availability::Unknown)
{} {}
TrafficManager::TrafficManager(DataSource & dataSource, TrafficManager::TrafficManager(DataSource & dataSource, CountryInfoGetterFn countryInfoGetter,
const CountryParentNameGetterFn &countryParentNameGetter, const CountryParentNameGetterFn &countryParentNameGetter,
GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes, GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes,
traffic::TrafficObserver & observer) traffic::TrafficObserver & observer)
: m_dataSource(dataSource) : m_dataSource(dataSource)
, m_countryInfoGetterFn(countryInfoGetter)
, m_countryParentNameGetterFn(countryParentNameGetter) , m_countryParentNameGetterFn(countryParentNameGetter)
, m_traffDecoder(dataSource, countryParentNameGetter, m_messageCache)
, m_getMwmsByRectFn(getMwmsByRectFn) , m_getMwmsByRectFn(getMwmsByRectFn)
, m_observer(observer) , m_observer(observer)
, m_currentDataVersion(0) , m_currentDataVersion(0)
@@ -129,6 +129,13 @@ void TrafficManager::SetEnabled(bool enabled)
m_observer.OnTrafficInfoClear(); m_observer.OnTrafficInfoClear();
} }
void TrafficManager::Start()
{
m_traffDecoder = make_unique<traffxml::DefaultTraffDecoder>(m_dataSource, m_countryInfoGetterFn,
m_countryParentNameGetterFn, m_messageCache);
m_isStarted = true;
}
void TrafficManager::Clear() void TrafficManager::Clear()
{ {
// TODO no longer needed // TODO no longer needed
@@ -211,7 +218,6 @@ void TrafficManager::UpdateActiveMwms(m2::RectD const & rect,
{ {
std::lock_guard<std::mutex> lock(m_mutex); std::lock_guard<std::mutex> lock(m_mutex);
m_isStarted = true;
m_activeMwmsChanged = true; m_activeMwmsChanged = true;
activeMwms.clear(); activeMwms.clear();
for (auto const & mwm : mwms) for (auto const & mwm : mwms)
@@ -462,7 +468,7 @@ void TrafficManager::DecodeFirstMessage()
} }
LOG(LINFO, (" ", message.m_id, ":", message)); LOG(LINFO, (" ", message.m_id, ":", message));
m_traffDecoder.DecodeMessage(message); m_traffDecoder->DecodeMessage(message);
// store message in cache // store message in cache
m_messageCache.insert_or_assign(message.m_id, message); m_messageCache.insert_or_assign(message.m_id, message);
// store message coloring in AllMwmColoring // store message coloring in AllMwmColoring

View File

@@ -9,6 +9,8 @@
#include "indexer/mwm_set.hpp" #include "indexer/mwm_set.hpp"
#include "storage/country_info_getter.hpp"
#include "traffxml/traff_decoder.hpp" #include "traffxml/traff_decoder.hpp"
#include "traffxml/traff_model.hpp" #include "traffxml/traff_model.hpp"
@@ -34,6 +36,7 @@
class TrafficManager final class TrafficManager final
{ {
public: public:
using CountryInfoGetterFn = std::function<storage::CountryInfoGetter const &()>;
using CountryParentNameGetterFn = std::function<std::string(std::string const &)>; using CountryParentNameGetterFn = std::function<std::string(std::string const &)>;
/** /**
@@ -75,6 +78,7 @@ public:
using GetMwmsByRectFn = std::function<std::vector<MwmSet::MwmId>(m2::RectD const &)>; using GetMwmsByRectFn = std::function<std::vector<MwmSet::MwmId>(m2::RectD const &)>;
TrafficManager(DataSource & dataSource, TrafficManager(DataSource & dataSource,
CountryInfoGetterFn countryInfoGetter,
CountryParentNameGetterFn const & countryParentNameGetter, CountryParentNameGetterFn const & countryParentNameGetter,
GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes, GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes,
traffic::TrafficObserver & observer); traffic::TrafficObserver & observer);
@@ -109,6 +113,26 @@ public:
*/ */
bool IsEnabled() const; bool IsEnabled() const;
/**
* @brief Starts the traffic manager.
*
* After creation, the traffic manager will not poll any sources or process any feeds until it is
* started. Feeds received through `Push()` will be added to the queue before the traffic manager
* is started, but will not be processed any further until the traffic manager is started.
*
* MWMs must be loaded before starting the traffic manager.
*
* @todo Currently, all MWMs must be loaded before calling `Start()`, as MWMs loaded after that
* will not get picked up. We need to extend `TrafficManager` to react to MWMs being added (and
* removed) note that this affects the data source, not the set of active MWMs.
*
* @todo Start is currently not integrated with state or pause/resume logic (all of which might
* not be fully implemented ATM). If the traffic manager is not started, no message processing
* (other than filling the queue and deduplication) will take place, regardless of state. Starting
* the traffic manager will not change the state it reports.
*/
void Start();
void UpdateViewport(ScreenBase const & screen); void UpdateViewport(ScreenBase const & screen);
void UpdateMyPosition(MyPosition const & myPosition); void UpdateMyPosition(MyPosition const & myPosition);
@@ -400,6 +424,7 @@ private:
} }
DataSource & m_dataSource; DataSource & m_dataSource;
CountryInfoGetterFn m_countryInfoGetterFn;
CountryParentNameGetterFn m_countryParentNameGetterFn; CountryParentNameGetterFn m_countryParentNameGetterFn;
GetMwmsByRectFn m_getMwmsByRectFn; GetMwmsByRectFn m_getMwmsByRectFn;
traffic::TrafficObserver & m_observer; traffic::TrafficObserver & m_observer;
@@ -535,7 +560,7 @@ private:
* *
* Used to decode TraFF locations into road segments on the map. * Used to decode TraFF locations into road segments on the map.
*/ */
traffxml::DefaultTraffDecoder m_traffDecoder; std::unique_ptr<traffxml::DefaultTraffDecoder> m_traffDecoder;
/** /**
* @brief Map between MWM IDs and their colorings. * @brief Map between MWM IDs and their colorings.

View File

@@ -276,6 +276,40 @@ IndexRouter::IndexRouter(VehicleType vehicleType, bool loadAltitudes,
CHECK(m_directionsEngine, ()); CHECK(m_directionsEngine, ());
} }
IndexRouter::IndexRouter(VehicleType vehicleType, bool loadAltitudes,
CountryParentNameGetterFn const & countryParentNameGetterFn,
TCountryFileFn const & countryFileFn, CountryRectFn const & countryRectFn,
shared_ptr<NumMwmIds> numMwmIds, unique_ptr<m4::Tree<NumMwmId>> numMwmTree,
DataSource & dataSource)
: m_vehicleType(vehicleType)
, m_loadAltitudes(loadAltitudes)
, m_name("astar-bidirectional-" + ToString(m_vehicleType))
, m_dataSource(dataSource, numMwmIds)
, m_vehicleModelFactory(CreateVehicleModelFactory(m_vehicleType, countryParentNameGetterFn))
, m_countryFileFn(countryFileFn)
, m_countryRectFn(countryRectFn)
, m_numMwmIds(std::move(numMwmIds))
, m_numMwmTree(std::move(numMwmTree))
, m_trafficStash(nullptr)
, m_roadGraph(m_dataSource,
vehicleType == VehicleType::Pedestrian || vehicleType == VehicleType::Transit
? IRoadGraph::Mode::IgnoreOnewayTag
: IRoadGraph::Mode::ObeyOnewayTag,
m_vehicleModelFactory)
, m_estimator(EdgeEstimator::Create(
m_vehicleType, CalcMaxSpeed(*m_numMwmIds, *m_vehicleModelFactory, m_vehicleType),
CalcOffroadSpeed(*m_vehicleModelFactory), m_trafficStash,
&dataSource, m_numMwmIds))
, m_directionsEngine(CreateDirectionsEngine(m_vehicleType, m_numMwmIds, m_dataSource))
, m_countryParentNameGetterFn(countryParentNameGetterFn)
{
CHECK(!m_name.empty(), ());
CHECK(m_numMwmIds, ());
CHECK(m_numMwmTree, ());
CHECK(m_estimator, ());
CHECK(m_directionsEngine, ());
}
unique_ptr<WorldGraph> IndexRouter::MakeSingleMwmWorldGraph() unique_ptr<WorldGraph> IndexRouter::MakeSingleMwmWorldGraph()
{ {
auto worldGraph = MakeWorldGraph(); auto worldGraph = MakeWorldGraph();

View File

@@ -65,6 +65,23 @@ public:
m2::PointD const m_direction; m2::PointD const m_direction;
}; };
/**
* @brief Creates a new `IndexRouter` instance.
*
* This is the constructor intended for normal routing. It requires a `TrafficCache` argument,
* from which it may create a traffic stash so the traffic situation can be considered for the
* route, depending on the vehicle type.
*
* @param vehicleType The vehichle type
* @param loadAltitudes Whether to load altitudes
* @param countryParentNameGetterFn Function which converts a country name into the name of its parent country)
* @param countryFileFn Function which converts a pointer to its country name
* @param countryRectFn Function which returns the rect for a country
* @param numMwmIds
* @param numMwmTree
* @param trafficCache The traffic cache (used only if `vehicleType` is `VehicleType::Car`)
* @param dataSource The MWM data source
*/
IndexRouter(VehicleType vehicleType, bool loadAltitudes, IndexRouter(VehicleType vehicleType, bool loadAltitudes,
CountryParentNameGetterFn const & countryParentNameGetterFn, CountryParentNameGetterFn const & countryParentNameGetterFn,
TCountryFileFn const & countryFileFn, CountryRectFn const & countryRectFn, TCountryFileFn const & countryFileFn, CountryRectFn const & countryRectFn,
@@ -89,6 +106,29 @@ public:
VehicleType GetVehicleType() const { return m_vehicleType; } VehicleType GetVehicleType() const { return m_vehicleType; }
protected:
/**
* @brief Creates a new `IndexRouter` instance.
*
* This constructor is intended for use by the TraFF decoder, not for normal routing. It lacks the
* `TrafficCache` argument and never creates a traffic stash. This creates a router instance which
* ignores the traffic situation, regardless of the vehicle type.
*
* @param vehicleType The vehichle type
* @param loadAltitudes Whether to load altitudes
* @param countryParentNameGetterFn Function which converts a country name into the name of its parent country)
* @param countryFileFn Function which converts a pointer to its country name
* @param countryRectFn Function which returns the rect for a country
* @param numMwmIds
* @param numMwmTree
* @param dataSource The MWM data source
*/
IndexRouter(VehicleType vehicleType, bool loadAltitudes,
CountryParentNameGetterFn const & countryParentNameGetterFn,
TCountryFileFn const & countryFileFn, CountryRectFn const & countryRectFn,
std::shared_ptr<NumMwmIds> numMwmIds, std::unique_ptr<m4::Tree<NumMwmId>> numMwmTree,
DataSource & dataSource);
private: private:
RouterResultCode CalculateSubrouteJointsMode(IndexGraphStarter & starter, RouterResultCode CalculateSubrouteJointsMode(IndexGraphStarter & starter,
RouterDelegate const & delegate, RouterDelegate const & delegate,

View File

@@ -6,10 +6,18 @@
#include "openlr/openlr_decoder.hpp" #include "openlr/openlr_decoder.hpp"
#include "openlr/openlr_model.hpp" #include "openlr/openlr_model.hpp"
#include "routing/async_router.hpp"
#include "routing/checkpoints.hpp"
#include "routing/maxspeeds.hpp" #include "routing/maxspeeds.hpp"
#include "routing/route.hpp"
#include "routing/router_delegate.hpp"
#include "routing_common/maxspeed_conversion.hpp" #include "routing_common/maxspeed_conversion.hpp"
#include "storage/routing_helpers.hpp"
#include "traffic/traffic_cache.hpp"
namespace traffxml namespace traffxml
{ {
// Number of worker threads for the OpenLR decoder // Number of worker threads for the OpenLR decoder
@@ -21,10 +29,15 @@ namespace traffxml
*/ */
auto constexpr kNumDecoderThreads = 1; auto constexpr kNumDecoderThreads = 1;
TraffDecoder::TraffDecoder(DataSource & dataSource, // Timeout for the router in seconds, used by RoutingTraffDecoder
// TODO set to a sensible value
auto constexpr kRouterTimeoutSec = 30;
TraffDecoder::TraffDecoder(DataSource & dataSource, CountryInfoGetterFn countryInfoGetter,
const CountryParentNameGetterFn & countryParentNameGetter, const CountryParentNameGetterFn & countryParentNameGetter,
std::map<std::string, TraffMessage> & messageCache) std::map<std::string, TraffMessage> & messageCache)
: m_dataSource(dataSource) : m_dataSource(dataSource)
, m_countryInfoGetterFn(countryInfoGetter)
, m_countryParentNameGetterFn(countryParentNameGetter) , m_countryParentNameGetterFn(countryParentNameGetter)
, m_messageCache(messageCache) , m_messageCache(messageCache)
{} {}
@@ -121,10 +134,10 @@ void TraffDecoder::DecodeMessage(traffxml::TraffMessage & message)
} }
} }
OpenLrV3TraffDecoder::OpenLrV3TraffDecoder(DataSource & dataSource, OpenLrV3TraffDecoder::OpenLrV3TraffDecoder(DataSource & dataSource, CountryInfoGetterFn countryInfoGetter,
const CountryParentNameGetterFn & countryParentNameGetter, const CountryParentNameGetterFn & countryParentNameGetter,
std::map<std::string, TraffMessage> & messageCache) std::map<std::string, TraffMessage> & messageCache)
: TraffDecoder(dataSource, countryParentNameGetter, messageCache) : TraffDecoder(dataSource, countryInfoGetter, countryParentNameGetter, messageCache)
, m_openLrDecoder(dataSource, countryParentNameGetter) , m_openLrDecoder(dataSource, countryParentNameGetter)
{} {}
@@ -336,4 +349,263 @@ void OpenLrV3TraffDecoder::DecodeLocation(traffxml::TraffMessage & message, traf
decoded[paths[i].m_path[j].GetFeatureId().m_mwmId][traffic::TrafficInfo::RoadSegmentId(fid, segment, direction)] = traffic::SpeedGroup::Unknown; decoded[paths[i].m_path[j].GetFeatureId().m_mwmId][traffic::TrafficInfo::RoadSegmentId(fid, segment, direction)] = traffic::SpeedGroup::Unknown;
} }
} }
RoutingTraffDecoder::DecoderRouter::DecoderRouter(CountryParentNameGetterFn const & countryParentNameGetterFn,
routing::TCountryFileFn const & countryFileFn,
routing::CountryRectFn const & countryRectFn,
std::shared_ptr<routing::NumMwmIds> numMwmIds,
std::unique_ptr<m4::Tree<routing::NumMwmId>> numMwmTree,
DataSource & dataSource)
: routing::IndexRouter(routing::VehicleType::Car /* VehicleType vehicleType */,
false /* bool loadAltitudes */,
countryParentNameGetterFn,
countryFileFn,
countryRectFn,
std::move(numMwmIds),
std::move(numMwmTree),
//std::nullopt /* std::optional<traffic::TrafficCache> const & trafficCache */,
dataSource)
/* TODO build our own edge estimator for TraFF decoding purposes
, m_estimator(EdgeEstimator::Create(
VehicleType::Car, CalcMaxSpeed(*m_numMwmIds, *m_vehicleModelFactory, m_vehicleType),
CalcOffroadSpeed(*m_vehicleModelFactory), m_trafficStash,
&dataSource, m_numMwmIds))
*/
//, m_directionsEngine(CreateDirectionsEngine(m_vehicleType, m_numMwmIds, m_dataSource)) // TODO we dont need directions, can we disable that?
{}
RoutingTraffDecoder::RoutingTraffDecoder(DataSource & dataSource, CountryInfoGetterFn countryInfoGetter,
const CountryParentNameGetterFn & countryParentNameGetter,
std::map<std::string, TraffMessage> & messageCache)
: TraffDecoder(dataSource, countryInfoGetter, countryParentNameGetter, messageCache)
{
InitRouter();
}
bool RoutingTraffDecoder::InitRouter()
{
if (m_router)
return true;
// code mostly from RoutingManager::SetRouterImpl(RouterType)
/*
* RoutingManager::SetRouterImpl(RouterType) calls m_delegate.RegisterCountryFilesOnRoute(numMwmIds).
* m_delegate is the framework, and the routine cycles through the countries in storage.
* As we dont have access to storage, we get our country files from the data source.
*/
std::vector<std::shared_ptr<MwmInfo>> mwmsInfo;
m_dataSource.GetMwmsInfo(mwmsInfo);
for (auto mwmInfo : mwmsInfo)
m_numMwmIds->RegisterFile(mwmInfo->GetLocalFile().GetCountryFile());
if (m_numMwmIds->IsEmpty())
return false;
auto const countryFileGetter = [this](m2::PointD const & p) -> std::string {
// TODO (@gorshenin): fix CountryInfoGetter to return CountryFile
// instances instead of plain strings.
return m_countryInfoGetterFn().GetRegionCountryId(p);
};
auto const getMwmRectByName = [this](std::string const & countryId) -> m2::RectD {
return m_countryInfoGetterFn().GetLimitRectForLeaf(countryId);
};
m_router =
make_unique<RoutingTraffDecoder::DecoderRouter>(m_countryParentNameGetterFn,
countryFileGetter, getMwmRectByName, m_numMwmIds,
routing::MakeNumMwmTree(*m_numMwmIds, m_countryInfoGetterFn()),
m_dataSource);
return true;
}
// Copied from AsyncRouter
// static
void RoutingTraffDecoder::LogCode(routing::RouterResultCode code, double const elapsedSec)
{
switch (code)
{
case routing::RouterResultCode::StartPointNotFound:
LOG(LWARNING, ("Can't find start or end node"));
break;
case routing::RouterResultCode::EndPointNotFound:
LOG(LWARNING, ("Can't find end point node"));
break;
case routing::RouterResultCode::PointsInDifferentMWM:
LOG(LWARNING, ("Points are in different MWMs"));
break;
case routing::RouterResultCode::RouteNotFound:
LOG(LWARNING, ("Route not found"));
break;
case routing::RouterResultCode::RouteFileNotExist:
LOG(LWARNING, ("There is no routing file"));
break;
case routing::RouterResultCode::NeedMoreMaps:
LOG(LINFO,
("Routing can find a better way with additional maps, elapsed seconds:", elapsedSec));
break;
case routing::RouterResultCode::Cancelled:
LOG(LINFO, ("Route calculation cancelled, elapsed seconds:", elapsedSec));
break;
case routing::RouterResultCode::NoError:
LOG(LINFO, ("Route found, elapsed seconds:", elapsedSec));
break;
case routing::RouterResultCode::NoCurrentPosition:
LOG(LINFO, ("No current position"));
break;
case routing::RouterResultCode::InconsistentMWMandRoute:
LOG(LINFO, ("Inconsistent mwm and route"));
break;
case routing::RouterResultCode::InternalError:
LOG(LINFO, ("Internal error"));
break;
case routing::RouterResultCode::FileTooOld:
LOG(LINFO, ("File too old"));
break;
case routing::RouterResultCode::IntermediatePointNotFound:
LOG(LWARNING, ("Can't find intermediate point node"));
break;
case routing::RouterResultCode::TransitRouteNotFoundNoNetwork:
LOG(LWARNING, ("No transit route is found because there's no transit network in the mwm of "
"the route point"));
break;
case routing::RouterResultCode::TransitRouteNotFoundTooLongPedestrian:
LOG(LWARNING, ("No transit route is found because pedestrian way is too long"));
break;
case routing::RouterResultCode::RouteNotFoundRedressRouteError:
LOG(LWARNING, ("Route not found because of a redress route error"));
break;
case routing::RouterResultCode::HasWarnings:
LOG(LINFO, ("Route has warnings, elapsed seconds:", elapsedSec));
break;
}
}
void RoutingTraffDecoder::DecodeLocationDirection(traffxml::TraffMessage & message,
traffxml::MultiMwmColoring & decoded, bool backwards)
{
bool adjustToPrevRoute = false; // calculate a fresh route, no adjustments to previous one
uint64_t routeId = 0; // used in callbacks to identify the route, we might not need it at all
std::string routerName; // set later
std::vector<m2::PointD> points;
if (message.m_location.value().m_from)
points.push_back(mercator::FromLatLon(message.m_location.value().m_from.value().m_coordinates));
if (message.m_location.value().m_at)
points.push_back(mercator::FromLatLon(message.m_location.value().m_at.value().m_coordinates));
else if (message.m_location.value().m_via)
points.push_back(mercator::FromLatLon(message.m_location.value().m_via.value().m_coordinates));
if (message.m_location.value().m_to)
points.push_back(mercator::FromLatLon(message.m_location.value().m_to.value().m_coordinates));
if (backwards)
std::reverse(points.begin(), points.end());
// m_notVia is ignored as OpenLR does not support this functionality.
CHECK_GREATER(points.size(), 1, ("At least two reference points must be given"));
/*
* startDirection is the direction of travel at start. Can be m2::PointD::Zero() to ignore
* direction, or PositionAccumulator::GetDirection(), which basically returns the difference
* between the last position and an earlier one (offset between two points from which the
* direction of travel can be inferred).
*
* For our purposes, points[1] - points[0] would be as close as we could get to a start direction.
* This would be accurate on very straight roads, less accurate on not-so-straight ones. However,
* even on a near-straight road, the standard router (with the default EdgeEstimator) seemed quite
* unimpressed by the direction and insisted on starting off on the carriageway closest to the
* start point and sending us on a huge detour, instead of taking the direct route on the opposite
* carriageway.
*/
m2::PointD startDirection = m2::PointD::Zero();
routing::Checkpoints checkpoints(std::move(points));
/*
* This code is mostly lifted from:
* - AsyncRouter::CalculateRoute(Checkpoints const &, m2::PointD const &, bool, ReadyCallbackOwnership const &,
* NeedMoreMapsCallback const &, RemoveRouteCallback const &, ProgressCallback, uint32_t)
* - AsyncRouter::CalculateRoute()
*/
// AsyncRouter::CalculateRoute(with args)
/*
* AsyncRouter::CalculateRoute() has a `DelegateProxy`, which is private. We just need the return
* value of GetDelegate(), which is a `routing::RouterDelegate`, so use that instead. We dont
* nedd any of the callbacks, therefore we dont set them.
*/
routing::RouterDelegate delegate;
delegate.SetTimeout(kRouterTimeoutSec);
// AsyncRouter::CalculateRoute()
if (!m_router && !InitRouter())
return;
routerName = m_router->GetName();
// TODO is that for following a track? If so, can we use that with just 23 reference points?
//router->SetGuides(std::move(m_guides));
//m_guides.clear();
auto route = std::make_shared<routing::Route>(m_router->GetName(), routeId);
routing::RouterResultCode code;
base::Timer timer;
double elapsedSec = 0.0;
try
{
LOG(LINFO, ("Calculating the route of direct length", checkpoints.GetSummaryLengthBetweenPointsMeters(),
"m. checkpoints:", checkpoints, "startDirection:", startDirection, "router name:", m_router->GetName()));
// Run basic request.
code = m_router->CalculateRoute(checkpoints, startDirection, adjustToPrevRoute,
delegate, *route);
m_router->SetGuides({});
elapsedSec = timer.ElapsedSeconds(); // routing time
LogCode(code, elapsedSec);
LOG(LINFO, ("ETA:", route->GetTotalTimeSec(), "sec."));
}
catch (RootException const & e)
{
code = routing::RouterResultCode::InternalError;
LOG(LERROR, ("Exception happened while calculating route:", e.Msg()));
return;
}
if (code == routing::RouterResultCode::NoError)
{
LOG(LINFO, ("Decoded route:"));
for (auto rsegment : route->GetRouteSegments())
{
routing::Segment segment = rsegment.GetSegment();
if (segment.GetMwmId() == routing::kFakeNumMwmId)
{
LOG(LINFO, (" Fake segment:", segment));
continue;
}
LOG(LINFO, (" segment:", segment));
auto const countryFile = m_numMwmIds->GetFile(segment.GetMwmId());
MwmSet::MwmId mwmId = m_dataSource.GetMwmIdByCountryFile(countryFile);
auto const fid = segment.GetFeatureId();
auto const sid = segment.GetSegmentIdx();
uint8_t direction = segment.IsForward() ?
traffic::TrafficInfo::RoadSegmentId::kForwardDirection :
traffic::TrafficInfo::RoadSegmentId::kReverseDirection;
decoded[mwmId][traffic::TrafficInfo::RoadSegmentId(fid, sid, direction)] = traffic::SpeedGroup::Unknown;
}
}
}
void RoutingTraffDecoder::DecodeLocation(traffxml::TraffMessage & message, traffxml::MultiMwmColoring & decoded)
{
ASSERT(message.m_location, ("Message has no location"));
decoded.clear();
int dirs = (message.m_location.value().m_directionality == Directionality::BothDirections) ? 2 : 1;
for (int dir = 0; dir < dirs; dir++)
DecodeLocationDirection(message, decoded, dir == 0 ? false : true /* backwards */);
}
} // namespace traffxml } // namespace traffxml

View File

@@ -7,6 +7,14 @@
#include "openlr/openlr_decoder.hpp" #include "openlr/openlr_decoder.hpp"
#include "openlr/openlr_model.hpp" #include "openlr/openlr_model.hpp"
#include "routing/index_router.hpp"
#include "routing/regions_decl.hpp"
#include "routing/router.hpp"
#include "routing_common/num_mwm_id.hpp"
#include "storage/country_info_getter.hpp"
namespace traffxml namespace traffxml
{ {
/** /**
@@ -15,9 +23,10 @@ namespace traffxml
class TraffDecoder class TraffDecoder
{ {
public: public:
using CountryInfoGetterFn = std::function<storage::CountryInfoGetter const &()>;
using CountryParentNameGetterFn = std::function<std::string(std::string const &)>; using CountryParentNameGetterFn = std::function<std::string(std::string const &)>;
TraffDecoder(DataSource & dataSource, TraffDecoder(DataSource & dataSource, CountryInfoGetterFn countryInfoGetter,
const CountryParentNameGetterFn & countryParentNameGetter, const CountryParentNameGetterFn & countryParentNameGetter,
std::map<std::string, traffxml::TraffMessage> & messageCache); std::map<std::string, traffxml::TraffMessage> & messageCache);
@@ -53,6 +62,7 @@ protected:
void ApplyTrafficImpact(traffxml::TrafficImpact & impact, traffxml::MultiMwmColoring & decoded); void ApplyTrafficImpact(traffxml::TrafficImpact & impact, traffxml::MultiMwmColoring & decoded);
DataSource & m_dataSource; DataSource & m_dataSource;
CountryInfoGetterFn m_countryInfoGetterFn;
CountryParentNameGetterFn m_countryParentNameGetterFn; CountryParentNameGetterFn m_countryParentNameGetterFn;
/** /**
@@ -71,7 +81,7 @@ private:
class OpenLrV3TraffDecoder : public TraffDecoder class OpenLrV3TraffDecoder : public TraffDecoder
{ {
public: public:
OpenLrV3TraffDecoder(DataSource & dataSource, OpenLrV3TraffDecoder(DataSource & dataSource, CountryInfoGetterFn countryInfoGetter,
const CountryParentNameGetterFn & countryParentNameGetter, const CountryParentNameGetterFn & countryParentNameGetter,
std::map<std::string, traffxml::TraffMessage> & messageCache); std::map<std::string, traffxml::TraffMessage> & messageCache);
@@ -151,6 +161,80 @@ private:
openlr::OpenLRDecoder m_openLrDecoder; openlr::OpenLRDecoder m_openLrDecoder;
}; };
/**
* @brief A `TraffDecoder` implementation which internally uses the routing engine.
*/
class RoutingTraffDecoder : public TraffDecoder
{
public:
class DecoderRouter : public routing::IndexRouter
{
public:
/**
* @brief Creates a new `DecoderRouter` instance.
*
* @param countryParentNameGetterFn Function which converts a country name into the name of its parent country)
* @param countryFileFn Function which converts a pointer to its country name
* @param countryRectFn Function which returns the rect for a country
* @param numMwmIds
* @param numMwmTree
* @param trafficCache Tre traffic cache (used only if `vehicleType` is `VehicleType::Car`)
* @param dataSource The MWM data source
*/
DecoderRouter(CountryParentNameGetterFn const & countryParentNameGetterFn,
routing::TCountryFileFn const & countryFileFn,
routing::CountryRectFn const & countryRectFn,
std::shared_ptr<routing::NumMwmIds> numMwmIds,
std::unique_ptr<m4::Tree<routing::NumMwmId>> numMwmTree,
DataSource & dataSource);
protected:
private:
};
RoutingTraffDecoder(DataSource & dataSource, CountryInfoGetterFn countryInfoGetter,
const CountryParentNameGetterFn & countryParentNameGetter,
std::map<std::string, traffxml::TraffMessage> & messageCache);
protected:
/**
* @brief Initializes the router.
*
* This is usually done in the constructor but fails if no maps are loaded (attempting to
* construct a router without maps results in a crash, hence we check for maps and exit with an
* error if we have none). It can be repeated any time.
*
* Attempting to initialize a router which has already been succesfully initialized is a no-op. It
* will be reported as success.
*
* @return true if successful, false if not.
*/
bool InitRouter();
/**
* @brief Decodes one direction of a TraFF location.
*
* @param message The message to decode.
* @param decoded Receives the decoded segments. The speed group will be `Unknown`.
* @param backwards If true, decode the backward direction, else the forward direction.
*/
void DecodeLocationDirection(traffxml::TraffMessage & message,
traffxml::MultiMwmColoring & decoded, bool backwards);
/**
* @brief Decodes a TraFF location.
*
* @param message The message to decode.
* @param decoded Receives the decoded segments. The speed group will be `Unknown`.
*/
void DecodeLocation(traffxml::TraffMessage & message, traffxml::MultiMwmColoring & decoded);
private:
static void LogCode(routing::RouterResultCode code, double const elapsedSec);
std::shared_ptr<routing::NumMwmIds> m_numMwmIds = std::make_shared<routing::NumMwmIds>();
std::unique_ptr<routing::IRouter> m_router;
};
/** /**
* @brief The default TraFF decoder implementation, recommended for production use. * @brief The default TraFF decoder implementation, recommended for production use.
*/ */