diff --git a/libs/traffxml/traff_decoder.cpp b/libs/traffxml/traff_decoder.cpp index d3426ed3a..e1b82e330 100644 --- a/libs/traffxml/traff_decoder.cpp +++ b/libs/traffxml/traff_decoder.cpp @@ -958,7 +958,7 @@ void RoutingTraffDecoder::AddDecodedSegment(traffxml::MultiMwmColoring & decoded } void RoutingTraffDecoder::TruncateRoute(std::vector & rsegments, - routing::Checkpoints const & checkpoints, bool toJunctions) + routing::Checkpoints const & checkpoints, bool backwards) { double const endWeight = rsegments.back().GetTimeFromBeginningSec(); @@ -981,8 +981,10 @@ void RoutingTraffDecoder::TruncateRoute(std::vector & rse // Cost saved by omitting the last `end` segments. double endSaving = 0; - TruncateStart(rsegments, checkpoints, start, startSaving, toJunctions); - TruncateEnd(rsegments, checkpoints, end, endSaving, endWeight, toJunctions); + TruncateStart(rsegments, checkpoints, start, startSaving, + backwards ? m_endJunctions : m_startJunctions); + TruncateEnd(rsegments, checkpoints, end, endSaving, endWeight, + backwards ? m_startJunctions : m_endJunctions); /* * If start <= end, we can truncate both ends at the same time. @@ -1000,7 +1002,8 @@ void RoutingTraffDecoder::TruncateRoute(std::vector & rse rsegments.erase(rsegments.begin(), rsegments.begin() + start); end = rsegments.size() - 1; endSaving = 0; - TruncateEnd(rsegments, checkpoints, end, endSaving, endWeight, toJunctions); + TruncateEnd(rsegments, checkpoints, end, endSaving, endWeight, + backwards ? m_startJunctions : m_endJunctions); rsegments.erase(rsegments.begin() + end + 1, rsegments.end()); } else @@ -1009,7 +1012,8 @@ void RoutingTraffDecoder::TruncateRoute(std::vector & rse rsegments.erase(rsegments.begin() + end + 1, rsegments.end()); start = 0; startSaving = 0; - TruncateStart(rsegments, checkpoints, start, startSaving, toJunctions); + TruncateStart(rsegments, checkpoints, start, startSaving, + backwards ? m_endJunctions : m_startJunctions); rsegments.erase(rsegments.begin(), rsegments.begin() + start); } } @@ -1108,9 +1112,7 @@ void RoutingTraffDecoder::DecodeLocationDirection(traffxml::TraffMessage & messa { std::vector rsegments(route->GetRouteSegments()); - TruncateRoute(rsegments, checkpoints, - message.m_location.value().m_fuzziness - && (message.m_location.value().m_fuzziness.value() == traffxml::Fuzziness::LowRes)); + TruncateRoute(rsegments, checkpoints, backwards); /* * `m_onRoundabout` is set only for the first segment after the junction. In order to identify @@ -1489,13 +1491,38 @@ std::vector ParseRef(std::string const & ref) void TruncateStart(std::vector & rsegments, routing::Checkpoints const & checkpoints, - size_t & start, double & startSaving, bool toJunction) + size_t & start, double & startSaving, + std::map const & junctions) { + if (rsegments.empty()) + return; + for (size_t i = 0; i < rsegments.size(); i++) { - double newStartSaving = rsegments[i].GetTimeFromBeginningSec() - - (mercator::DistanceOnEarth(checkpoints.GetStart(), rsegments[i].GetJunction().GetPoint()) - * kOffroadPenalty); + double newStartSaving = 0; + /* + * Examine end point of segment: for a junction, take weight from table; else calculate it as + * direct distance multiplied with offroad penalty; calculate saving based on that. + */ + auto it = junctions.find(rsegments[i].GetJunction().GetPoint()); + if (it != junctions.end()) + newStartSaving = rsegments[i].GetTimeFromBeginningSec() - it->second; + else + { + bool matched = false; + // TODO this is likely an inefficient way to return near-matches + for (auto & [point, weight] : junctions) + if (rsegments[i].GetJunction().GetPoint().EqualDxDy(point, kMwmPointAccuracy)) + { + newStartSaving = rsegments[i].GetTimeFromBeginningSec() - weight; + matched = true; + break; + } + if (!matched) + newStartSaving = rsegments[i].GetTimeFromBeginningSec() + - (mercator::DistanceOnEarth(checkpoints.GetStart(), rsegments[i].GetJunction().GetPoint()) + * kOffroadPenalty); + } if (newStartSaving > startSaving) { start = i + 1; // add 1 because we are ditching this segment and keeping the next one @@ -1506,13 +1533,35 @@ void TruncateStart(std::vector & rsegments, void TruncateEnd(std::vector & rsegments, routing::Checkpoints const & checkpoints, - size_t & end, double & endSaving, double const endWeight, bool toJunction) + size_t & end, double & endSaving, double const endWeight, + std::map const & junctions) { for (size_t i = 0; i < rsegments.size(); i++) { - double newEndSaving = endWeight - rsegments[i].GetTimeFromBeginningSec() - - (mercator::DistanceOnEarth(rsegments[i].GetJunction().GetPoint(), checkpoints.GetFinish()) - * kOffroadPenalty); + double newEndSaving = 0; + /* + * Examine end point of segment: for a junction, take weight from table; else calculate it as + * direct distance multiplied with offroad penalty; calculate saving based on that. + */ + auto it = junctions.find(rsegments[i].GetJunction().GetPoint()); + if (it != junctions.end()) + newEndSaving = endWeight - rsegments[i].GetTimeFromBeginningSec() - it->second; + else + { + bool matched = false; + // TODO this is likely an inefficient way to return near-matches + for (auto & [point, weight] : junctions) + if (rsegments[i].GetJunction().GetPoint().EqualDxDy(point, kMwmPointAccuracy)) + { + newEndSaving = endWeight - rsegments[i].GetTimeFromBeginningSec() - weight; + matched = true; + break; + } + if (!matched) + newEndSaving = endWeight - rsegments[i].GetTimeFromBeginningSec() + - (mercator::DistanceOnEarth(rsegments[i].GetJunction().GetPoint(), checkpoints.GetFinish()) + * kOffroadPenalty); + } if (newEndSaving > endSaving) { end = i; diff --git a/libs/traffxml/traff_decoder.hpp b/libs/traffxml/traff_decoder.hpp index 086e3b879..9e5869aa6 100644 --- a/libs/traffxml/traff_decoder.hpp +++ b/libs/traffxml/traff_decoder.hpp @@ -471,10 +471,10 @@ protected: * * @param rsegments The segments of the route * @param checkpoints The reference points (at least two) - * @param toJunctions Whether the truncated route should begin and end at a junction + * @param backwards True when decoding the backward direction, false when decodign the forward direction. */ void TruncateRoute(std::vector & rsegments, - routing::Checkpoints const & checkpoints, bool toJunctions); + routing::Checkpoints const & checkpoints, bool backwards); private: static void LogCode(routing::RouterResultCode code, double const elapsedSec); @@ -596,11 +596,12 @@ std::vector ParseRef(std::string const & ref); * @param checkpoints The reference points (at least two) * @param start Index of the first segment to keep * @param startSaving Cost saved by truncating - * @param toJunction Whether the truncated route should start at a junction + * @param junctions Junctions with the weight of their leap segment */ void TruncateStart(std::vector & rsegments, routing::Checkpoints const & checkpoints, - size_t & start, double & startSaving, bool toJunction); + size_t & start, double & startSaving, + std::map const & junctions); /** * @brief Calculates the segments to truncate at the start of the route. @@ -615,9 +616,10 @@ void TruncateStart(std::vector & rsegments, * @param checkpoints The reference points (at least two) * @param end Index of the last segment to keep * @param endSaving Cost saved by truncating - * @param toJunction Whether the truncated route should end at a junction + * @param junctions Junctions with the weight of their leap segment */ void TruncateEnd(std::vector & rsegments, routing::Checkpoints const & checkpoints, - size_t & end, double & endSaving, double const endWeight, bool ToJunction); + size_t & end, double & endSaving, double const endWeight, + std::map const & junctions); } // namespace traffxml