Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormpimenov <mpimenov@users.noreply.github.com>2016-12-05 18:45:48 +0300
committerGitHub <noreply@github.com>2016-12-05 18:45:48 +0300
commit92ce040996a35c6bccb385f7c77022881e794c7c (patch)
tree87b6cae5e712a64902cf048056ef2de3da2170b4
parenteeea9b4d02ebec838ab23ae12d17dde3003efc66 (diff)
parent56a37cd83ac1a5f2f262e17483edfe3a86317772 (diff)
Merge pull request #4840 from bykoianko/master-applying-jambeta-513
[routing] Applying traffic jam on index graph
-rw-r--r--android/jni/Android.mk2
-rw-r--r--map/framework.cpp6
-rw-r--r--map/map_tests/map_tests.pro2
-rw-r--r--map/traffic_manager.cpp22
-rw-r--r--map/traffic_manager.hpp8
-rw-r--r--routing/edge_estimator.cpp61
-rw-r--r--routing/edge_estimator.hpp26
-rw-r--r--routing/index_graph.cpp5
-rw-r--r--routing/index_graph_starter.cpp8
-rw-r--r--routing/routing_integration_tests/routing_test_tools.cpp15
-rw-r--r--routing/routing_integration_tests/routing_test_tools.hpp194
-rw-r--r--routing/routing_session.cpp66
-rw-r--r--routing/routing_session.hpp16
-rw-r--r--routing/routing_tests/applying_traffic_test.cpp224
-rw-r--r--routing/routing_tests/index_graph_test.cpp70
-rw-r--r--routing/routing_tests/index_graph_tools.cpp70
-rw-r--r--routing/routing_tests/index_graph_tools.hpp51
-rw-r--r--routing/routing_tests/routing_tests.pro3
-rw-r--r--routing/single_mwm_router.cpp11
-rw-r--r--routing/single_mwm_router.hpp4
-rw-r--r--traffic/traffic.pro2
-rw-r--r--traffic/traffic_cache.cpp23
-rw-r--r--traffic/traffic_cache.hpp27
-rw-r--r--traffic/traffic_info.cpp8
-rw-r--r--traffic/traffic_info.hpp13
25 files changed, 721 insertions, 216 deletions
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index f7fa5083be..f51beee1b2 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -25,7 +25,7 @@ define add_prebuild_static_lib
include $(PREBUILT_STATIC_LIBRARY)
endef
-prebuild_static_libs := map tracking traffic drape_frontend routing search storage indexer drape platform editor partners_api geometry coding base opening_hours
+prebuild_static_libs := map tracking routing traffic drape_frontend search storage indexer drape platform editor partners_api geometry coding base opening_hours
prebuild_static_libs += pugixml oauthcpp expat freetype fribidi minizip jansson protobuf osrm stats_client succinct
$(foreach item,$(prebuild_static_libs),$(eval $(call add_prebuild_static_lib,$(item))))
diff --git a/map/framework.cpp b/map/framework.cpp
index 9fcc720e9c..4d9a928ef9 100644
--- a/map/framework.cpp
+++ b/map/framework.cpp
@@ -356,7 +356,9 @@ Framework::Framework()
, m_isRenderingEnabled(true)
, m_trackingReporter(platform::CreateSocket(), TRACKING_REALTIME_HOST, TRACKING_REALTIME_PORT,
tracking::Reporter::kPushDelayMs)
- , m_trafficManager(bind(&Framework::GetMwmsByRect, this, _1), kMaxTrafficCacheSizeBytes)
+ , m_trafficManager(bind(&Framework::GetMwmsByRect, this, _1), kMaxTrafficCacheSizeBytes,
+ // Note. |m_routingSession| should be declared before |m_trafficManager|.
+ m_routingSession)
, m_displacementModeManager([this](bool show) {
int const mode = show ? dp::displacement::kHotelMode : dp::displacement::kDefaultMode;
CallDrapeFunction(bind(&df::DrapeEngine::SetDisplacementMode, _1, mode));
@@ -2493,7 +2495,7 @@ void Framework::SetRouterImpl(RouterType type)
router.reset(
new CarRouter(m_model.GetIndex(), countryFileGetter,
- SingleMwmRouter::CreateCarRouter(m_model.GetIndex())));
+ SingleMwmRouter::CreateCarRouter(m_model.GetIndex(), m_routingSession)));
fetcher.reset(new OnlineAbsentCountriesFetcher(countryFileGetter, localFileChecker));
m_routingSession.SetRoutingSettings(routing::GetCarRoutingSettings());
}
diff --git a/map/map_tests/map_tests.pro b/map/map_tests/map_tests.pro
index 78b428a9d6..59a471514e 100644
--- a/map/map_tests/map_tests.pro
+++ b/map/map_tests/map_tests.pro
@@ -6,7 +6,7 @@ CONFIG -= app_bundle
TEMPLATE = app
ROOT_DIR = ../..
-DEPENDENCIES = map traffic traffic drape_frontend routing search storage tracking drape indexer partners_api platform editor geometry coding base \
+DEPENDENCIES = map drape_frontend routing traffic search storage tracking drape indexer partners_api platform editor geometry coding base \
freetype fribidi expat protobuf jansson osrm stats_client minizip succinct pugixml stats_client
DEPENDENCIES *= opening_hours
diff --git a/map/traffic_manager.cpp b/map/traffic_manager.cpp
index be2c9b4e3e..6d3110557f 100644
--- a/map/traffic_manager.cpp
+++ b/map/traffic_manager.cpp
@@ -37,8 +37,10 @@ TrafficManager::CacheEntry::CacheEntry(time_point<steady_clock> const & requestT
, m_lastAvailability(traffic::TrafficInfo::Availability::Unknown)
{}
-TrafficManager::TrafficManager(GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes)
+TrafficManager::TrafficManager(GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes,
+ traffic::TrafficObserver & observer)
: m_getMwmsByRectFn(getMwmsByRectFn)
+ , m_observer(observer)
, m_currentDataVersion(0)
, m_state(TrafficState::Disabled)
, m_maxCacheSizeBytes(maxCacheSizeBytes)
@@ -92,6 +94,8 @@ void TrafficManager::SetEnabled(bool enabled)
if (m_currentPosition.second)
UpdateMyPosition(m_currentPosition.first);
}
+
+ m_observer.OnTrafficEnabled(enabled);
}
void TrafficManager::Clear()
@@ -183,12 +187,12 @@ void TrafficManager::ThreadRoutine()
if (info.ReceiveTrafficData())
{
- OnTrafficDataResponse(info);
+ OnTrafficDataResponse(move(info));
}
else
{
LOG(LWARNING, ("Traffic request failed. Mwm =", mwm));
- OnTrafficRequestFailed(info);
+ OnTrafficRequestFailed(move(info));
}
}
mwms.clear();
@@ -267,7 +271,7 @@ void TrafficManager::RequestTrafficData(MwmSet::MwmId const & mwmId)
m_condition.notify_one();
}
-void TrafficManager::OnTrafficRequestFailed(traffic::TrafficInfo const & info)
+void TrafficManager::OnTrafficRequestFailed(traffic::TrafficInfo && info)
{
lock_guard<mutex> lock(m_mutex);
@@ -300,7 +304,7 @@ void TrafficManager::OnTrafficRequestFailed(traffic::TrafficInfo const & info)
UpdateState();
}
-void TrafficManager::OnTrafficDataResponse(traffic::TrafficInfo const & info)
+void TrafficManager::OnTrafficDataResponse(traffic::TrafficInfo && info)
{
lock_guard<mutex> lock(m_mutex);
@@ -315,17 +319,21 @@ void TrafficManager::OnTrafficDataResponse(traffic::TrafficInfo const & info)
// Update cache.
size_t constexpr kElementSize = sizeof(traffic::TrafficInfo::RoadSegmentId) + sizeof(traffic::SpeedGroup);
+
size_t const dataSize = info.GetColoring().size() * kElementSize;
m_currentCacheSizeBytes += (dataSize - it->second.m_dataSize);
it->second.m_dataSize = dataSize;
CheckCacheSize();
- // Update traffic colors.
+ // Update traffic colors for drape.
df::TrafficSegmentsColoring coloring;
coloring[info.GetMwmId()] = info.GetColoring();
m_drapeEngine->UpdateTraffic(coloring);
UpdateState();
+
+ // Update traffic colors for routing.
+ m_observer.OnTrafficInfoAdded(move(info));
}
void TrafficManager::CheckCacheSize()
@@ -344,8 +352,10 @@ void TrafficManager::CheckCacheSize()
auto const it = m_mwmCache.find(mwmId);
if (it->second.m_isLoaded)
{
+ ASSERT_GREATER_OR_EQUAL(m_currentCacheSizeBytes, it->second.m_dataSize, ());
m_currentCacheSizeBytes -= it->second.m_dataSize;
m_drapeEngine->ClearTrafficCache(mwmId);
+ m_observer.OnTrafficInfoRemoved(mwmId);
}
m_mwmCache.erase(it);
++itSeen;
diff --git a/map/traffic_manager.hpp b/map/traffic_manager.hpp
index b14cac579a..d2f208a356 100644
--- a/map/traffic_manager.hpp
+++ b/map/traffic_manager.hpp
@@ -57,7 +57,8 @@ public:
using TrafficStateChangedFn = function<void(TrafficState)>;
using GetMwmsByRectFn = function<vector<MwmSet::MwmId>(m2::RectD const &)>;
- TrafficManager(GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes);
+ TrafficManager(GetMwmsByRectFn const & getMwmsByRectFn, size_t maxCacheSizeBytes,
+ traffic::TrafficObserver & observer);
~TrafficManager();
void SetStateListener(TrafficStateChangedFn const & onStateChangedFn);
@@ -76,8 +77,8 @@ private:
void ThreadRoutine();
bool WaitForRequest(vector<MwmSet::MwmId> & mwms);
- void OnTrafficDataResponse(traffic::TrafficInfo const & info);
- void OnTrafficRequestFailed(traffic::TrafficInfo const & info);
+ void OnTrafficDataResponse(traffic::TrafficInfo && info);
+ void OnTrafficRequestFailed(traffic::TrafficInfo && info);
private:
// This is a group of methods that haven't their own synchronization inside.
@@ -94,6 +95,7 @@ private:
bool IsEnabled() const;
GetMwmsByRectFn m_getMwmsByRectFn;
+ traffic::TrafficObserver & m_observer;
ref_ptr<df::DrapeEngine> m_drapeEngine;
atomic<int64_t> m_currentDataVersion;
diff --git a/routing/edge_estimator.cpp b/routing/edge_estimator.cpp
index 52cb10905a..86c27e8415 100644
--- a/routing/edge_estimator.cpp
+++ b/routing/edge_estimator.cpp
@@ -1,7 +1,22 @@
#include "routing/edge_estimator.hpp"
+#include "traffic/traffic_info.hpp"
+
#include "std/algorithm.hpp"
+using namespace traffic;
+
+namespace
+{
+double CalcTrafficFactor(SpeedGroup speedGroup)
+{
+ double const percentage =
+ 0.01 * static_cast<double>(kSpeedGroupThresholdPercentage[static_cast<size_t>(speedGroup)]);
+ CHECK_GREATER(percentage, 0.0, ("Speed group:", speedGroup));
+ return 1.0 / percentage;
+}
+} // namespace
+
namespace routing
{
double constexpr kKMPH2MPS = 1000.0 / (60 * 60);
@@ -17,24 +32,39 @@ inline double TimeBetweenSec(m2::PointD const & from, m2::PointD const & to, dou
class CarEdgeEstimator : public EdgeEstimator
{
public:
- CarEdgeEstimator(IVehicleModel const & vehicleModel);
+ CarEdgeEstimator(IVehicleModel const & vehicleModel, traffic::TrafficCache const & trafficCache);
// EdgeEstimator overrides:
- double CalcEdgesWeight(RoadGeometry const & road, uint32_t pointFrom,
+ void Start(MwmSet::MwmId const & mwmId) override;
+ void Finish() override;
+ double CalcEdgesWeight(uint32_t featureId, RoadGeometry const & road, uint32_t pointFrom,
uint32_t pointTo) const override;
double CalcHeuristic(m2::PointD const & from, m2::PointD const & to) const override;
private:
+ TrafficCache const & m_trafficCache;
+ shared_ptr<traffic::TrafficInfo> m_trafficInfo;
double const m_maxSpeedMPS;
};
-CarEdgeEstimator::CarEdgeEstimator(IVehicleModel const & vehicleModel)
- : m_maxSpeedMPS(vehicleModel.GetMaxSpeed() * kKMPH2MPS)
+CarEdgeEstimator::CarEdgeEstimator(IVehicleModel const & vehicleModel,
+ traffic::TrafficCache const & trafficCache)
+ : m_trafficCache(trafficCache), m_maxSpeedMPS(vehicleModel.GetMaxSpeed() * kKMPH2MPS)
+{
+}
+
+void CarEdgeEstimator::Start(MwmSet::MwmId const & mwmId)
+{
+ m_trafficInfo = m_trafficCache.GetTrafficInfo(mwmId);
+}
+
+void CarEdgeEstimator::Finish()
{
+ m_trafficInfo.reset();
}
-double CarEdgeEstimator::CalcEdgesWeight(RoadGeometry const & road, uint32_t pointFrom,
- uint32_t pointTo) const
+double CarEdgeEstimator::CalcEdgesWeight(uint32_t featureId, RoadGeometry const & road,
+ uint32_t pointFrom, uint32_t pointTo) const
{
uint32_t const start = min(pointFrom, pointTo);
uint32_t const finish = max(pointFrom, pointTo);
@@ -42,8 +72,20 @@ double CarEdgeEstimator::CalcEdgesWeight(RoadGeometry const & road, uint32_t poi
double result = 0.0;
double const speedMPS = road.GetSpeed() * kKMPH2MPS;
+ auto const dir = pointFrom < pointTo ? TrafficInfo::RoadSegmentId::kForwardDirection
+ : TrafficInfo::RoadSegmentId::kReverseDirection;
for (uint32_t i = start; i < finish; ++i)
- result += TimeBetweenSec(road.GetPoint(i), road.GetPoint(i + 1), speedMPS);
+ {
+ double edgeWeight = TimeBetweenSec(road.GetPoint(i), road.GetPoint(i + 1), speedMPS);
+ if (m_trafficInfo)
+ {
+ SpeedGroup const speedGroup =
+ m_trafficInfo->GetSpeedGroup(TrafficInfo::RoadSegmentId(featureId, i, dir));
+ ASSERT_LESS(speedGroup, SpeedGroup::Count, ());
+ edgeWeight *= CalcTrafficFactor(speedGroup);
+ }
+ result += edgeWeight;
+ }
return result;
}
@@ -57,8 +99,9 @@ double CarEdgeEstimator::CalcHeuristic(m2::PointD const & from, m2::PointD const
namespace routing
{
// static
-shared_ptr<EdgeEstimator> EdgeEstimator::CreateForCar(IVehicleModel const & vehicleModel)
+shared_ptr<EdgeEstimator> EdgeEstimator::CreateForCar(IVehicleModel const & vehicleModel,
+ traffic::TrafficCache const & trafficCache)
{
- return make_shared<CarEdgeEstimator>(vehicleModel);
+ return make_shared<CarEdgeEstimator>(vehicleModel, trafficCache);
}
} // namespace routing
diff --git a/routing/edge_estimator.hpp b/routing/edge_estimator.hpp
index 0a6ec2d1e0..f78f2a7c25 100644
--- a/routing/edge_estimator.hpp
+++ b/routing/edge_estimator.hpp
@@ -3,6 +3,10 @@
#include "routing/geometry.hpp"
#include "routing/vehicle_model.hpp"
+#include "traffic/traffic_cache.hpp"
+
+#include "indexer/mwm_set.hpp"
+
#include "geometry/point2d.hpp"
#include "std/cstdint.hpp"
@@ -15,10 +19,28 @@ class EdgeEstimator
public:
virtual ~EdgeEstimator() = default;
- virtual double CalcEdgesWeight(RoadGeometry const & road, uint32_t pointFrom,
+ virtual void Start(MwmSet::MwmId const & mwmId) = 0;
+ virtual void Finish() = 0;
+ virtual double CalcEdgesWeight(uint32_t featureId, RoadGeometry const & road, uint32_t pointFrom,
uint32_t pointTo) const = 0;
virtual double CalcHeuristic(m2::PointD const & from, m2::PointD const & to) const = 0;
- static shared_ptr<EdgeEstimator> CreateForCar(IVehicleModel const & vehicleModel);
+
+ static shared_ptr<EdgeEstimator> CreateForCar(IVehicleModel const & vehicleModel,
+ traffic::TrafficCache const & trafficCache);
+};
+
+class EstimatorGuard final
+{
+public:
+ EstimatorGuard(MwmSet::MwmId const & mwmId, EdgeEstimator & estimator) : m_estimator(estimator)
+ {
+ m_estimator.Start(mwmId);
+ }
+
+ ~EstimatorGuard() { m_estimator.Finish(); }
+
+private:
+ EdgeEstimator & m_estimator;
};
} // namespace routing
diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp
index 39e8cd30ce..2a5fde1693 100644
--- a/routing/index_graph.cpp
+++ b/routing/index_graph.cpp
@@ -72,7 +72,8 @@ void IndexGraph::GetNeighboringEdge(RoadGeometry const & road, RoadPoint const &
pair<Joint::Id, uint32_t> const & neighbor = m_roadIndex.FindNeighbor(rp, forward);
if (neighbor.first != Joint::kInvalidId)
{
- double const distance = m_estimator->CalcEdgesWeight(road, rp.GetPointId(), neighbor.second);
+ double const distance =
+ m_estimator->CalcEdgesWeight(rp.GetFeatureId(), road, rp.GetPointId(), neighbor.second);
edges.push_back({neighbor.first, distance});
}
}
@@ -87,7 +88,7 @@ void IndexGraph::GetDirectedEdge(uint32_t featureId, uint32_t pointFrom, uint32_
if (road.IsOneWay() && forward != (pointFrom < pointTo))
return;
- double const distance = m_estimator->CalcEdgesWeight(road, pointFrom, pointTo);
+ double const distance = m_estimator->CalcEdgesWeight(featureId, road, pointFrom, pointTo);
edges.emplace_back(target, distance);
}
} // namespace routing
diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp
index 5ae00512d6..158b7030b3 100644
--- a/routing/index_graph_starter.cpp
+++ b/routing/index_graph_starter.cpp
@@ -154,12 +154,12 @@ void IndexGraphStarter::FindPointsWithCommonFeature(Joint::Id jointId0, Joint::I
// CalcEdgesWeight is very expensive.
// So calculate it only if second common feature found.
RoadGeometry const & prevRoad = m_graph.GetGeometry().GetRoad(result0.GetFeatureId());
- minWeight = m_graph.GetEstimator().CalcEdgesWeight(prevRoad, result0.GetPointId(),
- result1.GetPointId());
+ minWeight = m_graph.GetEstimator().CalcEdgesWeight(
+ rp0.GetFeatureId(), prevRoad, result0.GetPointId(), result1.GetPointId());
}
- double const weight =
- m_graph.GetEstimator().CalcEdgesWeight(road, rp0.GetPointId(), rp1.GetPointId());
+ double const weight = m_graph.GetEstimator().CalcEdgesWeight(
+ rp0.GetFeatureId(), road, rp0.GetPointId(), rp1.GetPointId());
if (weight < minWeight)
{
minWeight = weight;
diff --git a/routing/routing_integration_tests/routing_test_tools.cpp b/routing/routing_integration_tests/routing_test_tools.cpp
index a982361670..b49bd5dae6 100644
--- a/routing/routing_integration_tests/routing_test_tools.cpp
+++ b/routing/routing_integration_tests/routing_test_tools.cpp
@@ -1,5 +1,7 @@
#include "routing/routing_integration_tests/routing_test_tools.hpp"
+#include "routing/routing_tests/index_graph_tools.hpp"
+
#include "testing/testing.hpp"
#include "map/feature_vec_model.hpp"
@@ -29,8 +31,8 @@
#include <sys/resource.h>
-
using namespace routing;
+using namespace routing_test;
using TRouterFactory =
function<unique_ptr<IRouter>(Index & index, TCountryFileFn const & countryFileFn)>;
@@ -76,14 +78,15 @@ namespace integration
}
unique_ptr<CarRouter> CreateCarRouter(Index & index,
- storage::CountryInfoGetter const & infoGetter)
+ storage::CountryInfoGetter const & infoGetter,
+ traffic::TrafficCache const & trafficCache)
{
auto const countryFileGetter = [&infoGetter](m2::PointD const & pt) {
return infoGetter.GetRegionCountryId(pt);
};
- auto carRouter = make_unique<CarRouter>(
- index, countryFileGetter, SingleMwmRouter::CreateCarRouter(index));
+ auto carRouter = make_unique<CarRouter>(index, countryFileGetter,
+ SingleMwmRouter::CreateCarRouter(index, trafficCache));
return carRouter;
}
@@ -106,12 +109,14 @@ namespace integration
public:
OsrmRouterComponents(vector<LocalCountryFile> const & localFiles)
: IRouterComponents(localFiles)
- , m_carRouter(CreateCarRouter(m_featuresFetcher->GetIndex(), *m_infoGetter))
+ , m_carRouter(CreateCarRouter(m_featuresFetcher->GetIndex(), *m_infoGetter, m_trafficCache))
{
}
IRouter * GetRouter() const override { return m_carRouter.get(); }
+
private:
+ traffic::TrafficCache m_trafficCache;
unique_ptr<CarRouter> m_carRouter;
};
diff --git a/routing/routing_integration_tests/routing_test_tools.hpp b/routing/routing_integration_tests/routing_test_tools.hpp
index cefa6b314b..6ead348743 100644
--- a/routing/routing_integration_tests/routing_test_tools.hpp
+++ b/routing/routing_integration_tests/routing_test_tools.hpp
@@ -50,107 +50,97 @@ shared_ptr<model::FeaturesFetcher> CreateFeaturesFetcher(vector<LocalCountryFile
unique_ptr<storage::CountryInfoGetter> CreateCountryInfoGetter();
- class IRouterComponents
+class IRouterComponents
+{
+public:
+ IRouterComponents(vector<LocalCountryFile> const & localFiles)
+ : m_featuresFetcher(CreateFeaturesFetcher(localFiles)), m_infoGetter(CreateCountryInfoGetter())
+ {
+ }
+
+ virtual ~IRouterComponents() = default;
+
+ virtual IRouter * GetRouter() const = 0;
+
+ storage::CountryInfoGetter const & GetCountryInfoGetter() const noexcept { return *m_infoGetter; }
+
+protected:
+ shared_ptr<model::FeaturesFetcher> m_featuresFetcher;
+ unique_ptr<storage::CountryInfoGetter> m_infoGetter;
+};
+
+void TestOnlineCrosses(ms::LatLon const & startPoint, ms::LatLon const & finalPoint,
+ vector<string> const & expected, IRouterComponents & routerComponents);
+void TestOnlineFetcher(ms::LatLon const & startPoint, ms::LatLon const & finalPoint,
+ vector<string> const & expected, IRouterComponents & routerComponents);
+
+/// Gets OSRM router components
+IRouterComponents & GetOsrmComponents();
+shared_ptr<IRouterComponents> GetOsrmComponents(vector<platform::LocalCountryFile> const & localFiles);
+
+/// Gets pedestrian router components
+IRouterComponents & GetPedestrianComponents();
+shared_ptr<IRouterComponents> GetPedestrianComponents(vector<platform::LocalCountryFile> const & localFiles);
+
+/// Gets bicycle router components.
+IRouterComponents & GetBicycleComponents();
+shared_ptr<IRouterComponents> GetBicycleComponents(vector<platform::LocalCountryFile> const & localFiles);
+
+TRouteResult CalculateRoute(IRouterComponents const & routerComponents,
+ m2::PointD const & startPoint, m2::PointD const & startDirection,
+ m2::PointD const & finalPoint);
+
+void TestTurnCount(Route const & route, uint32_t expectedTurnCount);
+
+/// Testing route length.
+/// It is used for checking if routes have expected(sample) length.
+/// A created route will pass the test iff
+/// expectedRouteMeters - expectedRouteMeters * relativeError <= route->GetDistance()
+/// && expectedRouteMeters + expectedRouteMeters * relativeError >= route->GetDistance()
+void TestRouteLength(Route const & route, double expectedRouteMeters, double relativeError = 0.01);
+void TestRouteTime(Route const & route, double expectedRouteSeconds, double relativeError = 0.01);
+
+void CalculateRouteAndTestRouteLength(IRouterComponents const & routerComponents,
+ m2::PointD const & startPoint,
+ m2::PointD const & startDirection,
+ m2::PointD const & finalPoint, double expectedRouteMeters,
+ double relativeError = 0.07);
+
+class TestTurn
+{
+ friend TestTurn GetNthTurn(Route const & route, uint32_t turnNumber);
+
+ m2::PointD const m_point;
+ TurnDirection const m_direction;
+ uint32_t const m_roundAboutExitNum;
+ bool const m_isValid;
+
+ TestTurn()
+ : m_point({0.0, 0.0})
+ , m_direction(TurnDirection::NoTurn)
+ , m_roundAboutExitNum(0)
+ , m_isValid(false)
{
- public:
- IRouterComponents(vector<LocalCountryFile> const & localFiles)
- : m_featuresFetcher(CreateFeaturesFetcher(localFiles))
- , m_infoGetter(CreateCountryInfoGetter())
- {
- }
-
- virtual ~IRouterComponents() = default;
-
- virtual IRouter * GetRouter() const = 0;
-
- storage::CountryInfoGetter const & GetCountryInfoGetter() const noexcept
- {
- return *m_infoGetter;
- }
-
- protected:
- shared_ptr<model::FeaturesFetcher> m_featuresFetcher;
- unique_ptr<storage::CountryInfoGetter> m_infoGetter;
- };
-
- void TestOnlineCrosses(ms::LatLon const & startPoint, ms::LatLon const & finalPoint,
- vector<string> const & expected, IRouterComponents & routerComponents);
- void TestOnlineFetcher(ms::LatLon const & startPoint, ms::LatLon const & finalPoint,
- vector<string> const & expected, IRouterComponents & routerComponents);
-
- /// Gets OSRM router components
- IRouterComponents & GetOsrmComponents();
- shared_ptr<IRouterComponents> GetOsrmComponents(vector<platform::LocalCountryFile> const & localFiles);
-
- /// Gets pedestrian router components
- IRouterComponents & GetPedestrianComponents();
- shared_ptr<IRouterComponents> GetPedestrianComponents(vector<platform::LocalCountryFile> const & localFiles);
-
- /// Gets bicycle router components.
- IRouterComponents & GetBicycleComponents();
- shared_ptr<IRouterComponents> GetBicycleComponents(
- vector<platform::LocalCountryFile> const & localFiles);
-
- TRouteResult CalculateRoute(IRouterComponents const & routerComponents,
- m2::PointD const & startPoint, m2::PointD const & startDirection,
- m2::PointD const & finalPoint);
-
- void TestTurnCount(Route const & route, uint32_t expectedTurnCount);
-
- /// Testing route length.
- /// It is used for checking if routes have expected(sample) length.
- /// A created route will pass the test iff
- /// expectedRouteMeters - expectedRouteMeters * relativeError <= route->GetDistance()
- /// && expectedRouteMeters + expectedRouteMeters * relativeError >= route->GetDistance()
- void TestRouteLength(Route const & route, double expectedRouteMeters,
- double relativeError = 0.01);
- void TestRouteTime(Route const & route, double expectedRouteSeconds,
- double relativeError = 0.01);
-
- void CalculateRouteAndTestRouteLength(IRouterComponents const & routerComponents,
- m2::PointD const & startPoint,
- m2::PointD const & startDirection,
- m2::PointD const & finalPoint, double expectedRouteMeters,
- double relativeError = 0.07);
-
- class TestTurn
+ }
+ TestTurn(m2::PointD const & pnt, TurnDirection direction, uint32_t roundAboutExitNum)
+ : m_point(pnt), m_direction(direction), m_roundAboutExitNum(roundAboutExitNum), m_isValid(true)
{
- friend TestTurn GetNthTurn(Route const & route, uint32_t turnNumber);
-
- m2::PointD const m_point;
- TurnDirection const m_direction;
- uint32_t const m_roundAboutExitNum;
- bool const m_isValid;
-
- TestTurn()
- : m_point({0., 0.}),
- m_direction(TurnDirection::NoTurn),
- m_roundAboutExitNum(0),
- m_isValid(false)
- {
- }
- TestTurn(m2::PointD const & pnt, TurnDirection direction, uint32_t roundAboutExitNum)
- : m_point(pnt),
- m_direction(direction),
- m_roundAboutExitNum(roundAboutExitNum),
- m_isValid(true)
- {
- }
-
- public:
- const TestTurn & TestValid() const;
- const TestTurn & TestNotValid() const;
- const TestTurn & TestPoint(m2::PointD const & expectedPoint, double inaccuracyMeters = 3.) const;
- const TestTurn & TestDirection(TurnDirection expectedDirection) const;
- const TestTurn & TestOneOfDirections(set<TurnDirection> const & expectedDirections) const;
- const TestTurn & TestRoundAboutExitNum(uint32_t expectedRoundAboutExitNum) const;
- };
-
- /// Extracting appropriate TestTurn if any. If not TestTurn::isValid() returns false.
- /// inaccuracy is set in meters.
- TestTurn GetNthTurn(Route const & route, uint32_t turnNumber);
-
- void TestCurrentStreetName(routing::Route const & route, string const & expectedStreetName);
-
- void TestNextStreetName(routing::Route const & route, string const & expectedStreetName);
-}
+ }
+
+public:
+ const TestTurn & TestValid() const;
+ const TestTurn & TestNotValid() const;
+ const TestTurn & TestPoint(m2::PointD const & expectedPoint, double inaccuracyMeters = 3.) const;
+ const TestTurn & TestDirection(TurnDirection expectedDirection) const;
+ const TestTurn & TestOneOfDirections(set<TurnDirection> const & expectedDirections) const;
+ const TestTurn & TestRoundAboutExitNum(uint32_t expectedRoundAboutExitNum) const;
+};
+
+/// Extracting appropriate TestTurn if any. If not TestTurn::isValid() returns false.
+/// inaccuracy is set in meters.
+TestTurn GetNthTurn(Route const & route, uint32_t turnNumber);
+
+void TestCurrentStreetName(routing::Route const & route, string const & expectedStreetName);
+
+void TestNextStreetName(routing::Route const & route, string const & expectedStreetName);
+} // namespace integration
diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp
index cca937ec48..4f3011a87d 100644
--- a/routing/routing_session.cpp
+++ b/routing/routing_session.cpp
@@ -10,9 +10,12 @@
#include "coding/internal/file_data.hpp"
+#include "std/utility.hpp"
+
#include "3party/Alohalytics/src/alohalytics.h"
using namespace location;
+using namespace traffic;
namespace
{
@@ -95,7 +98,7 @@ void RoutingSession::RebuildRoute(m2::PointD const & startPoint,
// Use old-style callback construction, because lambda constructs buggy function on Android
// (callback param isn't captured by value).
m_router->CalculateRoute(startPoint, startPoint - m_lastGoodPosition, m_endPoint,
- DoReadyCallback(*this, readyCallback, m_routeSessionMutex),
+ DoReadyCallback(*this, readyCallback, m_routingSessionMutex),
progressCallback, timeoutSec);
}
@@ -131,7 +134,7 @@ void RoutingSession::RemoveRouteImpl()
void RoutingSession::RemoveRoute()
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
RemoveRouteImpl();
@@ -141,7 +144,7 @@ void RoutingSession::Reset()
{
ASSERT(m_router != nullptr, ());
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
RemoveRouteImpl();
@@ -166,7 +169,7 @@ RoutingSession::State RoutingSession::OnLocationPositionChanged(GpsInfo const &
|| m_state == RouteNotReady || m_state == RouteNoFollowing)
return m_state;
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
ASSERT(m_route, ());
ASSERT(m_route->IsValid(), ());
@@ -258,7 +261,7 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const
value.erase(delim);
};
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
ASSERT(m_route, ());
@@ -353,7 +356,7 @@ void RoutingSession::GenerateTurnNotifications(vector<string> & turnNotification
{
turnNotifications.clear();
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
ASSERT(m_route, ());
@@ -410,7 +413,7 @@ void RoutingSession::MatchLocationToRoute(location::GpsInfo & location,
if (!IsOnRoute())
return;
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
ASSERT(m_route, ());
@@ -443,7 +446,7 @@ bool RoutingSession::EnableFollowMode()
void RoutingSession::SetRoutingSettings(RoutingSettings const & routingSettings)
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
m_routingSettings = routingSettings;
}
@@ -460,21 +463,21 @@ m2::PointD const & RoutingSession::GetUserCurrentPosition() const
void RoutingSession::EnableTurnNotifications(bool enable)
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
m_turnNotificationsMgr.Enable(enable);
}
bool RoutingSession::AreTurnNotificationsEnabled() const
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
return m_turnNotificationsMgr.IsEnabled();
}
void RoutingSession::SetTurnNotificationsUnits(measurement_utils::Units const units)
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
m_turnNotificationsMgr.SetLengthUnits(units);
}
@@ -482,14 +485,14 @@ void RoutingSession::SetTurnNotificationsUnits(measurement_utils::Units const un
void RoutingSession::SetTurnNotificationsLocale(string const & locale)
{
LOG(LINFO, ("The language for turn notifications is", locale));
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
m_turnNotificationsMgr.SetLocale(locale);
}
string RoutingSession::GetTurnNotificationsLocale() const
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
UNUSED_VALUE(guard);
return m_turnNotificationsMgr.GetLocale();
}
@@ -523,7 +526,7 @@ double RoutingSession::GetDistanceToCurrentCamM(SpeedCameraRestriction & camera,
void RoutingSession::EmitCloseRoutingEvent() const
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
ASSERT(m_route, ());
if (!m_route->IsValid())
@@ -552,14 +555,14 @@ bool RoutingSession::HasRouteAltitudeImpl() const
bool RoutingSession::HasRouteAltitude() const
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
return HasRouteAltitudeImpl();
}
bool RoutingSession::GetRouteAltitudesAndDistancesM(vector<double> & routeSegDistanceM,
feature::TAltitudes & routeAltitudesM) const
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
ASSERT(m_route, ());
if (!m_route->IsValid() || !HasRouteAltitudeImpl())
@@ -572,11 +575,40 @@ bool RoutingSession::GetRouteAltitudesAndDistancesM(vector<double> & routeSegDis
shared_ptr<Route> const RoutingSession::GetRoute() const
{
- threads::MutexGuard guard(m_routeSessionMutex);
+ threads::MutexGuard guard(m_routingSessionMutex);
ASSERT(m_route, ());
return m_route;
}
+void RoutingSession::OnTrafficEnabled(bool enable)
+{
+ threads::MutexGuard guard(m_routingSessionMutex);
+ UNUSED_VALUE(guard);
+ if (!enable)
+ Clear();
+}
+
+void RoutingSession::OnTrafficInfoAdded(TrafficInfo && info)
+{
+ threads::MutexGuard guard(m_routingSessionMutex);
+ UNUSED_VALUE(guard);
+ Set(move(info));
+}
+
+void RoutingSession::OnTrafficInfoRemoved(MwmSet::MwmId const & mwmId)
+{
+ threads::MutexGuard guard(m_routingSessionMutex);
+ UNUSED_VALUE(guard);
+ Remove(mwmId);
+}
+
+shared_ptr<traffic::TrafficInfo> RoutingSession::GetTrafficInfo(MwmSet::MwmId const & mwmId) const
+{
+ threads::MutexGuard guard(m_routingSessionMutex);
+ UNUSED_VALUE(guard);
+ return TrafficCache::GetTrafficInfo(mwmId);
+}
+
string DebugPrint(RoutingSession::State state)
{
switch (state)
diff --git a/routing/routing_session.hpp b/routing/routing_session.hpp
index b4fa257416..d22e9926b0 100644
--- a/routing/routing_session.hpp
+++ b/routing/routing_session.hpp
@@ -6,6 +6,9 @@
#include "routing/turns.hpp"
#include "routing/turns_notification_manager.hpp"
+#include "traffic/traffic_cache.hpp"
+#include "traffic/traffic_info.hpp"
+
#include "platform/location.hpp"
#include "platform/measurement_utils.hpp"
@@ -16,6 +19,7 @@
#include "std/atomic.hpp"
#include "std/limits.hpp"
+#include "std/map.hpp"
#include "std/shared_ptr.hpp"
#include "std/unique_ptr.hpp"
@@ -35,7 +39,7 @@ struct SpeedCameraRestriction
SpeedCameraRestriction() : m_index(0), m_maxSpeedKmH(numeric_limits<uint8_t>::max()) {}
};
-class RoutingSession
+class RoutingSession : public traffic::TrafficObserver, public traffic::TrafficCache
{
friend void UnitTest_TestFollowRoutePercentTest();
@@ -150,6 +154,14 @@ public:
void EmitCloseRoutingEvent() const;
+ // RoutingObserver overrides:
+ void OnTrafficEnabled(bool enable) override;
+ void OnTrafficInfoAdded(traffic::TrafficInfo && info) override;
+ void OnTrafficInfoRemoved(MwmSet::MwmId const & mwmId) override;
+
+ // TrafficCache overrides:
+ shared_ptr<traffic::TrafficInfo> GetTrafficInfo(MwmSet::MwmId const & mwmId) const override;
+
private:
struct DoReadyCallback
{
@@ -195,7 +207,7 @@ private:
/// about camera will be sent at most once.
mutable bool m_speedWarningSignal;
- mutable threads::Mutex m_routeSessionMutex;
+ mutable threads::Mutex m_routingSessionMutex;
/// Current position metrics to check for RouteNeedRebuild state.
double m_lastDistance;
diff --git a/routing/routing_tests/applying_traffic_test.cpp b/routing/routing_tests/applying_traffic_test.cpp
new file mode 100644
index 0000000000..e19258df57
--- /dev/null
+++ b/routing/routing_tests/applying_traffic_test.cpp
@@ -0,0 +1,224 @@
+#include "testing/testing.hpp"
+
+#include "routing/car_model.hpp"
+#include "routing/geometry.hpp"
+#include "routing/index_graph.hpp"
+#include "routing/index_graph_starter.hpp"
+#include "routing/routing_session.hpp"
+
+#include "routing/routing_tests/index_graph_tools.hpp"
+
+#include "traffic/traffic_info.hpp"
+
+#include "indexer/classificator_loader.hpp"
+
+#include "geometry/point2d.hpp"
+
+#include "routing/base/astar_algorithm.hpp"
+
+#include "std/shared_ptr.hpp"
+#include "std/unique_ptr.hpp"
+#include "std/vector.hpp"
+
+namespace
+{
+using namespace routing;
+using namespace routing_test;
+using namespace traffic;
+
+// @TODO(bykoianko) When PR with applying restricions is merged BuildXXGraph()
+// should be moved to "routing/routing_tests/index_graph_tools.hpp" and it should
+// be used by applying_traffic_test.cpp and cumulative_restriction_test.cpp.
+
+// Finish
+// 3 * *
+// ↖ ↗
+// F5 F6
+// ↖ ↗
+// 2 * *
+// ↖ ↗ ↖
+// F2 F3 F4
+// ↖ ↗ ↖
+// 1 * *
+// ↗ ↖ ^
+// F0 F1 F8
+// ↗ ↖ |
+// 0 * *--F7--->*
+// 0 1 2 3
+// Start
+// Note. This graph contains of 9 one segment directed features.
+unique_ptr<IndexGraph> BuildXXGraph(shared_ptr<EdgeEstimator> estimator)
+{
+ unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
+ loader->AddRoad(0 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{0.0, 0.0}, {1.0, 1.0}}));
+ loader->AddRoad(1 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{2.0, 0.0}, {1.0, 1.0}}));
+ loader->AddRoad(2 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{1.0, 1.0}, {0.0, 2.0}}));
+ loader->AddRoad(3 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{1.0, 1.0}, {2.0, 2.0}}));
+ loader->AddRoad(4 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{3.0, 1.0}, {2.0, 2.0}}));
+ loader->AddRoad(5 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{2.0, 2.0}, {1.0, 3.0}}));
+ loader->AddRoad(6 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{2.0, 2.0}, {3.0, 3.0}}));
+ loader->AddRoad(7 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{2.0, 0.0}, {3.0, 0.0}}));
+ loader->AddRoad(8 /* featureId */, true /* oneWay */, 1.0 /* speed */,
+ RoadGeometry::Points({{3.0, 0.0}, {3.0, 1.0}}));
+
+ vector<Joint> const joints = {
+ MakeJoint({{0 /* feature id */, 0 /* point id */}}), /* joint at point (0, 0) */
+ MakeJoint({{1, 0}, {7, 0}}), /* joint at point (2, 0) */
+ MakeJoint({{0, 1}, {1, 1}, {2, 0}, {3, 0}}), /* joint at point (1, 1) */
+ MakeJoint({{2, 1}}), /* joint at point (0, 2) */
+ MakeJoint({{3, 1}, {4, 1}, {5, 0}, {6, 0}}), /* joint at point (2, 2) */
+ MakeJoint({{4, 0}, {8, 1}}), /* joint at point (3, 1) */
+ MakeJoint({{5, 1}}), /* joint at point (1, 3) */
+ MakeJoint({{6, 1}}), /* joint at point (3, 3) */
+ MakeJoint({{7, 1}, {8, 0}}), /* joint at point (3, 0) */
+ };
+
+ unique_ptr<IndexGraph> graph = make_unique<IndexGraph>(move(loader), estimator);
+ graph->Import(joints);
+ return graph;
+}
+
+class ApplyingTrafficTest
+{
+public:
+ class TrafficCacheTest : public TrafficCache
+ {
+ public:
+ void SetTrafficInfo(traffic::TrafficInfo && info) { Set(move(info)); }
+ };
+
+ ApplyingTrafficTest() { classificator::Load(); }
+
+ void SetEstimator(TrafficInfo::Coloring && coloring)
+ {
+ m_trafficCache = make_unique<TrafficCacheTest>();
+ UpdateTrafficInfo(move(coloring));
+ m_estimator = EdgeEstimator::CreateForCar(*make_shared<CarModelFactory>()->GetVehicleModel(),
+ *m_trafficCache);
+ }
+
+ shared_ptr<EdgeEstimator> GetEstimator() const { return m_estimator; }
+
+ void UpdateTrafficInfo(TrafficInfo::Coloring && coloring)
+ {
+ m_trafficCache->SetTrafficInfo(TrafficInfo::BuildForTesting(move(coloring)));
+ }
+
+private:
+ unique_ptr<TrafficCacheTest> m_trafficCache;
+ shared_ptr<EdgeEstimator> m_estimator;
+};
+
+// Route through XX graph without any traffic info.
+UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_EmptyTrafficColoring)
+{
+ SetEstimator({} /* coloring */);
+
+ unique_ptr<IndexGraph> graph = BuildXXGraph(GetEstimator());
+ IndexGraphStarter starter(*graph, RoadPoint(1, 0) /* start */, RoadPoint(6, 1) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {3, 3}};
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// Route through XX graph with SpeedGroup::G0 on F3.
+UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_G0onF3)
+{
+ TrafficInfo::Coloring coloring = {
+ {{3 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G0}};
+ SetEstimator(move(coloring));
+
+ unique_ptr<IndexGraph> graph = BuildXXGraph(GetEstimator());
+ IndexGraphStarter starter(*graph, RoadPoint(1, 0) /* start */, RoadPoint(6, 1) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */}, {3, 0}, {3, 1}, {2, 2}, {3, 3}};
+ EstimatorGuard guard(MwmSet::MwmId(), *GetEstimator());
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// Route through XX graph with SpeedGroup::G0 in reverse direction on F3.
+UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_G0onF3ReverseDir)
+{
+ TrafficInfo::Coloring coloring = {
+ {{3 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kReverseDirection},
+ SpeedGroup::G0}};
+ SetEstimator(move(coloring));
+
+ unique_ptr<IndexGraph> graph = BuildXXGraph(GetEstimator());
+ IndexGraphStarter starter(*graph, RoadPoint(1, 0) /* start */, RoadPoint(6, 1) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {3, 3}};
+ EstimatorGuard guard(MwmSet::MwmId(), *GetEstimator());
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// Route through XX graph SpeedGroup::G1 on F3 and F6, SpeedGroup::G4 on F8 and F4.
+UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_G0onF3andF6andG4onF8andF4)
+{
+ TrafficInfo::Coloring coloring = {
+ {{3 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G0},
+ {{6 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G0},
+ {{8 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G4},
+ {{7 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G4}};
+ SetEstimator(move(coloring));
+
+ unique_ptr<IndexGraph> graph = BuildXXGraph(GetEstimator());
+ IndexGraphStarter starter(*graph, RoadPoint(1, 0) /* start */, RoadPoint(6, 1) /* finish */);
+ vector<m2::PointD> const expectedGeom = {{2 /* x */, 0 /* y */}, {3, 0}, {3, 1}, {2, 2}, {3, 3}};
+ EstimatorGuard guard(MwmSet::MwmId(), *GetEstimator());
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, expectedGeom);
+}
+
+// Route through XX graph with changing traffic.
+UNIT_CLASS_TEST(ApplyingTrafficTest, XXGraph_ChangingTraffic)
+{
+ // No trafic at all.
+ SetEstimator({} /* coloring */);
+ unique_ptr<IndexGraph> graph = BuildXXGraph(GetEstimator());
+ IndexGraphStarter starter(*graph, RoadPoint(1, 0) /* start */, RoadPoint(6, 1) /* finish */);
+ vector<m2::PointD> const noTrafficGeom = {{2 /* x */, 0 /* y */}, {1, 1}, {2, 2}, {3, 3}};
+ {
+ EstimatorGuard guard(MwmSet::MwmId(), *GetEstimator());
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, noTrafficGeom);
+ }
+
+ // Heavy traffic (SpeedGroup::G0) on F3.
+ TrafficInfo::Coloring coloringHeavyF3 = {
+ {{3 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G0}};
+ UpdateTrafficInfo(move(coloringHeavyF3));
+ {
+ EstimatorGuard guard(MwmSet::MwmId(), *GetEstimator());
+ vector<m2::PointD> const heavyF3Geom = {{2 /* x */, 0 /* y */}, {3, 0}, {3, 1}, {2, 2}, {3, 3}};
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, heavyF3Geom);
+ }
+
+ // Overloading traffic jam on F3. Middle traffic (SpeedGroup::G3) on F1, F3, F4, F7 and F8.
+ TrafficInfo::Coloring coloringMiddleF1F3F4F7F8 = {
+ {{1 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G3},
+ {{3 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G3},
+ {{4 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G3},
+ {{7 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G3},
+ {{8 /* feature id */, 0 /* segment id */, TrafficInfo::RoadSegmentId::kForwardDirection},
+ SpeedGroup::G3}};
+ UpdateTrafficInfo(move(coloringMiddleF1F3F4F7F8));
+ {
+ EstimatorGuard guard(MwmSet::MwmId(), *GetEstimator());
+ TestRouteGeometry(starter, AStarAlgorithm<IndexGraphStarter>::Result::OK, noTrafficGeom);
+ }
+}
+} // namespace
diff --git a/routing/routing_tests/index_graph_test.cpp b/routing/routing_tests/index_graph_test.cpp
index 4dfb73de64..9d060f31ad 100644
--- a/routing/routing_tests/index_graph_test.cpp
+++ b/routing/routing_tests/index_graph_test.cpp
@@ -6,6 +6,8 @@
#include "routing/index_graph.hpp"
#include "routing/index_graph_starter.hpp"
+#include "routing/routing_tests/index_graph_tools.hpp"
+
#include "geometry/point2d.hpp"
#include "base/assert.hpp"
@@ -18,49 +20,7 @@
namespace
{
using namespace routing;
-
-class TestGeometryLoader final : public GeometryLoader
-{
-public:
- // GeometryLoader overrides:
- void Load(uint32_t featureId, RoadGeometry & road) const override;
-
- void AddRoad(uint32_t featureId, bool oneWay, float speed, RoadGeometry::Points const & points);
-
-private:
- unordered_map<uint32_t, RoadGeometry> m_roads;
-};
-
-void TestGeometryLoader::Load(uint32_t featureId, RoadGeometry & road) const
-{
- auto it = m_roads.find(featureId);
- if (it == m_roads.cend())
- return;
-
- road = it->second;
-}
-
-void TestGeometryLoader::AddRoad(uint32_t featureId, bool oneWay, float speed,
- RoadGeometry::Points const & points)
-{
- auto it = m_roads.find(featureId);
- CHECK(it == m_roads.end(), ("Already contains feature", featureId));
- m_roads[featureId] = RoadGeometry(oneWay, speed, points);
-}
-
-Joint MakeJoint(vector<RoadPoint> const & points)
-{
- Joint joint;
- for (auto const & point : points)
- joint.AddPoint(point);
-
- return joint;
-}
-
-shared_ptr<EdgeEstimator> CreateEstimator()
-{
- return EdgeEstimator::CreateForCar(*make_shared<CarModelFactory>()->GetVehicleModel());
-}
+using namespace routing_test;
void TestRoute(IndexGraph & graph, RoadPoint const & start, RoadPoint const & finish,
size_t expectedLength, vector<RoadPoint> const * expectedRoute = nullptr)
@@ -68,16 +28,11 @@ void TestRoute(IndexGraph & graph, RoadPoint const & start, RoadPoint const & fi
LOG(LINFO, ("Test route", start.GetFeatureId(), ",", start.GetPointId(), "=>",
finish.GetFeatureId(), ",", finish.GetPointId()));
- AStarAlgorithm<IndexGraphStarter> algorithm;
- RoutingResult<Joint::Id> routingResult;
-
IndexGraphStarter starter(graph, start, finish);
- auto const resultCode = algorithm.FindPath(starter, starter.GetStartJoint(),
- starter.GetFinishJoint(), routingResult, {}, {});
+ vector<RoadPoint> roadPoints;
+ auto const resultCode = CalculateRoute(starter, roadPoints);
TEST_EQUAL(resultCode, AStarAlgorithm<IndexGraphStarter>::Result::OK, ());
- vector<RoadPoint> roadPoints;
- starter.RedressRoute(routingResult.path, roadPoints);
TEST_EQUAL(roadPoints.size(), expectedLength, ());
if (expectedRoute)
@@ -145,7 +100,8 @@ UNIT_TEST(EdgesTest)
loader->AddRoad(4 /* featureId */, true, 1.0 /* speed */,
RoadGeometry::Points({{3.0, -1.0}, {3.0, 0.0}, {3.0, 1.0}}));
- IndexGraph graph(move(loader), CreateEstimator());
+ traffic::TrafficCache const trafficCache;
+ IndexGraph graph(move(loader), CreateEstimator(trafficCache));
vector<Joint> joints;
joints.emplace_back(MakeJoint({{0, 1}, {3, 1}})); // J0
@@ -189,7 +145,8 @@ UNIT_TEST(FindPathCross)
1 /* featureId */, false, 1.0 /* speed */,
RoadGeometry::Points({{0.0, -2.0}, {-1.0, 0.0}, {0.0, 0.0}, {0.0, 1.0}, {0.0, 2.0}}));
- IndexGraph graph(move(loader), CreateEstimator());
+ traffic::TrafficCache const trafficCache;
+ IndexGraph graph(move(loader), CreateEstimator(trafficCache));
graph.Import({MakeJoint({{0, 2}, {1, 2}})});
@@ -245,7 +202,8 @@ UNIT_TEST(FindPathManhattan)
loader->AddRoad(i + kCitySize, false, 1.0 /* speed */, avenue);
}
- IndexGraph graph(move(loader), CreateEstimator());
+ traffic::TrafficCache const trafficCache;
+ IndexGraph graph(move(loader), CreateEstimator(trafficCache));
vector<Joint> joints;
for (uint32_t i = 0; i < kCitySize; ++i)
@@ -295,7 +253,8 @@ UNIT_TEST(RedressRace)
2 /* featureId */, false, 1.0 /* speed */,
RoadGeometry::Points({{0.0, 0.0}, {1.0, 1.0}, {2.0, 1.0}, {3.0, 1.0}, {4.0, 0.0}}));
- IndexGraph graph(move(loader), CreateEstimator());
+ traffic::TrafficCache const trafficCache;
+ IndexGraph graph(move(loader), CreateEstimator(trafficCache));
vector<Joint> joints;
joints.emplace_back(MakeJoint({{0, 0}, {1, 0}, {2, 0}})); // J0
@@ -325,7 +284,8 @@ UNIT_TEST(RoadSpeed)
loader->AddRoad(1 /* featureId */, false, 1.0 /* speed */,
RoadGeometry::Points({{0.0, 0.0}, {2.0, 0.0}, {4.0, 0.0}}));
- IndexGraph graph(move(loader), CreateEstimator());
+ traffic::TrafficCache const trafficCache;
+ IndexGraph graph(move(loader), CreateEstimator(trafficCache));
vector<Joint> joints;
joints.emplace_back(MakeJoint({{0, 0}, {1, 0}})); // J0
diff --git a/routing/routing_tests/index_graph_tools.cpp b/routing/routing_tests/index_graph_tools.cpp
new file mode 100644
index 0000000000..390ae86bd6
--- /dev/null
+++ b/routing/routing_tests/index_graph_tools.cpp
@@ -0,0 +1,70 @@
+#include "routing/routing_tests/index_graph_tools.hpp"
+
+#include "testing/testing.hpp"
+
+#include "routing/car_model.hpp"
+
+namespace routing_test
+{
+using namespace routing;
+
+void TestGeometryLoader::Load(uint32_t featureId, RoadGeometry & road) const
+{
+ auto it = m_roads.find(featureId);
+ if (it == m_roads.cend())
+ return;
+
+ road = it->second;
+}
+
+void TestGeometryLoader::AddRoad(uint32_t featureId, bool oneWay, float speed,
+ RoadGeometry::Points const & points)
+{
+ auto it = m_roads.find(featureId);
+ CHECK(it == m_roads.end(), ("Already contains feature", featureId));
+ m_roads[featureId] = RoadGeometry(oneWay, speed, points);
+}
+
+Joint MakeJoint(vector<RoadPoint> const & points)
+{
+ Joint joint;
+ for (auto const & point : points)
+ joint.AddPoint(point);
+
+ return joint;
+}
+
+shared_ptr<EdgeEstimator> CreateEstimator(traffic::TrafficCache const & trafficCache)
+{
+ return EdgeEstimator::CreateForCar(*make_shared<CarModelFactory>()->GetVehicleModel(), trafficCache);
+}
+
+AStarAlgorithm<IndexGraphStarter>::Result CalculateRoute(IndexGraphStarter & starter,
+ vector<RoadPoint> & roadPoints)
+{
+ AStarAlgorithm<IndexGraphStarter> algorithm;
+ RoutingResult<Joint::Id> routingResult;
+ auto const resultCode = algorithm.FindPath(
+ starter, starter.GetStartJoint(), starter.GetFinishJoint(), routingResult, {}, {});
+
+ starter.RedressRoute(routingResult.path, roadPoints);
+ return resultCode;
+}
+
+void TestRouteGeometry(IndexGraphStarter & starter,
+ AStarAlgorithm<IndexGraphStarter>::Result expectedRouteResult,
+ vector<m2::PointD> const & expectedRouteGeom)
+{
+ vector<RoadPoint> route;
+ auto const resultCode = CalculateRoute(starter, route);
+ TEST_EQUAL(resultCode, expectedRouteResult, ());
+ TEST_EQUAL(route.size(), expectedRouteGeom.size(), ());
+ for (size_t i = 0; i < route.size(); ++i)
+ {
+ // When PR with applying restricions is merged IndexGraph::GetRoad() should be used here instead.
+ RoadGeometry roadGeom = starter.GetGraph().GetGeometry().GetRoad(route[i].GetFeatureId());
+ CHECK_LESS(route[i].GetPointId(), roadGeom.GetPointsCount(), ());
+ TEST_EQUAL(expectedRouteGeom[i], roadGeom.GetPoint(route[i].GetPointId()), ());
+ }
+}
+} // namespace routing_test
diff --git a/routing/routing_tests/index_graph_tools.hpp b/routing/routing_tests/index_graph_tools.hpp
new file mode 100644
index 0000000000..8cc0f0b94d
--- /dev/null
+++ b/routing/routing_tests/index_graph_tools.hpp
@@ -0,0 +1,51 @@
+#pragma once
+
+#include "routing/edge_estimator.hpp"
+#include "routing/index_graph.hpp"
+#include "routing/index_graph_starter.hpp"
+#include "routing/road_point.hpp"
+
+#include "routing/base/astar_algorithm.hpp"
+
+#include "traffic/traffic_info.hpp"
+
+#include "geometry/point2d.hpp"
+
+#include "std/algorithm.hpp"
+#include "std/shared_ptr.hpp"
+#include "std/unique_ptr.hpp"
+#include "std/unordered_map.hpp"
+#include "std/vector.hpp"
+
+namespace routing_test
+{
+class TestGeometryLoader final : public routing::GeometryLoader
+{
+public:
+ // GeometryLoader overrides:
+ void Load(uint32_t featureId, routing::RoadGeometry & road) const override;
+
+ void AddRoad(uint32_t featureId, bool oneWay, float speed,
+ routing::RoadGeometry::Points const & points);
+
+private:
+ unordered_map<uint32_t, routing::RoadGeometry> m_roads;
+};
+
+routing::Joint MakeJoint(vector<routing::RoadPoint> const & points);
+
+shared_ptr<routing::EdgeEstimator> CreateEstimator(traffic::TrafficCache const & trafficCache);
+
+routing::AStarAlgorithm<routing::IndexGraphStarter>::Result CalculateRoute(
+ routing::IndexGraphStarter & graph, vector<routing::RoadPoint> & roadPoints);
+
+void TestRouteSegments(
+ routing::IndexGraphStarter & starter,
+ routing::AStarAlgorithm<routing::IndexGraphStarter>::Result expectedRouteResult,
+ vector<routing::RoadPoint> const & expectedRoute);
+
+void TestRouteGeometry(
+ routing::IndexGraphStarter & starter,
+ routing::AStarAlgorithm<routing::IndexGraphStarter>::Result expectedRouteResult,
+ vector<m2::PointD> const & expectedRouteGeom);
+} // namespace routing_test
diff --git a/routing/routing_tests/routing_tests.pro b/routing/routing_tests/routing_tests.pro
index 100399f067..49ee873ed0 100644
--- a/routing/routing_tests/routing_tests.pro
+++ b/routing/routing_tests/routing_tests.pro
@@ -21,6 +21,7 @@ INCLUDEPATH += $$ROOT_DIR/3party/jansson/src \
SOURCES += \
../../testing/testingmain.cpp \
+ applying_traffic_test.cpp \
astar_algorithm_test.cpp \
astar_progress_test.cpp \
astar_router_test.cpp \
@@ -28,6 +29,7 @@ SOURCES += \
cross_routing_tests.cpp \
followed_polyline_test.cpp \
index_graph_test.cpp \
+ index_graph_tools.cpp \
nearest_edge_finder_tests.cpp \
online_cross_fetcher_test.cpp \
osrm_router_test.cpp \
@@ -42,4 +44,5 @@ SOURCES += \
vehicle_model_test.cpp \
HEADERS += \
+ index_graph_tools.hpp \
road_graph_builder.hpp \
diff --git a/routing/single_mwm_router.cpp b/routing/single_mwm_router.cpp
index 95461b857f..89648b59b6 100644
--- a/routing/single_mwm_router.cpp
+++ b/routing/single_mwm_router.cpp
@@ -106,6 +106,8 @@ IRouter::ResultCode SingleMwmRouter::DoCalculateRoute(MwmSet::MwmId const & mwmI
RoadPoint const start(startEdge.GetFeatureId().m_index, startEdge.GetSegId());
RoadPoint const finish(finishEdge.GetFeatureId().m_index, finishEdge.GetSegId());
+ EstimatorGuard guard(mwmId, *m_estimator);
+
IndexGraph graph(GeometryLoader::Create(
m_index, mwmId, m_vehicleModelFactory->GetVehicleModelForCountry(country)),
m_estimator);
@@ -210,16 +212,17 @@ bool SingleMwmRouter::LoadIndex(MwmSet::MwmId const & mwmId, string const & coun
}
// static
-unique_ptr<SingleMwmRouter> SingleMwmRouter::CreateCarRouter(Index const & index)
+unique_ptr<SingleMwmRouter> SingleMwmRouter::CreateCarRouter(
+ Index const & index, traffic::TrafficCache const & trafficCache)
{
auto vehicleModelFactory = make_shared<CarModelFactory>();
// @TODO Bicycle turn generation engine is used now. It's ok for the time being.
// But later a special car turn generation engine should be implemented.
auto directionsEngine = make_unique<BicycleDirectionsEngine>(index);
- auto estimator = EdgeEstimator::CreateForCar(*vehicleModelFactory->GetVehicleModel());
+ auto estimator = EdgeEstimator::CreateForCar(*vehicleModelFactory->GetVehicleModel(), trafficCache);
auto router =
- make_unique<SingleMwmRouter>("astar-bidirectional-car", index, move(vehicleModelFactory),
- estimator, move(directionsEngine));
+ make_unique<SingleMwmRouter>("astar-bidirectional-car", index,
+ move(vehicleModelFactory), estimator, move(directionsEngine));
return router;
}
} // namespace routing
diff --git a/routing/single_mwm_router.hpp b/routing/single_mwm_router.hpp
index 96cd241453..fbc2413211 100644
--- a/routing/single_mwm_router.hpp
+++ b/routing/single_mwm_router.hpp
@@ -7,6 +7,7 @@
#include "routing/vehicle_model.hpp"
#include "indexer/index.hpp"
+#include "indexer/mwm_set.hpp"
#include "std/shared_ptr.hpp"
#include "std/unique_ptr.hpp"
@@ -31,7 +32,8 @@ public:
m2::PointD const & finalPoint, RouterDelegate const & delegate,
Route & route);
- static unique_ptr<SingleMwmRouter> CreateCarRouter(Index const & index);
+ static unique_ptr<SingleMwmRouter> CreateCarRouter(Index const & index,
+ traffic::TrafficCache const & trafficCache);
private:
IRouter::ResultCode DoCalculateRoute(MwmSet::MwmId const & mwmId, m2::PointD const & startPoint,
diff --git a/traffic/traffic.pro b/traffic/traffic.pro
index ecacd5f855..c02074c080 100644
--- a/traffic/traffic.pro
+++ b/traffic/traffic.pro
@@ -8,8 +8,10 @@ include($$ROOT_DIR/common.pri)
SOURCES += \
speed_groups.cpp \
+ traffic_cache.cpp \
traffic_info.cpp \
HEADERS += \
speed_groups.hpp \
+ traffic_cache.hpp \
traffic_info.hpp \
diff --git a/traffic/traffic_cache.cpp b/traffic/traffic_cache.cpp
new file mode 100644
index 0000000000..ec0373b7e6
--- /dev/null
+++ b/traffic/traffic_cache.cpp
@@ -0,0 +1,23 @@
+#include "traffic/traffic_cache.hpp"
+
+namespace traffic
+{
+void TrafficCache::Set(TrafficInfo && info)
+{
+ MwmSet::MwmId const mwmId = info.GetMwmId();
+ m_trafficInfo[mwmId] = make_shared<TrafficInfo>(move(info));
+}
+
+void TrafficCache::Remove(MwmSet::MwmId const & mwmId) { m_trafficInfo.erase(mwmId); }
+
+shared_ptr<TrafficInfo> TrafficCache::GetTrafficInfo(MwmSet::MwmId const & mwmId) const
+{
+ auto it = m_trafficInfo.find(mwmId);
+
+ if (it == m_trafficInfo.cend())
+ return shared_ptr<TrafficInfo>();
+ return it->second;
+}
+
+void TrafficCache::Clear() { m_trafficInfo.clear(); }
+} // namespace traffic
diff --git a/traffic/traffic_cache.hpp b/traffic/traffic_cache.hpp
new file mode 100644
index 0000000000..ba79312a6f
--- /dev/null
+++ b/traffic/traffic_cache.hpp
@@ -0,0 +1,27 @@
+#pragma once
+#include "traffic/traffic_info.hpp"
+
+#include "indexer/mwm_set.hpp"
+
+#include "std/map.hpp"
+#include "std/shared_ptr.hpp"
+
+namespace traffic
+{
+class TrafficCache
+{
+public:
+ TrafficCache() : m_trafficInfo() {}
+ virtual ~TrafficCache() = default;
+
+ virtual shared_ptr<traffic::TrafficInfo> GetTrafficInfo(MwmSet::MwmId const & mwmId) const;
+
+protected:
+ void Set(traffic::TrafficInfo && info);
+ void Remove(MwmSet::MwmId const & mwmId);
+ void Clear();
+
+private:
+ map<MwmSet::MwmId, shared_ptr<traffic::TrafficInfo>> m_trafficInfo;
+};
+} // namespace traffic
diff --git a/traffic/traffic_info.cpp b/traffic/traffic_info.cpp
index e02c00e900..879fe7a9cf 100644
--- a/traffic/traffic_info.cpp
+++ b/traffic/traffic_info.cpp
@@ -77,6 +77,14 @@ TrafficInfo::TrafficInfo(MwmSet::MwmId const & mwmId, int64_t currentDataVersion
, m_currentDataVersion(currentDataVersion)
{}
+// static
+TrafficInfo TrafficInfo::BuildForTesting(Coloring && coloring)
+{
+ TrafficInfo info;
+ info.m_coloring = move(coloring);
+ return info;
+}
+
bool TrafficInfo::ReceiveTrafficData()
{
auto const & info = m_mwmId.GetInfo();
diff --git a/traffic/traffic_info.hpp b/traffic/traffic_info.hpp
index a07e4d8cc4..bafa0a4fa5 100644
--- a/traffic/traffic_info.hpp
+++ b/traffic/traffic_info.hpp
@@ -6,6 +6,7 @@
#include "std/cstdint.hpp"
#include "std/map.hpp"
+#include "std/shared_ptr.hpp"
#include "std/vector.hpp"
namespace traffic
@@ -67,6 +68,8 @@ public:
TrafficInfo(MwmSet::MwmId const & mwmId, int64_t currentDataVersion);
+ static TrafficInfo BuildForTesting(Coloring && coloring);
+
// Fetches the latest traffic data from the server and updates the coloring.
// Construct the url by passing an MwmId.
// *NOTE* This method must not be called on the UI thread.
@@ -90,4 +93,14 @@ private:
Availability m_availability = Availability::Unknown;
int64_t m_currentDataVersion = 0;
};
+
+class TrafficObserver
+{
+public:
+ virtual ~TrafficObserver() = default;
+
+ virtual void OnTrafficEnabled(bool enable) = 0;
+ virtual void OnTrafficInfoAdded(traffic::TrafficInfo && info) = 0;
+ virtual void OnTrafficInfoRemoved(MwmSet::MwmId const & mwmId) = 0;
+};
} // namespace traffic