Merge pull request #3338 from bykoianko/master-velo-direction
[bicycle routing] "oneway" tag is taken into account while bicycle routing.
This commit is contained in:
commit
bb67816403
15 changed files with 288 additions and 112 deletions
|
@ -74,4 +74,40 @@ UNIT_TEST(EqualsBy)
|
|||
TEST_EQUAL(expected[i], actual[i].Get(), ());
|
||||
}
|
||||
}
|
||||
|
||||
UNIT_TEST(SortUnique)
|
||||
{
|
||||
{
|
||||
vector<int> actual = {1, 2, 1, 4, 3, 5, 2, 7, 1};
|
||||
my::SortUnique(actual);
|
||||
vector<int> const expected = {1, 2, 3, 4, 5, 7};
|
||||
TEST_EQUAL(actual, expected, ());
|
||||
}
|
||||
{
|
||||
using TValue = int;
|
||||
using TPair = pair<TValue, int>;
|
||||
vector<TPair> v =
|
||||
{{1, 22}, {2, 33}, {1, 23}, {4, 54}, {3, 34}, {5, 23}, {2, 23}, {7, 32}, {1, 12}};
|
||||
|
||||
my::SortUnique<TPair>(v, my::LessBy(&TPair::first), my::EqualsBy(&TPair::first));
|
||||
|
||||
vector<TValue> const expected = {1, 2, 3, 4, 5, 7};
|
||||
TEST_EQUAL(v.size(), expected.size(), ());
|
||||
for (int i = 0; i < v.size(); ++i)
|
||||
TEST_EQUAL(v[i].first, expected[i], (i));
|
||||
}
|
||||
{
|
||||
using TValue = double;
|
||||
using TPair = pair<TValue, int>;
|
||||
vector<TPair> v =
|
||||
{{0.5, 11}, {1000.99, 234}, {0.5, 23}, {1234.56789, 54}, {1000.99, 34}};
|
||||
|
||||
my::SortUnique<TPair>(v, my::LessBy(&TPair::first), my::EqualsBy(&TPair::first));
|
||||
|
||||
vector<TValue> const expected = {0.5, 1000.99, 1234.56789};
|
||||
TEST_EQUAL(v.size(), expected.size(), ());
|
||||
for (int i = 0; i < v.size(); ++i)
|
||||
TEST_EQUAL(v[i].first, expected[i], (i));
|
||||
}
|
||||
}
|
||||
} // namespace
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
#pragma once
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
#include "std/functional.hpp"
|
||||
#include "std/utility.hpp"
|
||||
#include "std/vector.hpp"
|
||||
|
||||
|
||||
namespace my
|
||||
{
|
||||
namespace impl
|
||||
|
@ -85,6 +88,16 @@ void SortUnique(vector<T> & v)
|
|||
v.erase(unique(v.begin(), v.end()), v.end());
|
||||
}
|
||||
|
||||
// Sorts according to |comp| and removes duplicate entries according to |pred| from |v|.
|
||||
// Note. If several entries are equal according to |pred| an arbitrary entry of them
|
||||
// is left in |v| after a call of this function.
|
||||
template <typename T, typename TLess, typename TEquals>
|
||||
void SortUnique(vector<T> & v, TLess && less, TEquals && equals)
|
||||
{
|
||||
sort(v.begin(), v.end(), forward<TLess>(less));
|
||||
v.erase(unique(v.begin(), v.end(), forward<TEquals>(equals)), v.end());
|
||||
}
|
||||
|
||||
template <typename T, class TFn>
|
||||
void EraseIf(vector<T> & v, TFn && fn)
|
||||
{
|
||||
|
|
|
@ -1035,7 +1035,7 @@ void Framework::StartInteractiveSearch(search::SearchParams const & params)
|
|||
|
||||
m_lastInteractiveSearchParams = params;
|
||||
m_lastInteractiveSearchParams.SetForceSearch(false);
|
||||
m_lastInteractiveSearchParams.SetMode(Mode::Viewport);
|
||||
m_lastInteractiveSearchParams.SetMode(search::Mode::Viewport);
|
||||
m_lastInteractiveSearchParams.SetSuggestsEnabled(false);
|
||||
m_lastInteractiveSearchParams.m_onResults = [this](Results const & results)
|
||||
{
|
||||
|
|
|
@ -94,7 +94,9 @@ unique_ptr<routing::IRouter> CreatePedestrianAStarTestRouter(Index & index, stor
|
|||
auto UKGetter = [&](m2::PointD const & pt) { return cig.GetRegionCountryId(pt); };
|
||||
unique_ptr<routing::IVehicleModelFactory> vehicleModelFactory(new SimplifiedPedestrianModelFactory());
|
||||
unique_ptr<routing::IRoutingAlgorithm> algorithm(new routing::AStarRoutingAlgorithm());
|
||||
unique_ptr<routing::IRouter> router(new routing::RoadGraphRouter("test-astar-pedestrian", index, UKGetter, move(vehicleModelFactory), move(algorithm), nullptr));
|
||||
unique_ptr<routing::IRouter> router(new routing::RoadGraphRouter(
|
||||
"test-astar-pedestrian", index, UKGetter, routing::IRoadGraph::Mode::IgnoreOnewayTag,
|
||||
move(vehicleModelFactory), move(algorithm), nullptr));
|
||||
return router;
|
||||
}
|
||||
|
||||
|
@ -103,7 +105,9 @@ unique_ptr<routing::IRouter> CreatePedestrianAStarBidirectionalTestRouter(Index
|
|||
auto UKGetter = [&](m2::PointD const & pt) { return cig.GetRegionCountryId(pt); };
|
||||
unique_ptr<routing::IVehicleModelFactory> vehicleModelFactory(new SimplifiedPedestrianModelFactory());
|
||||
unique_ptr<routing::IRoutingAlgorithm> algorithm(new routing::AStarBidirectionalRoutingAlgorithm());
|
||||
unique_ptr<routing::IRouter> router(new routing::RoadGraphRouter("test-astar-bidirectional-pedestrian", index, UKGetter, move(vehicleModelFactory), move(algorithm), nullptr));
|
||||
unique_ptr<routing::IRouter> router(new routing::RoadGraphRouter(
|
||||
"test-astar-bidirectional-pedestrian", index, UKGetter, routing::IRoadGraph::Mode::IgnoreOnewayTag,
|
||||
move(vehicleModelFactory), move(algorithm), nullptr));
|
||||
return router;
|
||||
}
|
||||
|
||||
|
@ -120,7 +124,8 @@ m2::PointD GetPointOnEdge(routing::Edge & e, double posAlong)
|
|||
void GetNearestPedestrianEdges(Index & index, m2::PointD const & pt, vector<pair<routing::Edge, m2::PointD>> & edges)
|
||||
{
|
||||
unique_ptr<routing::IVehicleModelFactory> vehicleModelFactory(new SimplifiedPedestrianModelFactory());
|
||||
routing::FeaturesRoadGraph roadGraph(index, move(vehicleModelFactory));
|
||||
routing::FeaturesRoadGraph roadGraph(index, routing::IRoadGraph::Mode::IgnoreOnewayTag,
|
||||
move(vehicleModelFactory));
|
||||
|
||||
roadGraph.FindClosestEdges(pt, 1 /*count*/, edges);
|
||||
}
|
||||
|
|
|
@ -17,7 +17,6 @@ public:
|
|||
/// @name Overrides from VehicleModel.
|
||||
//@{
|
||||
double GetSpeed(FeatureType const & f) const override;
|
||||
bool IsOneWay(FeatureType const &) const override { return false; }
|
||||
//@}
|
||||
|
||||
private:
|
||||
|
|
|
@ -36,12 +36,6 @@ string GetFeatureCountryName(FeatureID const featureId)
|
|||
return countryName;
|
||||
return countryName.substr(0, pos);
|
||||
}
|
||||
|
||||
inline bool PointsAlmostEqualAbs(const m2::PointD & pt1, const m2::PointD & pt2)
|
||||
{
|
||||
double constexpr kEpsilon = 1e-6;
|
||||
return my::AlmostEqualAbs(pt1.x, pt2.x, kEpsilon) && my::AlmostEqualAbs(pt1.y, pt2.y, kEpsilon);
|
||||
}
|
||||
} // namespace
|
||||
|
||||
|
||||
|
@ -101,10 +95,11 @@ void FeaturesRoadGraph::RoadInfoCache::Clear()
|
|||
m_cache.clear();
|
||||
}
|
||||
|
||||
|
||||
FeaturesRoadGraph::FeaturesRoadGraph(Index & index, unique_ptr<IVehicleModelFactory> && vehicleModelFactory)
|
||||
: m_index(index),
|
||||
m_vehicleModel(move(vehicleModelFactory))
|
||||
FeaturesRoadGraph::FeaturesRoadGraph(Index const & index, IRoadGraph::Mode mode,
|
||||
unique_ptr<IVehicleModelFactory> && vehicleModelFactory)
|
||||
: m_index(index)
|
||||
, m_mode(mode)
|
||||
, m_vehicleModel(move(vehicleModelFactory))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -113,9 +108,8 @@ uint32_t FeaturesRoadGraph::GetStreetReadScale() { return scales::GetUpperScale(
|
|||
class CrossFeaturesLoader
|
||||
{
|
||||
public:
|
||||
CrossFeaturesLoader(FeaturesRoadGraph const & graph,
|
||||
IRoadGraph::CrossEdgesLoader & edgesLoader)
|
||||
: m_graph(graph), m_edgesLoader(edgesLoader)
|
||||
CrossFeaturesLoader(FeaturesRoadGraph const & graph, IRoadGraph::ICrossEdgesLoader & edgesLoader)
|
||||
: m_graph(graph), m_edgesLoader(edgesLoader)
|
||||
{}
|
||||
|
||||
void operator()(FeatureType & ft)
|
||||
|
@ -136,7 +130,7 @@ public:
|
|||
|
||||
private:
|
||||
FeaturesRoadGraph const & m_graph;
|
||||
IRoadGraph::CrossEdgesLoader & m_edgesLoader;
|
||||
IRoadGraph::ICrossEdgesLoader & m_edgesLoader;
|
||||
};
|
||||
|
||||
IRoadGraph::RoadInfo FeaturesRoadGraph::GetRoadInfo(FeatureID const & featureId) const
|
||||
|
@ -159,7 +153,7 @@ double FeaturesRoadGraph::GetMaxSpeedKMPH() const
|
|||
}
|
||||
|
||||
void FeaturesRoadGraph::ForEachFeatureClosestToCross(m2::PointD const & cross,
|
||||
CrossEdgesLoader & edgesLoader) const
|
||||
ICrossEdgesLoader & edgesLoader) const
|
||||
{
|
||||
CrossFeaturesLoader featuresLoader(*this, edgesLoader);
|
||||
m2::RectD const rect = MercatorBounds::RectByCenterXYAndSizeInMeters(cross, kMwmRoadCrossingRadiusMeters);
|
||||
|
@ -218,7 +212,7 @@ void FeaturesRoadGraph::GetJunctionTypes(Junction const & junction, feature::Typ
|
|||
if (ft.GetFeatureType() != feature::GEOM_POINT)
|
||||
return;
|
||||
|
||||
if (!PointsAlmostEqualAbs(ft.GetCenter(), cross))
|
||||
if (!my::AlmostEqualAbs(ft.GetCenter(), cross, routing::kPointsEqualEpsilon))
|
||||
return;
|
||||
|
||||
feature::TypesHolder typesHolder(ft);
|
||||
|
@ -230,6 +224,11 @@ void FeaturesRoadGraph::GetJunctionTypes(Junction const & junction, feature::Typ
|
|||
m_index.ForEachInRect(f, rect, GetStreetReadScale());
|
||||
}
|
||||
|
||||
IRoadGraph::Mode FeaturesRoadGraph::GetMode() const
|
||||
{
|
||||
return m_mode;
|
||||
};
|
||||
|
||||
void FeaturesRoadGraph::ClearState()
|
||||
{
|
||||
m_cache.Clear();
|
||||
|
|
|
@ -56,7 +56,8 @@ private:
|
|||
};
|
||||
|
||||
public:
|
||||
FeaturesRoadGraph(Index & index, unique_ptr<IVehicleModelFactory> && vehicleModelFactory);
|
||||
FeaturesRoadGraph(Index const & index, IRoadGraph::Mode mode,
|
||||
unique_ptr<IVehicleModelFactory> && vehicleModelFactory);
|
||||
|
||||
static uint32_t GetStreetReadScale();
|
||||
|
||||
|
@ -65,11 +66,12 @@ public:
|
|||
double GetSpeedKMPH(FeatureID const & featureId) const override;
|
||||
double GetMaxSpeedKMPH() const override;
|
||||
void ForEachFeatureClosestToCross(m2::PointD const & cross,
|
||||
CrossEdgesLoader & edgesLoader) const override;
|
||||
ICrossEdgesLoader & edgesLoader) const override;
|
||||
void FindClosestEdges(m2::PointD const & point, uint32_t count,
|
||||
vector<pair<Edge, m2::PointD>> & vicinities) const override;
|
||||
void GetFeatureTypes(FeatureID const & featureId, feature::TypesHolder & types) const override;
|
||||
void GetJunctionTypes(Junction const & junction, feature::TypesHolder & types) const override;
|
||||
IRoadGraph::Mode GetMode() const override;
|
||||
void ClearState() override;
|
||||
|
||||
private:
|
||||
|
@ -89,7 +91,8 @@ private:
|
|||
|
||||
void LockFeatureMwm(FeatureID const & featureId) const;
|
||||
|
||||
Index & m_index;
|
||||
Index const & m_index;
|
||||
IRoadGraph::Mode const m_mode;
|
||||
mutable RoadInfoCache m_cache;
|
||||
mutable CrossCountryVehicleModel m_vehicleModel;
|
||||
mutable map<MwmSet::MwmId, MwmSet::MwmHandle> m_mwmLocks;
|
||||
|
|
|
@ -15,16 +15,8 @@
|
|||
|
||||
namespace routing
|
||||
{
|
||||
|
||||
namespace
|
||||
{
|
||||
|
||||
inline bool PointsAlmostEqualAbs(const m2::PointD & pt1, const m2::PointD & pt2)
|
||||
{
|
||||
double constexpr kEpsilon = 1e-6;
|
||||
return my::AlmostEqualAbs(pt1.x, pt2.x, kEpsilon) && my::AlmostEqualAbs(pt1.y, pt2.y, kEpsilon);
|
||||
}
|
||||
|
||||
vector<Edge>::const_iterator FindEdgeContainingPoint(vector<Edge> const & edges, m2::PointD const & pt)
|
||||
{
|
||||
// A P B
|
||||
|
@ -38,7 +30,8 @@ vector<Edge>::const_iterator FindEdgeContainingPoint(vector<Edge> const & edges,
|
|||
|
||||
m2::PointD const v1 = e.GetStartJunction().GetPoint() - pt;
|
||||
m2::PointD const v2 = e.GetEndJunction().GetPoint() - pt;
|
||||
if (PointsAlmostEqualAbs(v1, m2::PointD::Zero()) || PointsAlmostEqualAbs(v2, m2::PointD::Zero()))
|
||||
if (my::AlmostEqualAbs(v1, m2::PointD::Zero(), kPointsEqualEpsilon)
|
||||
|| my::AlmostEqualAbs(v2, m2::PointD::Zero(), kPointsEqualEpsilon))
|
||||
{
|
||||
// Point p corresponds to the start or the end of the edge.
|
||||
return true;
|
||||
|
@ -61,6 +54,14 @@ vector<Edge>::const_iterator FindEdgeContainingPoint(vector<Edge> const & edges,
|
|||
return find_if(edges.begin(), edges.end(), liesOnEdgeFn);
|
||||
}
|
||||
|
||||
/// \brief Reverses |edges| starting from index |beginIdx| and upto the end of |v|.
|
||||
void ReverseEdges(size_t beginIdx, IRoadGraph::TEdgeVector & edges)
|
||||
{
|
||||
ASSERT_LESS_OR_EQUAL(beginIdx, edges.size(), ("Index too large."));
|
||||
|
||||
for (size_t i = beginIdx; i < edges.size(); ++i)
|
||||
edges[i] = edges[i].GetReverseEdge();
|
||||
}
|
||||
} // namespace
|
||||
|
||||
// Junction --------------------------------------------------------------------
|
||||
|
@ -154,76 +155,70 @@ IRoadGraph::RoadInfo::RoadInfo(bool bidirectional, double speedKMPH, initializer
|
|||
: m_points(points), m_speedKMPH(speedKMPH), m_bidirectional(bidirectional)
|
||||
{}
|
||||
|
||||
// IRoadGraph::CrossEdgesLoader ------------------------------------------------
|
||||
|
||||
IRoadGraph::CrossEdgesLoader::CrossEdgesLoader(m2::PointD const & cross, TEdgeVector & outgoingEdges)
|
||||
: m_cross(cross), m_outgoingEdges(outgoingEdges)
|
||||
// IRoadGraph::CrossOutgoingLoader ---------------------------------------------
|
||||
void IRoadGraph::CrossOutgoingLoader::LoadEdges(FeatureID const & featureId, RoadInfo const & roadInfo)
|
||||
{
|
||||
ForEachEdge(roadInfo, [&featureId, &roadInfo, this](size_t segId, m2::PointD const & endPoint, bool forward)
|
||||
{
|
||||
if (forward || roadInfo.m_bidirectional || m_mode == IRoadGraph::Mode::IgnoreOnewayTag)
|
||||
m_edges.emplace_back(featureId, forward, segId, m_cross, endPoint);
|
||||
});
|
||||
}
|
||||
|
||||
void IRoadGraph::CrossEdgesLoader::operator()(FeatureID const & featureId, RoadInfo const & roadInfo)
|
||||
// IRoadGraph::CrossIngoingLoader ----------------------------------------------
|
||||
void IRoadGraph::CrossIngoingLoader::LoadEdges(FeatureID const & featureId, RoadInfo const & roadInfo)
|
||||
{
|
||||
size_t const numPoints = roadInfo.m_points.size();
|
||||
|
||||
for (size_t i = 0; i < numPoints; ++i)
|
||||
ForEachEdge(roadInfo, [&featureId, &roadInfo, this](size_t segId, m2::PointD const & endPoint, bool forward)
|
||||
{
|
||||
m2::PointD const & p = roadInfo.m_points[i];
|
||||
|
||||
if (!PointsAlmostEqualAbs(m_cross, p))
|
||||
continue;
|
||||
|
||||
if (i > 0)
|
||||
{
|
||||
// p
|
||||
// o------------>o
|
||||
|
||||
m_outgoingEdges.emplace_back(featureId, false /* forward */, i - 1, p, roadInfo.m_points[i - 1]);
|
||||
}
|
||||
|
||||
if (i < numPoints - 1)
|
||||
{
|
||||
// p
|
||||
// o------------>o
|
||||
|
||||
m_outgoingEdges.emplace_back(featureId, true /* forward */, i, p, roadInfo.m_points[i + 1]);
|
||||
}
|
||||
}
|
||||
if (!forward || roadInfo.m_bidirectional || m_mode == IRoadGraph::Mode::IgnoreOnewayTag)
|
||||
m_edges.emplace_back(featureId, !forward, segId, endPoint, m_cross);
|
||||
});
|
||||
}
|
||||
|
||||
// IRoadGraph ------------------------------------------------------------------
|
||||
|
||||
void IRoadGraph::GetOutgoingEdges(Junction const & junction, TEdgeVector & edges) const
|
||||
{
|
||||
auto const itr = m_outgoingEdges.find(junction);
|
||||
if (itr != m_outgoingEdges.end())
|
||||
{
|
||||
edges.reserve(edges.size() + itr->second.size());
|
||||
edges.insert(edges.end(), itr->second.begin(), itr->second.end());
|
||||
}
|
||||
else
|
||||
{
|
||||
GetRegularOutgoingEdges(junction, edges);
|
||||
}
|
||||
GetFakeOutgoingEdges(junction, edges);
|
||||
GetRegularOutgoingEdges(junction, edges);
|
||||
}
|
||||
|
||||
void IRoadGraph::GetIngoingEdges(Junction const & junction, TEdgeVector & edges) const
|
||||
{
|
||||
size_t const wasSize = edges.size();
|
||||
|
||||
GetOutgoingEdges(junction, edges);
|
||||
|
||||
size_t const size = edges.size();
|
||||
for (size_t i = wasSize; i < size; ++i)
|
||||
edges[i] = edges[i].GetReverseEdge();
|
||||
GetFakeIngoingEdges(junction, edges);
|
||||
GetRegularIngoingEdges(junction, edges);
|
||||
}
|
||||
|
||||
void IRoadGraph::GetRegularOutgoingEdges(Junction const & junction, TEdgeVector & edges) const
|
||||
{
|
||||
m2::PointD const cross = junction.GetPoint();
|
||||
CrossEdgesLoader loader(cross, edges);
|
||||
CrossOutgoingLoader loader(cross, GetMode(), edges);
|
||||
ForEachFeatureClosestToCross(cross, loader);
|
||||
}
|
||||
|
||||
void IRoadGraph::GetRegularIngoingEdges(Junction const & junction, TEdgeVector & edges) const
|
||||
{
|
||||
m2::PointD const cross = junction.GetPoint();
|
||||
CrossIngoingLoader loader(cross, GetMode(), edges);
|
||||
ForEachFeatureClosestToCross(cross, loader);
|
||||
}
|
||||
|
||||
void IRoadGraph::GetFakeOutgoingEdges(Junction const & junction, TEdgeVector & edges) const
|
||||
{
|
||||
auto const itr = m_outgoingEdges.find(junction);
|
||||
if (itr == m_outgoingEdges.cend())
|
||||
return;
|
||||
|
||||
edges.reserve(edges.size() + itr->second.size());
|
||||
edges.insert(edges.end(), itr->second.begin(), itr->second.end());
|
||||
}
|
||||
|
||||
void IRoadGraph::GetFakeIngoingEdges(Junction const & junction, TEdgeVector & edges) const
|
||||
{
|
||||
size_t const oldSize = edges.size();
|
||||
GetFakeOutgoingEdges(junction, edges);
|
||||
ReverseEdges(oldSize, edges);
|
||||
}
|
||||
|
||||
void IRoadGraph::ResetFakes()
|
||||
{
|
||||
m_outgoingEdges.clear();
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
|
||||
namespace routing
|
||||
{
|
||||
double constexpr kPointsEqualEpsilon = 1e-6;
|
||||
|
||||
/// The Junction class represents a node description on a road network graph
|
||||
class Junction
|
||||
|
@ -83,6 +84,12 @@ public:
|
|||
typedef vector<Junction> TJunctionVector;
|
||||
typedef vector<Edge> TEdgeVector;
|
||||
|
||||
enum class Mode
|
||||
{
|
||||
ObeyOnewayTag,
|
||||
IgnoreOnewayTag,
|
||||
};
|
||||
|
||||
/// This struct contains the part of a feature's metadata that is
|
||||
/// relevant for routing.
|
||||
struct RoadInfo
|
||||
|
@ -99,17 +106,75 @@ public:
|
|||
};
|
||||
|
||||
/// This class is responsible for loading edges in a cross.
|
||||
/// It loades only outgoing edges.
|
||||
class CrossEdgesLoader
|
||||
class ICrossEdgesLoader
|
||||
{
|
||||
public:
|
||||
CrossEdgesLoader(m2::PointD const & cross, TEdgeVector & outgoingEdges);
|
||||
ICrossEdgesLoader(m2::PointD const & cross, IRoadGraph::Mode mode, TEdgeVector & edges)
|
||||
: m_cross(cross), m_mode(mode), m_edges(edges)
|
||||
{
|
||||
}
|
||||
|
||||
void operator()(FeatureID const & featureId, RoadInfo const & roadInfo);
|
||||
virtual ~ICrossEdgesLoader() = default;
|
||||
|
||||
void operator()(FeatureID const & featureId, RoadInfo const & roadInfo)
|
||||
{
|
||||
LoadEdges(featureId, roadInfo);
|
||||
}
|
||||
|
||||
private:
|
||||
virtual void LoadEdges(FeatureID const & featureId, RoadInfo const & roadInfo) = 0;
|
||||
|
||||
protected:
|
||||
template <typename TFn>
|
||||
void ForEachEdge(RoadInfo const & roadInfo, TFn && fn)
|
||||
{
|
||||
for (size_t i = 0; i < roadInfo.m_points.size(); ++i)
|
||||
{
|
||||
if (!my::AlmostEqualAbs(m_cross, roadInfo.m_points[i], kPointsEqualEpsilon))
|
||||
continue;
|
||||
|
||||
if (i < roadInfo.m_points.size() - 1)
|
||||
{
|
||||
// Head of the edge.
|
||||
// m_cross
|
||||
// o------------>o
|
||||
fn(i, roadInfo.m_points[i + 1], true /* forward */);
|
||||
}
|
||||
if (i > 0)
|
||||
{
|
||||
// Tail of the edge.
|
||||
// m_cross
|
||||
// o------------>o
|
||||
fn(i - 1, roadInfo.m_points[i - 1], false /* backward */);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m2::PointD const m_cross;
|
||||
TEdgeVector & m_outgoingEdges;
|
||||
IRoadGraph::Mode const m_mode;
|
||||
TEdgeVector & m_edges;
|
||||
};
|
||||
|
||||
class CrossOutgoingLoader : public ICrossEdgesLoader
|
||||
{
|
||||
public:
|
||||
CrossOutgoingLoader(m2::PointD const & cross, IRoadGraph::Mode mode, TEdgeVector & edges)
|
||||
: ICrossEdgesLoader(cross, mode, edges) {}
|
||||
|
||||
private:
|
||||
// ICrossEdgesLoader overrides:
|
||||
virtual void LoadEdges(FeatureID const & featureId, RoadInfo const & roadInfo) override;
|
||||
};
|
||||
|
||||
class CrossIngoingLoader : public ICrossEdgesLoader
|
||||
{
|
||||
public:
|
||||
CrossIngoingLoader(m2::PointD const & cross, IRoadGraph::Mode mode, TEdgeVector & edges)
|
||||
: ICrossEdgesLoader(cross, mode, edges) {}
|
||||
|
||||
private:
|
||||
// ICrossEdgesLoader overrides:
|
||||
virtual void LoadEdges(FeatureID const & featureId, RoadInfo const & roadInfo) override;
|
||||
};
|
||||
|
||||
virtual ~IRoadGraph() = default;
|
||||
|
@ -141,7 +206,7 @@ public:
|
|||
|
||||
/// Calls edgesLoader on each feature which is close to cross.
|
||||
virtual void ForEachFeatureClosestToCross(m2::PointD const & cross,
|
||||
CrossEdgesLoader & edgesLoader) const = 0;
|
||||
ICrossEdgesLoader & edgesLoader) const = 0;
|
||||
|
||||
/// Finds the closest edges to the point.
|
||||
/// @return Array of pairs of Edge and projection point on the Edge. If there is no the closest edges
|
||||
|
@ -158,12 +223,20 @@ public:
|
|||
/// @return Types for specified junction
|
||||
virtual void GetJunctionTypes(Junction const & junction, feature::TypesHolder & types) const = 0;
|
||||
|
||||
virtual IRoadGraph::Mode GetMode() const = 0;
|
||||
|
||||
/// Clear all temporary buffers.
|
||||
virtual void ClearState() {}
|
||||
|
||||
private:
|
||||
/// Finds all outgoing regular (non-fake) edges for junction.
|
||||
/// \brief Finds all outgoing regular (non-fake) edges for junction.
|
||||
void GetRegularOutgoingEdges(Junction const & junction, TEdgeVector & edges) const;
|
||||
/// \brief Finds all ingoing regular (non-fake) edges for junction.
|
||||
void GetRegularIngoingEdges(Junction const & junction, TEdgeVector & edges) const;
|
||||
/// \brief Finds all outgoing fake edges for junction.
|
||||
void GetFakeOutgoingEdges(Junction const & junction, TEdgeVector & edges) const;
|
||||
/// \brief Finds all ingoing fake edges for junction.
|
||||
void GetFakeIngoingEdges(Junction const & junction, TEdgeVector & edges) const;
|
||||
|
||||
/// Determines if the edge has been split by fake edges and if yes returns these fake edges.
|
||||
bool HasBeenSplitToFakes(Edge const & edge, vector<Edge> & fakeEdges) const;
|
||||
|
@ -171,5 +244,4 @@ private:
|
|||
// Map of outgoing edges for junction
|
||||
map<Junction, TEdgeVector> m_outgoingEdges;
|
||||
};
|
||||
|
||||
} // namespace routing
|
||||
|
|
|
@ -130,17 +130,17 @@ void FindClosestEdges(IRoadGraph const & graph, m2::PointD const & point,
|
|||
|
||||
RoadGraphRouter::~RoadGraphRouter() {}
|
||||
|
||||
RoadGraphRouter::RoadGraphRouter(string const & name, Index & index,
|
||||
TCountryFileFn const & countryFileFn,
|
||||
RoadGraphRouter::RoadGraphRouter(string const & name, Index const & index,
|
||||
TCountryFileFn const & countryFileFn, IRoadGraph::Mode mode,
|
||||
unique_ptr<IVehicleModelFactory> && vehicleModelFactory,
|
||||
unique_ptr<IRoutingAlgorithm> && algorithm,
|
||||
unique_ptr<IDirectionsEngine> && directionsEngine)
|
||||
: m_name(name)
|
||||
, m_countryFileFn(countryFileFn)
|
||||
, m_index(index)
|
||||
, m_algorithm(move(algorithm))
|
||||
, m_roadGraph(make_unique<FeaturesRoadGraph>(index, move(vehicleModelFactory)))
|
||||
, m_directionsEngine(move(directionsEngine))
|
||||
: m_name(name)
|
||||
, m_countryFileFn(countryFileFn)
|
||||
, m_index(index)
|
||||
, m_algorithm(move(algorithm))
|
||||
, m_roadGraph(make_unique<FeaturesRoadGraph>(index, mode, move(vehicleModelFactory)))
|
||||
, m_directionsEngine(move(directionsEngine))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -258,9 +258,9 @@ unique_ptr<IRouter> CreatePedestrianAStarRouter(Index & index, TCountryFileFn co
|
|||
unique_ptr<IVehicleModelFactory> vehicleModelFactory(new PedestrianModelFactory());
|
||||
unique_ptr<IRoutingAlgorithm> algorithm(new AStarRoutingAlgorithm());
|
||||
unique_ptr<IDirectionsEngine> directionsEngine(new PedestrianDirectionsEngine());
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter("astar-pedestrian", index, countryFileFn,
|
||||
move(vehicleModelFactory), move(algorithm),
|
||||
move(directionsEngine)));
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter(
|
||||
"astar-pedestrian", index, countryFileFn, IRoadGraph::Mode::IgnoreOnewayTag,
|
||||
move(vehicleModelFactory), move(algorithm), move(directionsEngine)));
|
||||
return router;
|
||||
}
|
||||
|
||||
|
@ -269,9 +269,9 @@ unique_ptr<IRouter> CreatePedestrianAStarBidirectionalRouter(Index & index, TCou
|
|||
unique_ptr<IVehicleModelFactory> vehicleModelFactory(new PedestrianModelFactory());
|
||||
unique_ptr<IRoutingAlgorithm> algorithm(new AStarBidirectionalRoutingAlgorithm());
|
||||
unique_ptr<IDirectionsEngine> directionsEngine(new PedestrianDirectionsEngine());
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter("astar-bidirectional-pedestrian", index,
|
||||
countryFileFn, move(vehicleModelFactory),
|
||||
move(algorithm), move(directionsEngine)));
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter(
|
||||
"astar-bidirectional-pedestrian", index, countryFileFn, IRoadGraph::Mode::IgnoreOnewayTag,
|
||||
move(vehicleModelFactory), move(algorithm), move(directionsEngine)));
|
||||
return router;
|
||||
}
|
||||
|
||||
|
@ -280,8 +280,9 @@ unique_ptr<IRouter> CreateBicycleAStarBidirectionalRouter(Index & index, TCountr
|
|||
unique_ptr<IVehicleModelFactory> vehicleModelFactory(new BicycleModelFactory());
|
||||
unique_ptr<IRoutingAlgorithm> algorithm(new AStarBidirectionalRoutingAlgorithm());
|
||||
unique_ptr<IDirectionsEngine> directionsEngine(new BicycleDirectionsEngine(index));
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter("astar-bidirectional-bicycle", index, countryFileFn, move(vehicleModelFactory),
|
||||
move(algorithm), move(directionsEngine)));
|
||||
unique_ptr<IRouter> router(new RoadGraphRouter(
|
||||
"astar-bidirectional-bicycle", index, countryFileFn, IRoadGraph::Mode::ObeyOnewayTag,
|
||||
move(vehicleModelFactory), move(algorithm), move(directionsEngine)));
|
||||
return router;
|
||||
}
|
||||
} // namespace routing
|
||||
|
|
|
@ -23,8 +23,8 @@ namespace routing
|
|||
class RoadGraphRouter : public IRouter
|
||||
{
|
||||
public:
|
||||
RoadGraphRouter(string const & name, Index & index,
|
||||
TCountryFileFn const & countryFileFn,
|
||||
RoadGraphRouter(string const & name, Index const & index, TCountryFileFn const & countryFileFn,
|
||||
IRoadGraph::Mode mode,
|
||||
unique_ptr<IVehicleModelFactory> && vehicleModelFactory,
|
||||
unique_ptr<IRoutingAlgorithm> && algorithm,
|
||||
unique_ptr<IDirectionsEngine> && directionsEngine);
|
||||
|
@ -47,7 +47,7 @@ private:
|
|||
|
||||
string const m_name;
|
||||
TCountryFileFn const m_countryFileFn;
|
||||
Index & m_index;
|
||||
Index const & m_index;
|
||||
unique_ptr<IRoutingAlgorithm> const m_algorithm;
|
||||
unique_ptr<IRoadGraph> const m_roadGraph;
|
||||
unique_ptr<IDirectionsEngine> const m_directionsEngine;
|
||||
|
|
|
@ -17,11 +17,13 @@ UNIT_TEST(RussiaMoscowSevTushinoParkBicycleWayTurnTest)
|
|||
IRouter::ResultCode const result = routeResult.second;
|
||||
TEST_EQUAL(result, IRouter::NoError, ());
|
||||
|
||||
integration::TestTurnCount(route, 1);
|
||||
integration::TestTurnCount(route, 3);
|
||||
|
||||
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
integration::GetNthTurn(route, 1).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
integration::GetNthTurn(route, 2).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
|
||||
integration::TestRouteLength(route, 752.);
|
||||
integration::TestRouteLength(route, 2350.0);
|
||||
}
|
||||
|
||||
UNIT_TEST(RussiaMoscowGerPanfilovtsev22BicycleWayTurnTest)
|
||||
|
@ -67,3 +69,42 @@ UNIT_TEST(RussiaMoscowSevTushinoParkBicycleOnePointTurnTest)
|
|||
TEST_EQUAL(route.GetTurns().size(), 0, ());
|
||||
integration::TestRouteLength(route, 0.0);
|
||||
}
|
||||
|
||||
UNIT_TEST(RussiaMoscowPlanernaiOnewayCarRoadTurnTest)
|
||||
{
|
||||
TRouteResult const routeResult = integration::CalculateRoute(
|
||||
integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.87012, 37.44028),
|
||||
{0.0, 0.0}, MercatorBounds::FromLatLon(55.87153, 37.43928));
|
||||
|
||||
Route const & route = *routeResult.first;
|
||||
IRouter::ResultCode const result = routeResult.second;
|
||||
TEST_EQUAL(result, IRouter::NoError, ());
|
||||
|
||||
integration::TestTurnCount(route, 4);
|
||||
|
||||
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
integration::GetNthTurn(route, 1).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
integration::GetNthTurn(route, 2).TestValid().TestDirection(TurnDirection::TurnSlightRight);
|
||||
integration::GetNthTurn(route, 3).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
|
||||
integration::TestRouteLength(route, 420.0);
|
||||
}
|
||||
|
||||
UNIT_TEST(RussiaMoscowSvobodiOnewayBicycleWayTurnTest)
|
||||
{
|
||||
TRouteResult const routeResult = integration::CalculateRoute(
|
||||
integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.87277, 37.44002),
|
||||
{0.0, 0.0}, MercatorBounds::FromLatLon(55.87362, 37.43853));
|
||||
|
||||
Route const & route = *routeResult.first;
|
||||
IRouter::ResultCode const result = routeResult.second;
|
||||
TEST_EQUAL(result, IRouter::NoError, ());
|
||||
|
||||
integration::TestTurnCount(route, 3);
|
||||
|
||||
integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
integration::GetNthTurn(route, 1).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
integration::GetNthTurn(route, 2).TestValid().TestDirection(TurnDirection::TurnLeft);
|
||||
|
||||
integration::TestRouteLength(route, 768.0);
|
||||
}
|
||||
|
|
|
@ -84,7 +84,7 @@ double RoadGraphMockSource::GetMaxSpeedKMPH() const
|
|||
}
|
||||
|
||||
void RoadGraphMockSource::ForEachFeatureClosestToCross(m2::PointD const & /* cross */,
|
||||
CrossEdgesLoader & edgesLoader) const
|
||||
ICrossEdgesLoader & edgesLoader) const
|
||||
{
|
||||
for (size_t roadId = 0; roadId < m_roads.size(); ++roadId)
|
||||
edgesLoader(MakeTestFeatureID(roadId), m_roads[roadId]);
|
||||
|
@ -110,6 +110,11 @@ void RoadGraphMockSource::GetJunctionTypes(Junction const & junction, feature::T
|
|||
UNUSED_VALUE(types);
|
||||
}
|
||||
|
||||
IRoadGraph::Mode RoadGraphMockSource::GetMode() const
|
||||
{
|
||||
return IRoadGraph::Mode::IgnoreOnewayTag;
|
||||
}
|
||||
|
||||
FeatureID MakeTestFeatureID(uint32_t offset)
|
||||
{
|
||||
static TestValidFeatureIDProvider instance;
|
||||
|
|
|
@ -17,11 +17,12 @@ public:
|
|||
double GetSpeedKMPH(FeatureID const & featureId) const override;
|
||||
double GetMaxSpeedKMPH() const override;
|
||||
void ForEachFeatureClosestToCross(m2::PointD const & cross,
|
||||
CrossEdgesLoader & edgeLoader) const override;
|
||||
ICrossEdgesLoader & edgeLoader) const override;
|
||||
void FindClosestEdges(m2::PointD const & point, uint32_t count,
|
||||
vector<pair<routing::Edge, m2::PointD>> & vicinities) const override;
|
||||
void GetFeatureTypes(FeatureID const & featureId, feature::TypesHolder & types) const override;
|
||||
void GetJunctionTypes(routing::Junction const & junction, feature::TypesHolder & types) const override;
|
||||
routing::IRoadGraph::Mode GetMode() const override;
|
||||
|
||||
private:
|
||||
vector<RoadInfo> m_roads;
|
||||
|
|
|
@ -64,6 +64,12 @@ public:
|
|||
//@}
|
||||
|
||||
double GetSpeed(feature::TypesHolder const & types) const;
|
||||
|
||||
/// \returns true if |types| is a oneway feature.
|
||||
/// \note According to OSM tag "oneway" could have value "-1". That means it's a oneway feature
|
||||
/// with reversed geometry. In that case while map generation the geometry of such features
|
||||
/// is reversed (the order of points is changed) so in vehicle model all oneway feature
|
||||
/// could be considered as features with forward geometry.
|
||||
bool IsOneWay(feature::TypesHolder const & types) const;
|
||||
|
||||
bool IsRoad(FeatureType const & f) const;
|
||||
|
|
Reference in a new issue