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:
authorMikhail Gorbushin <m.gorbushin@corp.mail.ru>2019-02-16 19:53:09 +0300
committerVladimir Byko-Ianko <bykoianko@gmail.com>2019-03-13 14:08:56 +0300
commitc8a788c0418324bb127346eb3703c6092db2c5ea (patch)
tree39bc90199e91f9e27842f20400ef015e1fc6e940 /routing
parentbf44a88f98d60143b66cecf0fa172ad2159aed5e (diff)
[routing] Add core implementation of routing with avoiding different types of road
Diffstat (limited to 'routing')
-rw-r--r--routing/geometry.cpp11
-rw-r--r--routing/geometry.hpp9
-rw-r--r--routing/index_graph.cpp17
-rw-r--r--routing/index_graph.hpp5
-rw-r--r--routing/index_graph_loader.cpp16
-rw-r--r--routing/index_graph_loader.hpp3
-rw-r--r--routing/index_graph_starter.cpp11
-rw-r--r--routing/index_graph_starter.hpp2
-rw-r--r--routing/index_graph_starter_joints.cpp15
-rw-r--r--routing/index_graph_starter_joints.hpp2
-rw-r--r--routing/index_router.cpp236
-rw-r--r--routing/online_absent_fetcher.hpp1
-rw-r--r--routing/route.hpp8
-rw-r--r--routing/routing_options.cpp127
-rw-r--r--routing/routing_options.hpp31
-rw-r--r--routing/routing_tests/CMakeLists.txt1
-rw-r--r--routing/routing_tests/routing_options_tests.cpp51
-rw-r--r--routing/single_vehicle_world_graph.cpp19
-rw-r--r--routing/single_vehicle_world_graph.hpp7
-rw-r--r--routing/turns_notification_manager.cpp5
-rw-r--r--routing/world_graph.cpp12
-rw-r--r--routing/world_graph.hpp6
22 files changed, 484 insertions, 111 deletions
diff --git a/routing/geometry.cpp b/routing/geometry.cpp
index c53e3db179..e975e60977 100644
--- a/routing/geometry.cpp
+++ b/routing/geometry.cpp
@@ -3,9 +3,12 @@
#include "routing/city_roads.hpp"
#include "routing/maxspeeds.hpp"
#include "routing/routing_exceptions.hpp"
+#include "routing/routing_options.hpp"
#include "indexer/altitude_loader.hpp"
+#include "indexer/classificator.hpp"
#include "indexer/data_source.hpp"
+#include "indexer/ftypes_matcher.hpp"
#include "geometry/mercator.hpp"
@@ -159,6 +162,14 @@ void RoadGeometry::Load(VehicleModelInterface const & vehicleModel, FeatureType
m_backwardSpeed = vehicleModel.GetSpeed(feature, {false /* forward */, inCity, maxspeed});
m_isPassThroughAllowed = vehicleModel.IsPassThroughAllowed(feature);
+ feature::TypesHolder types(feature);
+ auto const & optionsClassfier = RoutingOptionsClassifier::Instance();
+ for (uint32_t type : types)
+ {
+ if (auto const it = optionsClassfier.Get(type))
+ m_routingOptions.Add(*it);
+ }
+
m_junctions.clear();
m_junctions.reserve(feature.GetPointsCount());
for (size_t i = 0; i < feature.GetPointsCount(); ++i)
diff --git a/routing/geometry.hpp b/routing/geometry.hpp
index 6912e72120..58b84265bf 100644
--- a/routing/geometry.hpp
+++ b/routing/geometry.hpp
@@ -4,6 +4,7 @@
#include "routing/maxspeeds.hpp"
#include "routing/road_graph.hpp"
#include "routing/road_point.hpp"
+#include "routing/routing_options.hpp"
#include "routing_common/maxspeed_conversion.hpp"
#include "routing_common/vehicle_model.hpp"
@@ -65,6 +66,13 @@ public:
m_isPassThroughAllowed = passThroughAllowed;
}
+ bool SuitableForOptions(RoutingOptions avoidRoutingOptions) const
+ {
+ return (avoidRoutingOptions.GetOptions() & m_routingOptions.GetOptions()) == 0;
+ }
+
+ RoutingOptions GetRoutingOptions() const { return m_routingOptions; }
+
private:
buffer_vector<Junction, 32> m_junctions;
VehicleModelInterface::SpeedKMpH m_forwardSpeed;
@@ -72,6 +80,7 @@ private:
bool m_isOneWay = false;
bool m_valid = false;
bool m_isPassThroughAllowed = false;
+ RoutingOptions m_routingOptions;
};
struct AttrLoader
diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp
index 41cc5175a1..b9153ccfa7 100644
--- a/routing/index_graph.cpp
+++ b/routing/index_graph.cpp
@@ -1,12 +1,16 @@
#include "routing/index_graph.hpp"
#include "routing/restrictions_serialization.hpp"
+#include "routing/routing_options.hpp"
+
+#include "platform/settings.hpp"
#include "base/assert.hpp"
#include "base/checked_cast.hpp"
#include "base/exception.hpp"
#include <algorithm>
+#include <cstdlib>
#include <limits>
namespace
@@ -57,8 +61,11 @@ bool IsRestricted(RestrictionVec const & restrictions, Segment const & u, Segmen
namespace routing
{
-IndexGraph::IndexGraph(shared_ptr<Geometry> geometry, shared_ptr<EdgeEstimator> estimator)
- : m_geometry(geometry), m_estimator(move(estimator))
+IndexGraph::IndexGraph(shared_ptr<Geometry> geometry, shared_ptr<EdgeEstimator> estimator,
+ RoutingOptions routingOptions)
+ : m_geometry(geometry),
+ m_estimator(move(estimator)),
+ m_avoidRoutingOptions(routingOptions)
{
CHECK(m_geometry, ());
CHECK(m_estimator, ());
@@ -205,6 +212,9 @@ void IndexGraph::GetNeighboringEdges(Segment const & from, RoadPoint const & rp,
if (!road.IsValid())
return;
+ if (!road.SuitableForOptions(m_avoidRoutingOptions))
+ return;
+
bool const bidirectional = !road.IsOneWay();
if ((isOutgoing || bidirectional) && rp.GetPointId() + 1 < road.GetPointsCount())
@@ -237,6 +247,9 @@ void IndexGraph::GetSegmentCandidateForJoint(Segment const & parent, bool isOutg
if (!road.IsValid())
return;
+ if (!road.SuitableForOptions(m_avoidRoutingOptions))
+ return;
+
bool const bidirectional = !road.IsOneWay();
auto const pointId = rp.GetPointId();
diff --git a/routing/index_graph.hpp b/routing/index_graph.hpp
index 225aabdd92..cd31179a2d 100644
--- a/routing/index_graph.hpp
+++ b/routing/index_graph.hpp
@@ -9,6 +9,7 @@
#include "routing/road_access.hpp"
#include "routing/road_index.hpp"
#include "routing/road_point.hpp"
+#include "routing/routing_options.hpp"
#include "routing/segment.hpp"
#include "geometry/point2d.hpp"
@@ -32,7 +33,8 @@ public:
using Weight = RouteWeight;
IndexGraph() = default;
- IndexGraph(shared_ptr<Geometry> geometry, shared_ptr<EdgeEstimator> estimator);
+ IndexGraph(shared_ptr<Geometry> geometry, shared_ptr<EdgeEstimator> estimator,
+ RoutingOptions routingOptions = RoutingOptions());
// Put outgoing (or ingoing) egdes for segment to the 'edges' vector.
void GetEdgeList(Segment const & segment, bool isOutgoing, vector<SegmentEdge> & edges);
@@ -113,5 +115,6 @@ private:
JointIndex m_jointIndex;
RestrictionVec m_restrictions;
RoadAccess m_roadAccess;
+ RoutingOptions m_avoidRoutingOptions;
};
} // namespace routing
diff --git a/routing/index_graph_loader.cpp b/routing/index_graph_loader.cpp
index 5dba082f86..c57adccc2b 100644
--- a/routing/index_graph_loader.cpp
+++ b/routing/index_graph_loader.cpp
@@ -30,7 +30,8 @@ class IndexGraphLoaderImpl final : public IndexGraphLoader
public:
IndexGraphLoaderImpl(VehicleType vehicleType, bool loadAltitudes, shared_ptr<NumMwmIds> numMwmIds,
shared_ptr<VehicleModelFactoryInterface> vehicleModelFactory,
- shared_ptr<EdgeEstimator> estimator, DataSource & dataSource);
+ shared_ptr<EdgeEstimator> estimator, DataSource & dataSource,
+ RoutingOptions routingOptions = RoutingOptions());
// IndexGraphLoader overrides:
Geometry & GetGeometry(NumMwmId numMwmId) override;
@@ -59,18 +60,22 @@ private:
unordered_map<NumMwmId, map<SegmentCoord, vector<RouteSegment::SpeedCamera>>> m_cachedCameras;
decltype(m_cachedCameras)::iterator ReceiveSpeedCamsFromMwm(NumMwmId numMwmId);
+
+ RoutingOptions m_avoidRoutingOptions = RoutingOptions();
};
IndexGraphLoaderImpl::IndexGraphLoaderImpl(
VehicleType vehicleType, bool loadAltitudes, shared_ptr<NumMwmIds> numMwmIds,
shared_ptr<VehicleModelFactoryInterface> vehicleModelFactory,
- shared_ptr<EdgeEstimator> estimator, DataSource & dataSource)
+ shared_ptr<EdgeEstimator> estimator, DataSource & dataSource,
+ RoutingOptions routingOptions)
: m_vehicleType(vehicleType)
, m_loadAltitudes(loadAltitudes)
, m_dataSource(dataSource)
, m_numMwmIds(numMwmIds)
, m_vehicleModelFactory(vehicleModelFactory)
, m_estimator(estimator)
+ , m_avoidRoutingOptions(routingOptions)
{
CHECK(m_numMwmIds, ());
CHECK(m_vehicleModelFactory, ());
@@ -198,7 +203,7 @@ IndexGraphLoaderImpl::GraphAttrs & IndexGraphLoaderImpl::CreateIndexGraph(
if (!handle.IsAlive())
MYTHROW(RoutingException, ("Can't get mwm handle for", file));
- graph.m_indexGraph = make_unique<IndexGraph>(graph.m_geometry, m_estimator);
+ graph.m_indexGraph = make_unique<IndexGraph>(graph.m_geometry, m_estimator, m_avoidRoutingOptions);
base::Timer timer;
MwmValue const & mwmValue = *handle.GetValue<MwmValue>();
DeserializeIndexGraph(mwmValue, m_vehicleType, *graph.m_indexGraph);
@@ -237,10 +242,11 @@ namespace routing
unique_ptr<IndexGraphLoader> IndexGraphLoader::Create(
VehicleType vehicleType, bool loadAltitudes, shared_ptr<NumMwmIds> numMwmIds,
shared_ptr<VehicleModelFactoryInterface> vehicleModelFactory,
- shared_ptr<EdgeEstimator> estimator, DataSource & dataSource)
+ shared_ptr<EdgeEstimator> estimator, DataSource & dataSource,
+ RoutingOptions routingOptions)
{
return make_unique<IndexGraphLoaderImpl>(vehicleType, loadAltitudes, numMwmIds, vehicleModelFactory,
- estimator, dataSource);
+ estimator, dataSource, routingOptions);
}
void DeserializeIndexGraph(MwmValue const & mwmValue, VehicleType vehicleType, IndexGraph & graph)
diff --git a/routing/index_graph_loader.hpp b/routing/index_graph_loader.hpp
index 44077ad6e1..110f24c661 100644
--- a/routing/index_graph_loader.hpp
+++ b/routing/index_graph_loader.hpp
@@ -31,7 +31,8 @@ public:
static std::unique_ptr<IndexGraphLoader> Create(
VehicleType vehicleType, bool loadAltitudes, std::shared_ptr<NumMwmIds> numMwmIds,
std::shared_ptr<VehicleModelFactoryInterface> vehicleModelFactory,
- std::shared_ptr<EdgeEstimator> estimator, DataSource & dataSource);
+ std::shared_ptr<EdgeEstimator> estimator, DataSource & dataSource,
+ RoutingOptions routingOptions = RoutingOptions());
};
void DeserializeIndexGraph(MwmValue const & mwmValue, VehicleType vehicleType, IndexGraph & graph);
diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp
index 8eeffb7e4d..82e73237b1 100644
--- a/routing/index_graph_starter.cpp
+++ b/routing/index_graph_starter.cpp
@@ -53,7 +53,8 @@ size_t IndexGraphStarter::GetRouteNumPoints(vector<Segment> const & segments)
}
IndexGraphStarter::IndexGraphStarter(FakeEnding const & startEnding,
- FakeEnding const & finishEnding, uint32_t fakeNumerationStart,
+ FakeEnding const & finishEnding,
+ uint32_t fakeNumerationStart,
bool strictForward, WorldGraph & graph)
: m_graph(graph)
{
@@ -124,6 +125,11 @@ m2::PointD const & IndexGraphStarter::GetPoint(Segment const & segment, bool fro
return GetJunction(segment, front).GetPoint();
}
+bool IndexGraphStarter::IsRoutingOptionsGood(Segment const & segment) const
+{
+ return m_graph.IsRoutingOptionsGood(segment);
+}
+
set<NumMwmId> IndexGraphStarter::GetMwms() const
{
set<NumMwmId> mwms;
@@ -165,6 +171,9 @@ void IndexGraphStarter::GetEdgesList(Segment const & segment, bool isOutgoing,
// If mode is LeapsOnly we need to connect start/finish segment to transitions.
if (m_graph.GetMode() == WorldGraph::Mode::LeapsOnly)
{
+ if (segment.IsRealSegment() && !IsRoutingOptionsGood(segment))
+ return;
+
// Ingoing edges listing is not supported in LeapsOnly mode because we do not have enough
// information to calculate |segment| weight. See https://jira.mail.ru/browse/MAPSME-5743 for details.
CHECK(isOutgoing, ("Ingoing edges listing is not supported in LeapsOnly mode."));
diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp
index a3fd11df14..5cfe29da05 100644
--- a/routing/index_graph_starter.hpp
+++ b/routing/index_graph_starter.hpp
@@ -65,6 +65,7 @@ public:
Junction const & GetJunction(Segment const & segment, bool front) const;
Junction const & GetRouteJunction(std::vector<Segment> const & route, size_t pointIndex) const;
m2::PointD const & GetPoint(Segment const & segment, bool front) const;
+ bool IsRoutingOptionsGood(Segment const & segment) const;
uint32_t GetNumFakeSegments() const
{
// Maximal number of fake segments in fake graph is numeric_limits<uint32_t>::max()
@@ -162,5 +163,6 @@ private:
Ending m_finish;
double m_startToFinishDistanceM;
FakeGraph<Segment, FakeVertex> m_fake;
+ RoutingOptions m_avoidRoutingOptions;
};
} // namespace routing
diff --git a/routing/index_graph_starter_joints.cpp b/routing/index_graph_starter_joints.cpp
index 4c1db67525..5b93579956 100644
--- a/routing/index_graph_starter_joints.cpp
+++ b/routing/index_graph_starter_joints.cpp
@@ -398,4 +398,19 @@ bool IndexGraphStarterJoints::IsJoint(Segment const & segment, bool fromStart)
return m_starter.GetGraph().GetIndexGraph(segment.GetMwmId())
.IsJoint(segment.GetRoadPoint(fromStart));
}
+
+void IndexGraphStarterJoints::Reset()
+{
+ m_startJoint = JointSegment();
+ m_endJoint = JointSegment();
+ m_startSegment = Segment();
+ m_endSegment = Segment();
+ m_savedWeight.clear();
+ m_fakeJointSegments.clear();
+ m_reconstructedFakeJoints.clear();
+ m_startOutEdges.clear();
+ m_endOutEdges.clear();
+ m_fakeId = 0;
+ m_init = false;
+}
} // namespace routing
diff --git a/routing/index_graph_starter_joints.hpp b/routing/index_graph_starter_joints.hpp
index 3ea231481b..cc61b03929 100644
--- a/routing/index_graph_starter_joints.hpp
+++ b/routing/index_graph_starter_joints.hpp
@@ -53,6 +53,8 @@ public:
/// \brief Reconstructs JointSegment by segment after building the route.
std::vector<Segment> ReconstructJoint(JointSegment const & joint);
+ void Reset();
+
private:
static auto constexpr kInvisibleId = std::numeric_limits<uint32_t>::max() - 2;
diff --git a/routing/index_router.cpp b/routing/index_router.cpp
index 4e005979a6..4c372678f4 100644
--- a/routing/index_router.cpp
+++ b/routing/index_router.cpp
@@ -14,6 +14,7 @@
#include "routing/route.hpp"
#include "routing/routing_exceptions.hpp"
#include "routing/routing_helpers.hpp"
+#include "routing/routing_options.hpp"
#include "routing/single_vehicle_world_graph.hpp"
#include "routing/speed_camera_prohibition.hpp"
#include "routing/transit_info.hpp"
@@ -43,6 +44,8 @@
#include <algorithm>
#include <cstdlib>
+#include <deque>
+#include <iterator>
#include <map>
#include <utility>
@@ -611,6 +614,7 @@ RouterResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoints,
set<NumMwmId> const mwmIds = starter.GetMwms();
RouterResultCode const result = FindPath<IndexGraphStarter>(params, mwmIds, routingResult);
+
if (result != RouterResultCode::NoError)
return result;
@@ -621,6 +625,7 @@ RouterResultCode IndexRouter::CalculateSubroute(Checkpoints const & checkpoints,
if (leapsResult != RouterResultCode::NoError)
return leapsResult;
}
+
LOG(LINFO, ("Time for routing in mode:", starter.GetGraph().GetMode(), "is",
timer.ElapsedNano() / 1e6, "ms"));
@@ -739,18 +744,31 @@ RouterResultCode IndexRouter::AdjustRoute(Checkpoints const & checkpoints,
unique_ptr<WorldGraph> IndexRouter::MakeWorldGraph()
{
+ RoutingOptions routingOptions;
+ if (m_vehicleType == VehicleType::Car)
+ {
+ routingOptions = RoutingOptions::LoadCarOptionsFromSettings();
+ LOG(LINFO, ("Avoid next roads:", routingOptions));
+ }
+
auto crossMwmGraph = make_unique<CrossMwmGraph>(
m_numMwmIds, m_numMwmTree, m_vehicleModelFactory,
m_vehicleType == VehicleType::Transit ? VehicleType::Pedestrian : m_vehicleType,
m_countryRectFn, m_dataSource);
+
auto indexGraphLoader = IndexGraphLoader::Create(
m_vehicleType == VehicleType::Transit ? VehicleType::Pedestrian : m_vehicleType,
- m_loadAltitudes, m_numMwmIds, m_vehicleModelFactory, m_estimator, m_dataSource);
+ m_loadAltitudes, m_numMwmIds, m_vehicleModelFactory, m_estimator, m_dataSource,
+ routingOptions);
+
if (m_vehicleType != VehicleType::Transit)
{
- return make_unique<SingleVehicleWorldGraph>(move(crossMwmGraph), move(indexGraphLoader),
- m_estimator);
+ auto graph = make_unique<SingleVehicleWorldGraph>(move(crossMwmGraph), move(indexGraphLoader),
+ m_estimator);
+ graph->SetRoutingOptions(routingOptions);
+ return graph;
}
+
auto transitGraphLoader = TransitGraphLoader::Create(m_dataSource, m_numMwmIds, m_estimator);
return make_unique<TransitWorldGraph>(move(crossMwmGraph), move(indexGraphLoader),
move(transitGraphLoader), m_estimator);
@@ -816,6 +834,7 @@ RouterResultCode IndexRouter::ProcessLeapsJoints(vector<Segment> const & input,
CHECK_GREATER_OR_EQUAL(input.size(), 4,
("Route in LeapsOnly mode must have at least start and finish leaps."));
+ LOG(LINFO, ("Start process leaps with Joints."));
WorldGraph & worldGraph = starter.GetGraph();
// For all leaps except the first leap which connects start to mwm exit in LeapsOnly mode we need
@@ -828,14 +847,14 @@ RouterResultCode IndexRouter::ProcessLeapsJoints(vector<Segment> const & input,
// to the correct start mwm exit and then we have normal route.
// |input| mwm ids for such case look like
// { fake, startId, otherId, otherId, startId, startId, .. pairs of ids for other leaps .. , finishId, fake}.
- // To avoid this behavior we collapse all leaps from start to last occurrence of startId to one leap and
+ // To avoid this behavior we collapse all leaps from start to last occurrence of startId to one leap and
// use WorldGraph with NoLeaps mode to proccess these leap. Unlike SingleMwm mode used to process ordinary leaps
// NoLeaps allows to use all mwms so if we really need to visit other mwm we will.
auto const firstMwmId = input[1].GetMwmId();
auto const startLeapEndReverseIt = find_if(input.rbegin() + 2, input.rend(),
[firstMwmId](Segment const & s) { return s.GetMwmId() == firstMwmId; });
auto const startLeapEndIt = startLeapEndReverseIt.base() - 1;
- auto const startLeapEnd = distance(input.begin(), startLeapEndIt);
+ auto const startLeapEnd = static_cast<size_t>(distance(input.begin(), startLeapEndIt));
// The last leap processed the same way. See the comment above.
auto const lastMwmId = input[input.size() - 2].GetMwmId();
@@ -843,83 +862,160 @@ RouterResultCode IndexRouter::ProcessLeapsJoints(vector<Segment> const & input,
[lastMwmId](Segment const & s) { return s.GetMwmId() == lastMwmId; });
auto const finishLeapStart = static_cast<size_t>(distance(input.begin(), finishLeapStartIt));
- for (size_t i = 0; i <= finishLeapStart; ++i)
+ auto checkLength = [&starter](RouteWeight const & weight) {
+ return starter.CheckLength(weight);
+ };
+
+ auto fillMwmIds = [&](size_t start, size_t end, set<NumMwmId> & mwmIds)
{
- auto const & current = input[i];
+ CHECK_LESS(start, input.size(), ());
+ CHECK_LESS(end, input.size(), ());
+ mwmIds.clear();
+
+ if (start == startLeapEnd)
+ mwmIds = starter.GetStartMwms();
+
+ if (end == finishLeapStart)
+ mwmIds = starter.GetFinishMwms();
+
+ for (size_t i = start; i <= end; ++i)
+ {
+ if (input[i].GetMwmId() != kFakeNumMwmId)
+ mwmIds.insert(input[i].GetMwmId());
+ }
+ };
+
+ set<NumMwmId> mwmIds;
+ IndexGraphStarterJoints jointStarter(starter);
+ auto const runAStarAlgorithm = [&](size_t start, size_t end, WorldGraph::Mode mode,
+ RoutingResult<JointSegment, RouteWeight> & routingResult)
+ {
// Clear previous loaded graphs to not spend too much memory at one time.
worldGraph.ClearCachedGraphs();
- auto checkLength = [&starter](RouteWeight const & weight) {
- return starter.CheckLength(weight);
- };
+ // Clear previous info about route.
+ routingResult.Clear();
+ jointStarter.Reset();
- RouterResultCode result = RouterResultCode::InternalError;
- RoutingResult<JointSegment, RouteWeight> routingResult;
- IndexGraphStarterJoints jointStarter(starter);
- if (i == 0 || i == finishLeapStart)
+ worldGraph.SetMode(mode);
+ jointStarter.Init(input[start], input[end]);
+
+ fillMwmIds(start, end, mwmIds);
+
+ AStarAlgorithm<IndexGraphStarterJoints>::Params params(
+ jointStarter, jointStarter.GetStartJoint(), jointStarter.GetFinishJoint(),
+ nullptr /* prevRoute */, delegate,
+ {} /* onVisitedVertexCallback */, checkLength);
+
+ return FindPath<IndexGraphStarterJoints>(params, mwmIds, routingResult);
+ };
+
+ deque<vector<Segment>> paths;
+ size_t prevStart = numeric_limits<size_t>::max();
+ auto const tryBuildRoute = [&](size_t start, size_t end, WorldGraph::Mode mode,
+ RoutingResult<JointSegment, RouteWeight> & routingResult)
+ {
+ RouterResultCode const result = runAStarAlgorithm(start, end, mode, routingResult);
+ if (result == RouterResultCode::NoError)
{
- bool const isStartLeap = i == 0;
- i = isStartLeap ? startLeapEnd : input.size() - 1;
- CHECK_LESS(static_cast<size_t>(i), input.size(), ());
- auto const & next = input[i];
+ vector<Segment> subroute = ProcessJoints(routingResult.m_path, jointStarter);
- set<NumMwmId> mwmIds;
- if (isStartLeap)
- {
- mwmIds = starter.GetStartMwms();
- mwmIds.insert(next.GetMwmId());
- }
- else
- {
- mwmIds = starter.GetFinishMwms();
- mwmIds.insert(current.GetMwmId());
- }
+ CHECK(!subroute.empty(), ());
+ if (start == prevStart && !paths.empty())
+ paths.pop_back();
- worldGraph.SetMode(WorldGraph::Mode::Joints);
- jointStarter.Init(current, next);
- AStarAlgorithm<IndexGraphStarterJoints>::Params params(
- jointStarter, jointStarter.GetStartJoint(), jointStarter.GetFinishJoint(),
- nullptr /* prevRoute */, delegate,
- {} /* onVisitedVertexCallback */, checkLength);
- result = FindPath<IndexGraphStarterJoints>(params, mwmIds, routingResult);
+ ASSERT(!subroute.empty(), ());
+ paths.emplace_back(vector<Segment>(dropFirstSegment ? subroute.cbegin() + 1 : subroute.cbegin(), subroute.cend()));
+
+ dropFirstSegment = true;
+ prevStart = start;
+ return true;
+ }
+
+ LOG(LINFO, ("Can not find path",
+ "from:",
+ MercatorBounds::ToLatLon(starter.GetPoint(input[start], input[start].IsForward())),
+ "to:",
+ MercatorBounds::ToLatLon(starter.GetPoint(input[end], input[end].IsForward()))));
+
+ return false;
+ };
+
+ size_t lastPrev = 0;
+ size_t prev = 0;
+ size_t next = 0;
+ RoutingResult<JointSegment, RouteWeight> routingResult;
+
+ for (size_t i = startLeapEnd; i <= finishLeapStart; ++i)
+ {
+ if (i == startLeapEnd)
+ {
+ prev = 0;
+ next = i;
+ }
+ else if (i == finishLeapStart)
+ {
+ prev = i;
+ next = input.size() - 1;
}
else
{
- ++i;
- CHECK_LESS(static_cast<size_t>(i), input.size(), ());
- auto const & next = input[i];
-
- CHECK(!IndexGraphStarter::IsFakeSegment(current), ());
- CHECK(!IndexGraphStarter::IsFakeSegment(next), ());
- CHECK_EQUAL(
- current.GetMwmId(), next.GetMwmId(),
- ("Different mwm ids for leap enter and exit, i:", i, "size of input:", input.size()));
-
- // Single mwm route.
- worldGraph.SetMode(WorldGraph::Mode::JointSingleMwm);
- // It's not start-to-mwm-exit leap, we already have its first segment in previous mwm.
- dropFirstSegment = true;
+ prev = i;
+ next = i + 1;
+ }
+
+ if (!tryBuildRoute(prev, next, WorldGraph::Mode::JointSingleMwm, routingResult))
+ {
+ auto const prevPoint = starter.GetPoint(input[next], true);
+ // |next + 1| - is the twin of |next|
+ // |next + 2| - is the next exit.
+ while (next + 2 < finishLeapStart && next != finishLeapStart)
+ {
+ auto const point = starter.GetPoint(input[next + 2], true);
+ double const distBetweenExistsMeters = MercatorBounds::DistanceOnEarth(point, prevPoint);
- jointStarter.Init(current, next);
- AStarAlgorithm<IndexGraphStarterJoints>::Params params(
- jointStarter, jointStarter.GetStartJoint(), jointStarter.GetFinishJoint(),
- nullptr /* prevRoute */, delegate,
- {} /* onVisitedVertexCallback */, checkLength);
+ static double constexpr kMinDistBetweenExitsM = 100000; // 100 km
+ if (distBetweenExistsMeters > kMinDistBetweenExitsM)
+ break;
- set<NumMwmId> const mwmIds = {current.GetMwmId(), next.GetMwmId()};
- result = FindPath<IndexGraphStarterJoints>(params, mwmIds, routingResult);
+ LOG(LINFO, ("Exit:", MercatorBounds::ToLatLon(point),
+ "too close(", distBetweenExistsMeters / 1000, "km ), try get next."));
+ next += 2;
+ }
+
+ if (next + 2 > finishLeapStart || next == finishLeapStart)
+ next = input.size() - 1;
+ else
+ next += 2;
+
+ if (!tryBuildRoute(prev, next, WorldGraph::Mode::Joints, routingResult))
+ {
+ // Already in start
+ if (prev == 0)
+ return RouterResultCode::RouteNotFound;
+
+ prev = lastPrev;
+ if (prev == 0)
+ dropFirstSegment = false;
+
+ CHECK_GREATER_OR_EQUAL(prev, 0, ());
+ if (!tryBuildRoute(prev, next, WorldGraph::Mode::Joints, routingResult))
+ return RouterResultCode::RouteNotFound;
+ }
}
- if (result != RouterResultCode::NoError)
- return result;
+ lastPrev = prev;
+ i = next;
+ }
- vector<Segment> subroute;
- subroute = ProcessJoints(routingResult.m_path, jointStarter);
- CHECK(!subroute.empty(), ());
+ while (!paths.empty())
+ {
+ using Iterator = vector<Segment>::iterator;
output.insert(output.end(),
- dropFirstSegment ? subroute.cbegin() + 1 : subroute.cbegin(), subroute.cend());
- dropFirstSegment = true;
+ move_iterator<Iterator>(paths.front().begin()),
+ move_iterator<Iterator>(paths.front().end()));
+ paths.pop_front();
}
return RouterResultCode::NoError;
@@ -964,10 +1060,16 @@ RouterResultCode IndexRouter::RedressRoute(vector<Segment> const & segments,
// Removing speed cameras from the route with method AreSpeedCamerasProhibited(...)
// at runtime is necessary for maps from Jan 2019 with speed cameras where it's prohibited
// to use them.
- if (m_vehicleType == VehicleType::Car && routeSegment.IsRealSegment()
- && !AreSpeedCamerasProhibited(m_numMwmIds->GetFile(routeSegment.GetSegment().GetMwmId())))
+ if (m_vehicleType == VehicleType::Car)
{
- routeSegment.SetSpeedCameraInfo(worldGraph.GetSpeedCamInfo(routeSegment.GetSegment()));
+ auto const & segment = routeSegment.GetSegment();
+ if (segment.IsRealSegment())
+ {
+ if (!AreSpeedCamerasProhibited(m_numMwmIds->GetFile(segment.GetMwmId())))
+ routeSegment.SetSpeedCameraInfo(worldGraph.GetSpeedCamInfo(segment));
+
+ routeSegment.SetRoadTypes(worldGraph.GetRoutingOptions(segment));
+ }
}
}
diff --git a/routing/online_absent_fetcher.hpp b/routing/online_absent_fetcher.hpp
index 28ea84acf3..6ddfd8ce71 100644
--- a/routing/online_absent_fetcher.hpp
+++ b/routing/online_absent_fetcher.hpp
@@ -7,6 +7,7 @@
#include "base/thread.hpp"
+#include <functional>
#include <memory>
#include <string>
#include <vector>
diff --git a/routing/route.hpp b/routing/route.hpp
index bc687d7a26..f16b2b7b8e 100644
--- a/routing/route.hpp
+++ b/routing/route.hpp
@@ -100,10 +100,10 @@ public:
TransitInfo const & GetTransitInfo() const { return m_transitInfo.Get(); }
void SetSpeedCameraInfo(std::vector<SpeedCamera> && data) { m_speedCameras = std::move(data); }
- bool IsRealSegment() const { return m_segment.IsRealSegment(); }
std::vector<SpeedCamera> const & GetSpeedCams() const { return m_speedCameras; }
- RoutingOptions::Road GetRoadType() const { return m_roadType; }
- void SetRoadType(RoutingOptions::Road road) { m_roadType = road; }
+
+ RoutingOptions GetRoadTypes() const { return m_roadTypes; }
+ void SetRoadTypes(RoutingOptions types) { m_roadTypes = types; }
private:
Segment m_segment;
@@ -137,7 +137,7 @@ private:
// and theirs' max speed.
std::vector<SpeedCamera> m_speedCameras;
- RoutingOptions::Road m_roadType = RoutingOptions::Road::Usual;
+ RoutingOptions m_roadTypes;
};
class Route
diff --git a/routing/routing_options.cpp b/routing/routing_options.cpp
index 5d2863189f..f2aa5c594e 100644
--- a/routing/routing_options.cpp
+++ b/routing/routing_options.cpp
@@ -2,23 +2,33 @@
#include "platform/settings.hpp"
+#include "indexer/classificator.hpp"
+
#include "base/assert.hpp"
+#include "base/checked_cast.hpp"
#include "base/logging.hpp"
#include "base/macros.hpp"
+#include <initializer_list>
#include <sstream>
+#include <utility>
+
+using namespace std;
namespace routing
{
-std::string const RoutingOptions::kAvoidRoutingOptionSettings = "avoid_routing_options";
+
+// RoutingOptions -------------------------------------------------------------------------------------
+
+string const RoutingOptions::kAvoidRoutingOptionSettingsForCar = "avoid_routing_options_car";
// static
-RoutingOptions RoutingOptions::LoadFromSettings()
+RoutingOptions RoutingOptions::LoadCarOptionsFromSettings()
{
- RoadType mode = 0;
- UNUSED_VALUE(settings::Get(kAvoidRoutingOptionSettings, mode));
+ uint32_t mode = 0;
+ UNUSED_VALUE(settings::Get(kAvoidRoutingOptionSettingsForCar, mode));
- return RoutingOptions(mode);
+ return RoutingOptions(base::checked_cast<RoadType>(mode));
}
void RoutingOptions::Add(RoutingOptions::Road type)
@@ -36,38 +46,107 @@ bool RoutingOptions::Has(RoutingOptions::Road type) const
return (m_options & static_cast<RoadType>(type)) != 0;
}
-std::string DebugPrint(RoutingOptions const & routingOptions)
+// RoutingOptionsClassifier ---------------------------------------------------------------------------
+
+RoutingOptionsClassifier::RoutingOptionsClassifier()
{
- std::ostringstream ss;
- ss << "RoutingOptions: {";
+ Classificator const & c = classif();
+
+ initializer_list<pair<vector<string>, RoutingOptions::Road>> const types = {
+ {{"highway", "motorway"}, RoutingOptions::Road::Motorway},
+
+ {{"hwtag", "toll"}, RoutingOptions::Road::Toll},
+
+ {{"route", "ferry"}, RoutingOptions::Road::Ferry},
+ {{"route", "ferry", "motorcar"}, RoutingOptions::Road::Ferry},
+ {{"route", "ferry", "motor_vehicle"}, RoutingOptions::Road::Ferry},
+
+ {{"highway", "track"}, RoutingOptions::Road::Dirty},
+ {{"highway", "road"}, RoutingOptions::Road::Dirty},
+ {{"psurface", "unpaved_bad"}, RoutingOptions::Road::Dirty},
+ {{"psurface", "unpaved_good"}, RoutingOptions::Road::Dirty}
+ };
+
+ for (auto const & data : types)
+ {
+ auto const & stringType = data.first;
+ auto const & optionType = data.second;
+
+ ASSERT_EQUAL(m_data.count(c.GetTypeByPath(stringType)), 0, ());
+ m_data[c.GetTypeByPath(stringType)] = optionType;
+ }
+}
+
+boost::optional<RoutingOptions::Road> RoutingOptionsClassifier::Get(uint32_t type) const
+{
+ auto const it = m_data.find(type);
+ if (it == m_data.cend())
+ return boost::none;
+
+ return it->second;
+}
+
+RoutingOptionsClassifier const & RoutingOptionsClassifier::Instance()
+{
+ static RoutingOptionsClassifier instance;
+ return instance;
+}
+
+RoutingOptions::Road ChooseMainRoutingOptionRoad(RoutingOptions options)
+{
+ if (options.Has(RoutingOptions::Road::Toll))
+ return RoutingOptions::Road::Toll;
- if (routingOptions.Has(RoutingOptions::Road::Usual))
- ss << " | " << DebugPrint(RoutingOptions::Road::Usual);
+ if (options.Has(RoutingOptions::Road::Ferry))
+ return RoutingOptions::Road::Ferry;
- if (routingOptions.Has(RoutingOptions::Road::Toll))
- ss << " | " << DebugPrint(RoutingOptions::Road::Toll);
+ if (options.Has(RoutingOptions::Road::Dirty))
+ return RoutingOptions::Road::Dirty;
- if (routingOptions.Has(RoutingOptions::Road::Motorway))
- ss << " | " << DebugPrint(RoutingOptions::Road::Motorway);
+ if (options.Has(RoutingOptions::Road::Motorway))
+ return RoutingOptions::Road::Motorway;
- if (routingOptions.Has(RoutingOptions::Road::Ferry))
- ss << " | " << DebugPrint(RoutingOptions::Road::Ferry);
+ return RoutingOptions::Road::Usual;
+}
+
+string DebugPrint(RoutingOptions const & routingOptions)
+{
+ ostringstream ss;
+ ss << "RoutingOptions: {";
- if (routingOptions.Has(RoutingOptions::Road::Dirty))
- ss << " | " << DebugPrint(RoutingOptions::Road::Dirty);
+ bool wasAppended = false;
+ auto const append = [&](RoutingOptions::Road road) {
+ if (routingOptions.Has(road))
+ {
+ wasAppended = true;
+ ss << " | " << DebugPrint(road);
+ }
+ };
+
+ append(RoutingOptions::Road::Usual);
+ append(RoutingOptions::Road::Toll);
+ append(RoutingOptions::Road::Motorway);
+ append(RoutingOptions::Road::Ferry);
+ append(RoutingOptions::Road::Dirty);
+
+ if (wasAppended)
+ ss << " | ";
ss << "}";
+
return ss.str();
}
-std::string DebugPrint(RoutingOptions::Road type)
+
+string DebugPrint(RoutingOptions::Road type)
{
switch (type)
{
- case RoutingOptions::Road::Toll: return "toll";
- case RoutingOptions::Road::Motorway: return "motorway";
- case RoutingOptions::Road::Ferry: return "ferry";
- case RoutingOptions::Road::Dirty: return "dirty";
- case RoutingOptions::Road::Usual: return "usual";
+ case RoutingOptions::Road::Toll: return "toll";
+ case RoutingOptions::Road::Motorway: return "motorway";
+ case RoutingOptions::Road::Ferry: return "ferry";
+ case RoutingOptions::Road::Dirty: return "dirty";
+ case RoutingOptions::Road::Usual: return "usual";
+ case RoutingOptions::Road::Max: return "max";
}
UNREACHABLE();
diff --git a/routing/routing_options.hpp b/routing/routing_options.hpp
index 0402a18019..437080de98 100644
--- a/routing/routing_options.hpp
+++ b/routing/routing_options.hpp
@@ -1,15 +1,20 @@
#pragma once
#include <cstdint>
+#include <set>
#include <string>
#include <type_traits>
+#include <unordered_map>
+#include <vector>
+
+#include "boost/optional.hpp"
namespace routing
{
class RoutingOptions
{
public:
- static std::string const kAvoidRoutingOptionSettings;
+ static std::string const kAvoidRoutingOptionSettingsForCar;
enum class Road : uint8_t
{
@@ -17,15 +22,17 @@ public:
Toll = 1u << 1,
Motorway = 1u << 2,
Ferry = 1u << 3,
- Dirty = 1u << 4
+ Dirty = 1u << 4,
+
+ Max = (1u << 4) + 1
};
- using RoadType = std::underlying_type<Road>::type;
+ using RoadType = std::underlying_type_t<Road>;
RoutingOptions() = default;
explicit RoutingOptions(RoadType mask) : m_options(mask) {}
- static RoutingOptions LoadFromSettings();
+ static RoutingOptions LoadCarOptionsFromSettings();
void Add(Road type);
void Remove(Road type);
@@ -37,6 +44,22 @@ private:
RoadType m_options = 0;
};
+class RoutingOptionsClassifier
+{
+public:
+ RoutingOptionsClassifier();
+
+ boost::optional<RoutingOptions::Road> Get(uint32_t type) const;
+ static RoutingOptionsClassifier const & Instance();
+
+private:
+ std::unordered_map<uint32_t, RoutingOptions::Road> m_data;
+};
+
+RoutingOptions::Road ChooseMainRoutingOptionRoad(RoutingOptions options);
+
std::string DebugPrint(RoutingOptions const & routingOptions);
std::string DebugPrint(RoutingOptions::Road type);
+
} // namespace routing
+
diff --git a/routing/routing_tests/CMakeLists.txt b/routing/routing_tests/CMakeLists.txt
index 03d9d637d4..adf4e3cdf6 100644
--- a/routing/routing_tests/CMakeLists.txt
+++ b/routing/routing_tests/CMakeLists.txt
@@ -28,6 +28,7 @@ set(
routing_algorithm.cpp
routing_algorithm.hpp
routing_helpers_tests.cpp
+ routing_options_tests.cpp
routing_session_test.cpp
speed_cameras_tests.cpp
tools.hpp
diff --git a/routing/routing_tests/routing_options_tests.cpp b/routing/routing_tests/routing_options_tests.cpp
new file mode 100644
index 0000000000..779101a392
--- /dev/null
+++ b/routing/routing_tests/routing_options_tests.cpp
@@ -0,0 +1,51 @@
+#include "testing/testing.hpp"
+
+#include "routing/routing_options.hpp"
+
+#include <cstdint>
+#include <vector>
+
+using namespace routing;
+
+namespace
+{
+using RoadType = RoutingOptions::RoadType;
+
+void Checker(std::vector<RoutingOptions::Road> const & include)
+{
+ RoutingOptions options;
+
+ for (auto type : include)
+ options.Add(type);
+
+ for (auto type : include)
+ TEST(options.Has(type), ());
+
+ auto max = static_cast<RoadType>(RoutingOptions::Road::Max);
+ for (uint8_t i = 1; i < max; i <<= 1)
+ {
+ bool hasInclude = false;
+ auto type = static_cast<RoutingOptions::Road>(i);
+ for (auto has : include)
+ hasInclude |= (type == has);
+
+ if (!hasInclude)
+ TEST(!options.Has(static_cast<RoutingOptions::Road>(i)), ());
+ }
+}
+
+UNIT_TEST(RoutingOptionTest)
+{
+ Checker({RoutingOptions::Road::Toll, RoutingOptions::Road::Motorway,
+ RoutingOptions::Road::Dirty});
+ Checker({RoutingOptions::Road::Toll, RoutingOptions::Road::Dirty});
+
+ Checker({RoutingOptions::Road::Toll, RoutingOptions::Road::Ferry,
+ RoutingOptions::Road::Dirty});
+
+ Checker({RoutingOptions::Road::Dirty});
+ Checker({RoutingOptions::Road::Toll});
+ Checker({RoutingOptions::Road::Dirty, RoutingOptions::Road::Motorway});
+ Checker({});
+}
+} // namespace
diff --git a/routing/single_vehicle_world_graph.cpp b/routing/single_vehicle_world_graph.cpp
index 262e19d85c..0e8db521cd 100644
--- a/routing/single_vehicle_world_graph.cpp
+++ b/routing/single_vehicle_world_graph.cpp
@@ -35,6 +35,7 @@ void SingleVehicleWorldGraph::CheckAndProcessTransitFeatures(Segment const & par
for (auto const & twin : twins)
{
NumMwmId const twinMwmId = twin.GetMwmId();
+
uint32_t const twinFeatureId = twin.GetFeatureId();
Segment const start(twinMwmId, twinFeatureId, target.GetSegmentId(!opposite), target.IsForward());
@@ -89,13 +90,14 @@ void SingleVehicleWorldGraph::GetEdgeList(Segment const & segment, bool isOutgoi
GetTwins(segment, isOutgoing, edges);
else
m_crossMwmGraph->GetOutgoingEdgeList(segment, edges);
+
return;
}
IndexGraph & indexGraph = m_loader->GetIndexGraph(segment.GetMwmId());
indexGraph.GetEdgeList(segment, isOutgoing, edges);
- if (m_mode != Mode::SingleMwm && m_crossMwmGraph && m_crossMwmGraph->IsTransition(segment, isOutgoing))
+ if (m_mode != Mode::JointSingleMwm && m_crossMwmGraph && m_crossMwmGraph->IsTransition(segment, isOutgoing))
GetTwins(segment, isOutgoing, edges);
}
@@ -188,6 +190,7 @@ unique_ptr<TransitInfo> SingleVehicleWorldGraph::GetTransitInfo(Segment const &)
vector<RouteSegment::SpeedCamera> SingleVehicleWorldGraph::GetSpeedCamInfo(Segment const & segment)
{
+ ASSERT(segment.IsRealSegment(), ());
return m_loader->GetSpeedCameraInfo(segment);
}
@@ -201,4 +204,18 @@ void SingleVehicleWorldGraph::GetTwinsInner(Segment const & segment, bool isOutg
{
m_crossMwmGraph->GetTwins(segment, isOutgoing, twins);
}
+
+bool SingleVehicleWorldGraph::IsRoutingOptionsGood(Segment const & segment)
+{
+ auto const & geometry = GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId());
+ return geometry.SuitableForOptions(m_avoidRoutingOptions);
+}
+
+RoutingOptions SingleVehicleWorldGraph::GetRoutingOptions(Segment const & segment)
+{
+ ASSERT(segment.IsRealSegment(), ());
+
+ auto const & geometry = GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId());
+ return geometry.GetRoutingOptions();
+}
} // namespace routing
diff --git a/routing/single_vehicle_world_graph.hpp b/routing/single_vehicle_world_graph.hpp
index 1d4a0cb6d5..20827a4efa 100644
--- a/routing/single_vehicle_world_graph.hpp
+++ b/routing/single_vehicle_world_graph.hpp
@@ -56,6 +56,12 @@ public:
double CalcSegmentETA(Segment const & segment) override;
bool LeapIsAllowed(NumMwmId mwmId) const override;
std::vector<Segment> const & GetTransitions(NumMwmId numMwmId, bool isEnter) override;
+
+ /// \returns true if feature, associated with segment satisfies users conditions.
+ bool IsRoutingOptionsGood(Segment const & segment) override;
+ RoutingOptions GetRoutingOptions(Segment const & segment) override;
+ void SetRoutingOptions(RoutingOptions routingOptions) override { m_avoidRoutingOptions = routingOptions; }
+
std::unique_ptr<TransitInfo> GetTransitInfo(Segment const & segment) override;
std::vector<RouteSegment::SpeedCamera> GetSpeedCamInfo(Segment const & segment) override;
@@ -86,5 +92,6 @@ private:
std::unique_ptr<IndexGraphLoader> m_loader;
std::shared_ptr<EdgeEstimator> m_estimator;
Mode m_mode = Mode::NoLeaps;
+ RoutingOptions m_avoidRoutingOptions = RoutingOptions();
};
} // namespace routing
diff --git a/routing/turns_notification_manager.cpp b/routing/turns_notification_manager.cpp
index dde6a2437f..e554409028 100644
--- a/routing/turns_notification_manager.cpp
+++ b/routing/turns_notification_manager.cpp
@@ -2,7 +2,10 @@
#include "platform/location.hpp"
-#include "std/algorithm.hpp"
+#include <algorithm>
+#include <vector>
+
+using namespace std;
namespace
{
diff --git a/routing/world_graph.cpp b/routing/world_graph.cpp
index 201d2d8d9f..aff4c60f69 100644
--- a/routing/world_graph.cpp
+++ b/routing/world_graph.cpp
@@ -36,6 +36,18 @@ void WorldGraph::GetTwins(Segment const & segment, bool isOutgoing, std::vector<
SetMode(prevMode);
}
+RoutingOptions WorldGraph::GetRoutingOptions(Segment const & /* segment */)
+{
+ return {};
+}
+
+bool WorldGraph::IsRoutingOptionsGood(Segment const & /* segment */)
+{
+ return true;
+}
+
+void WorldGraph::SetRoutingOptions(RoutingOptions /* routingOption */) {}
+
std::string DebugPrint(WorldGraph::Mode mode)
{
switch (mode)
diff --git a/routing/world_graph.hpp b/routing/world_graph.hpp
index f8e5df06db..882d26dbfb 100644
--- a/routing/world_graph.hpp
+++ b/routing/world_graph.hpp
@@ -5,6 +5,7 @@
#include "routing/joint_segment.hpp"
#include "routing/road_graph.hpp"
#include "routing/route.hpp"
+#include "routing/routing_options.hpp"
#include "routing/segment.hpp"
#include "routing/transit_info.hpp"
@@ -13,6 +14,7 @@
#include "geometry/point2d.hpp"
#include <memory>
+#include <set>
#include <string>
#include <vector>
@@ -77,6 +79,10 @@ public:
/// \returns transitions for mwm with id |numMwmId|.
virtual std::vector<Segment> const & GetTransitions(NumMwmId numMwmId, bool isEnter) = 0;
+ virtual bool IsRoutingOptionsGood(Segment const & /* segment */);
+ virtual RoutingOptions GetRoutingOptions(Segment const & /* segment */);
+ virtual void SetRoutingOptions(RoutingOptions /* routingOptions */);
+
/// \returns transit-specific information for segment. For nontransit segments returns nullptr.
virtual std::unique_ptr<TransitInfo> GetTransitInfo(Segment const & segment) = 0;