mirror of
https://codeberg.org/comaps/comaps
synced 2025-12-21 05:43:37 +00:00
[traffic] Refactor TraFF decoder into separate class
Signed-off-by: mvglasow <michael -at- vonglasow.com>
This commit is contained in:
@@ -1,10 +1,7 @@
|
||||
#include "map/traffic_manager.hpp"
|
||||
|
||||
#include "routing/maxspeeds.hpp"
|
||||
#include "routing/routing_helpers.hpp"
|
||||
|
||||
#include "routing_common/maxspeed_conversion.hpp"
|
||||
|
||||
#include "drape_frontend/drape_engine.hpp"
|
||||
#include "drape_frontend/visual_params.hpp"
|
||||
|
||||
@@ -13,10 +10,6 @@
|
||||
|
||||
#include "geometry/mercator.hpp"
|
||||
|
||||
#include "openlr/decoded_path.hpp"
|
||||
#include "openlr/openlr_decoder.hpp"
|
||||
#include "openlr/openlr_model.hpp"
|
||||
|
||||
#include "platform/platform.hpp"
|
||||
|
||||
#include "traffxml/traff_model_xml.hpp"
|
||||
@@ -43,15 +36,6 @@ auto constexpr kDrapeUpdateInterval = seconds(10);
|
||||
* Interval at which the traffic observer gets traffic updates while messages are being processed.
|
||||
*/
|
||||
auto constexpr kObserverUpdateInterval = minutes(1);
|
||||
|
||||
// Number of worker threads for the OpenLR decoder
|
||||
/*
|
||||
* TODO how to determine the best number of worker threads?
|
||||
* One per direction? Does not seem to help with bidirectional locations (two reference points).
|
||||
* One per segment (from–via/from–at, via–to/at–to)? Not yet tested.
|
||||
* Otherwise there is little to be gained, as we decode messages one at a time.
|
||||
*/
|
||||
auto constexpr kNumDecoderThreads = 1;
|
||||
} // namespace
|
||||
|
||||
TrafficManager::CacheEntry::CacheEntry()
|
||||
@@ -78,7 +62,7 @@ TrafficManager::TrafficManager(DataSource & dataSource,
|
||||
traffic::TrafficObserver & observer)
|
||||
: m_dataSource(dataSource)
|
||||
, m_countryParentNameGetterFn(countryParentNameGetter)
|
||||
, m_openLrDecoder(m_dataSource, countryParentNameGetter)
|
||||
, m_traffDecoder(dataSource, countryParentNameGetter, m_messageCache)
|
||||
, m_getMwmsByRectFn(getMwmsByRectFn)
|
||||
, m_observer(observer)
|
||||
, m_currentDataVersion(0)
|
||||
@@ -439,146 +423,6 @@ void TrafficManager::ConsolidateFeedQueue()
|
||||
++it;
|
||||
}
|
||||
|
||||
void TrafficManager::DecodeLocation(traffxml::TraffMessage & message, traffxml::MultiMwmColoring & decoded)
|
||||
{
|
||||
decoded.clear();
|
||||
|
||||
// Convert the location to a format understood by the OpenLR decoder.
|
||||
std::vector<openlr::LinearSegment> segments
|
||||
= message.m_location.value().ToOpenLrSegments(message.m_id);
|
||||
|
||||
for (auto segment : segments)
|
||||
{
|
||||
LOG(LINFO, (" Segment:", segment.m_segmentId));
|
||||
for (int i = 0; i < segment.m_locationReference.m_points.size(); i++)
|
||||
{
|
||||
LOG(LINFO, (" ", i, ":", segment.m_locationReference.m_points[i].m_latLon));
|
||||
if (i < segment.m_locationReference.m_points.size() - 1)
|
||||
{
|
||||
LOG(LINFO, (" FRC:", segment.m_locationReference.m_points[i].m_functionalRoadClass));
|
||||
LOG(LINFO, (" DNP:", segment.m_locationReference.m_points[i].m_distanceToNextPoint));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Decode the location into a path on the map.
|
||||
// One path per segment
|
||||
std::vector<openlr::DecodedPath> paths(segments.size());
|
||||
m_openLrDecoder.DecodeV3(segments, kNumDecoderThreads, paths);
|
||||
|
||||
for (size_t i = 0; i < paths.size(); i++)
|
||||
for (size_t j = 0; j < paths[i].m_path.size(); j++)
|
||||
{
|
||||
auto fid = paths[i].m_path[j].GetFeatureId().m_index;
|
||||
auto segment = paths[i].m_path[j].GetSegId();
|
||||
uint8_t direction = paths[i].m_path[j].IsForward() ?
|
||||
traffic::TrafficInfo::RoadSegmentId::kForwardDirection :
|
||||
traffic::TrafficInfo::RoadSegmentId::kReverseDirection;
|
||||
decoded[paths[i].m_path[j].GetFeatureId().m_mwmId][traffic::TrafficInfo::RoadSegmentId(fid, segment, direction)] = traffic::SpeedGroup::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
void TrafficManager::ApplyTrafficImpact(traffxml::TrafficImpact & impact, traffxml::MultiMwmColoring & decoded)
|
||||
{
|
||||
for (auto dit = decoded.begin(); dit != decoded.end(); dit++)
|
||||
for (auto cit = dit->second.begin(); cit != dit->second.end(); cit++)
|
||||
{
|
||||
/*
|
||||
* Consolidate TrafficImpact into a single SpeedGroup per segment.
|
||||
* Exception: if TrafficImpact already has SpeedGrup::TempBlock, no need to evaluate
|
||||
* the rest.
|
||||
*/
|
||||
traffic::SpeedGroup sg = impact.m_speedGroup;
|
||||
/*
|
||||
* TODO also process m_delayMins if greater than zero.
|
||||
* This would require a separate pass over all edges, calculating length,
|
||||
* total (normal) travel time (length / maxspeed), then a speed group based on
|
||||
* (normal_travel_time / delayed_travel_time) – which is the same as the ratio between
|
||||
* reduced and normal speed. That would give us a third potential speed group.
|
||||
*/
|
||||
if ((sg != traffic::SpeedGroup::TempBlock) && (impact.m_maxspeed != traffxml::kMaxspeedNone))
|
||||
{
|
||||
auto const handle = m_dataSource.GetMwmHandleById(dit->first);
|
||||
auto const speeds = routing::LoadMaxspeeds(handle);
|
||||
if (speeds)
|
||||
{
|
||||
traffic::SpeedGroup fromMaxspeed = traffic::SpeedGroup::Unknown;
|
||||
auto const speed = speeds->GetMaxspeed(cit->first.GetFid());
|
||||
auto const speedKmPH = speed.GetSpeedKmPH(cit->first.GetDir() == traffic::TrafficInfo::RoadSegmentId::kForwardDirection);
|
||||
if (speedKmPH != routing::kInvalidSpeed)
|
||||
{
|
||||
fromMaxspeed = traffic::GetSpeedGroupByPercentage(impact.m_maxspeed * 100.0f / speedKmPH);
|
||||
if ((sg == traffic::SpeedGroup::Unknown) || (fromMaxspeed < sg))
|
||||
sg = fromMaxspeed;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* TODO fully process TrafficImpact (unless m_speedGroup is TempBlock, which overrules everything else)
|
||||
* If no maxspeed or delay is set, just give out speed groups.
|
||||
* Else, examine segments, length, normal travel time, travel time considering impact, and
|
||||
* determine the closest matching speed group.
|
||||
*/
|
||||
}
|
||||
// TODO process all TrafficImpact fields and determine the speed group based on that
|
||||
cit->second = sg;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO the OpenLR decoder is designed to handle multiple segments (i.e. locations).
|
||||
* Decoding message by message kind of defeats the purpose.
|
||||
* But after decoding the location, we need to examine the map features we got in order to
|
||||
* determine the speed groups, thus we may need to decode one by one (TBD).
|
||||
* If we batch-decode segments, we need to fix the [partner] segment IDs in the segment and path
|
||||
* structures to accept a TraFF message ID (string) rather than an integer, or derive
|
||||
* [partner] segment IDs from TraFF message IDs.
|
||||
*/
|
||||
void TrafficManager::DecodeMessage(traffxml::TraffMessage & message)
|
||||
{
|
||||
if (!message.m_location)
|
||||
return;
|
||||
// Decode events into consolidated traffic impact
|
||||
std::optional<traffxml::TrafficImpact> impact = message.GetTrafficImpact();
|
||||
|
||||
LOG(LINFO, (" Impact: ", impact));
|
||||
|
||||
// Skip further processing if there is no impact
|
||||
if (!impact)
|
||||
return;
|
||||
|
||||
traffxml::MultiMwmColoring decoded;
|
||||
|
||||
auto it = m_messageCache.find(message.m_id);
|
||||
if ((it != m_messageCache.end())
|
||||
&& !it->second.m_decoded.empty()
|
||||
&& (it->second.m_location == message.m_location))
|
||||
{
|
||||
// cache already has a message with reusable location
|
||||
|
||||
LOG(LINFO, (" Location for message", message.m_id, "can be reused from cache"));
|
||||
|
||||
std::optional<traffxml::TrafficImpact> cachedImpact = it->second.GetTrafficImpact();
|
||||
if (cachedImpact.has_value() && cachedImpact.value() == impact.value())
|
||||
{
|
||||
LOG(LINFO, (" Impact for message", message.m_id, "unchanged, reusing cached coloring"));
|
||||
|
||||
// same impact, m_decoded can be reused altogether
|
||||
message.m_decoded = it->second.m_decoded;
|
||||
return;
|
||||
}
|
||||
else
|
||||
decoded = it->second.m_decoded;
|
||||
}
|
||||
else
|
||||
DecodeLocation(message, decoded);
|
||||
|
||||
if (impact)
|
||||
{
|
||||
ApplyTrafficImpact(impact.value(), decoded);
|
||||
std::swap(message.m_decoded, decoded);
|
||||
}
|
||||
}
|
||||
|
||||
void TrafficManager::DecodeFirstMessage()
|
||||
{
|
||||
traffxml::TraffMessage message;
|
||||
@@ -618,7 +462,7 @@ void TrafficManager::DecodeFirstMessage()
|
||||
}
|
||||
|
||||
LOG(LINFO, (" ", message.m_id, ":", message));
|
||||
DecodeMessage(message);
|
||||
m_traffDecoder.DecodeMessage(message);
|
||||
// store message in cache
|
||||
m_messageCache.insert_or_assign(message.m_id, message);
|
||||
// store message coloring in AllMwmColoring
|
||||
|
||||
Reference in New Issue
Block a user