Merge pull request #4672 from dobriy-eeh/index-routing

Indexed AStar routing
This commit is contained in:
Vladimir Byko-Ianko 2016-11-26 09:30:12 +03:00 committed by GitHub
commit 4492f89b9d
49 changed files with 2116 additions and 97 deletions

View file

@ -27,6 +27,7 @@
#define METADATA_FILE_TAG "meta"
#define METADATA_INDEX_FILE_TAG "metaidx"
#define ALTITUDES_FILE_TAG "altitudes"
#define RESTRICTIONS_FILE_TAG "restrictions"
#define ROUTING_FILE_TAG "routing"
#define FEATURE_OFFSETS_FILE_TAG "offs"
#define RANKS_FILE_TAG "ranks"
@ -40,8 +41,6 @@
#define ROUTING_SHORTCUTS_FILE_TAG "skoda"
#define ROUTING_CROSS_CONTEXT_TAG "chrysler"
#define ROUTING_FILE_TAG "routing"
#define ROUTING_FTSEG_FILE_TAG "ftseg"
#define ROUTING_NODEIND_TO_FTSEGIND_FILE_TAG "node2ftseg"

View file

@ -40,6 +40,7 @@ SOURCES += \
restriction_generator.cpp \
restriction_writer.cpp \
routing_generator.cpp \
routing_index_generator.cpp \
search_index_builder.cpp \
sponsored_scoring.cpp \
srtm_parser.cpp \
@ -80,6 +81,7 @@ HEADERS += \
restriction_generator.hpp \
restriction_writer.hpp \
routing_generator.hpp \
routing_index_generator.hpp \
search_index_builder.hpp \
sponsored_dataset.hpp \
sponsored_dataset_inl.hpp \

View file

@ -10,6 +10,7 @@
#include "generator/osm_source.hpp"
#include "generator/restriction_generator.hpp"
#include "generator/routing_generator.hpp"
#include "generator/routing_index_generator.hpp"
#include "generator/search_index_builder.hpp"
#include "generator/statistics.hpp"
#include "generator/unpack_mwm.hpp"
@ -87,6 +88,7 @@ DEFINE_string(restriction_name, "", "Name of file with relation restriction in o
DEFINE_string(feature_ids_to_osm_ids_name, "",
"Name of file with mapping from feature ids to osm ids.");
DEFINE_bool(generate_routing, false, "Generate section with routing information.");
DEFINE_bool(generate_restrictions, false, "Generate section with road restrictions.");
int main(int argc, char ** argv)
{
@ -150,7 +152,7 @@ int main(int argc, char ** argv)
FLAGS_generate_index || FLAGS_generate_search_index || FLAGS_calc_statistics ||
FLAGS_type_statistics || FLAGS_dump_types || FLAGS_dump_prefixes ||
FLAGS_dump_feature_names != "" || FLAGS_check_mwm || FLAGS_srtm_path != "" ||
FLAGS_generate_routing)
FLAGS_generate_routing || FLAGS_generate_restrictions )
{
classificator::Load();
classif().SortClassificator();
@ -237,8 +239,10 @@ int main(int argc, char ** argv)
if (!FLAGS_srtm_path.empty())
routing::BuildRoadAltitudes(datFile, FLAGS_srtm_path);
// @TODO(bykoianko) generate_routing flag should be used for all routing information.
if (FLAGS_generate_routing)
routing::BuildRoutingIndex(datFile);
if (FLAGS_generate_restrictions)
{
routing::BuildRoadRestrictions(
datFile, genInfo.GetIntermediateFileName(genInfo.m_restrictions, "" /* extention */),

View file

@ -39,7 +39,7 @@ bool BuildRoadRestrictions(string const & mwmPath, string const & restrictionPat
header.m_onlyRestrictionCount, "of type Only restrictions"));
FilesContainerW cont(mwmPath, FileWriter::OP_WRITE_EXISTING);
FileWriter w = cont.GetWriter(ROUTING_FILE_TAG);
FileWriter w = cont.GetWriter(RESTRICTIONS_FILE_TAG);
header.Serialize(w);
RestrictionSerializer::Serialize(header, restrictions.cbegin(), restrictions.cend(), w);

View file

@ -0,0 +1,94 @@
#include "generator/routing_index_generator.hpp"
#include "routing/index_graph.hpp"
#include "routing/routing_helpers.hpp"
#include "indexer/feature.hpp"
#include "indexer/feature_processor.hpp"
#include "indexer/point_to_int64.hpp"
#include "indexer/routing_section.hpp"
#include "coding/file_container.hpp"
#include "base/logging.hpp"
#include "std/bind.hpp"
#include "std/unordered_map.hpp"
#include "std/vector.hpp"
using namespace feature;
using namespace platform;
using namespace routing;
namespace
{
class Processor final
{
public:
void ProcessAllFeatures(string const & filename)
{
feature::ForEachFromDat(filename, bind(&Processor::ProcessFeature, this, _1, _2));
}
void BuildGraph(IndexGraph & graph) const
{
vector<Joint> joints;
for (auto const & it : m_posToJoint)
{
// Need only connected points (2 or more roads)
if (it.second.GetSize() >= 2)
joints.emplace_back(it.second);
}
graph.Import(joints);
}
private:
void ProcessFeature(FeatureType const & f, uint32_t id)
{
if (!IsRoad(feature::TypesHolder(f)))
return;
f.ParseGeometry(FeatureType::BEST_GEOMETRY);
for (size_t i = 0; i < f.GetPointsCount(); ++i)
{
uint64_t const locationKey = PointToInt64(f.GetPoint(i), POINT_COORD_BITS);
m_posToJoint[locationKey].AddPoint(RoadPoint(id, i));
}
}
unordered_map<uint64_t, Joint> m_posToJoint;
};
} // namespace
namespace routing
{
bool BuildRoutingIndex(string const & filename)
{
LOG(LINFO, ("Building routing index for", filename));
try
{
Processor processor;
processor.ProcessAllFeatures(filename);
IndexGraph graph;
processor.BuildGraph(graph);
LOG(LINFO, ("Routing index contains", graph.GetNumRoads(), "roads,", graph.GetNumJoints(),
"joints,", graph.GetNumPoints(), "points"));
FilesContainerW cont(filename, FileWriter::OP_WRITE_EXISTING);
FileWriter writer = cont.GetWriter(ROUTING_FILE_TAG);
RoutingSectionHeader const routingHeader;
routingHeader.Serialize(writer);
graph.Serialize(writer);
return true;
}
catch (RootException const & e)
{
LOG(LERROR, ("An exception happened while creating", ROUTING_FILE_TAG, "section:", e.what()));
return false;
}
}
} // namespace routing

View file

@ -0,0 +1,8 @@
#pragma once
#include "std/string.hpp"
namespace routing
{
bool BuildRoutingIndex(string const & filename);
} // namespace routing

View file

@ -117,6 +117,7 @@ HEADERS += \
point_to_int64.hpp \
postcodes_matcher.hpp \ # it's in indexer due to editor wich is in indexer and depends on postcodes_marcher
rank_table.hpp \
routing_section.hpp \
scale_index.hpp \
scale_index_builder.hpp \
scales.hpp \

View file

@ -0,0 +1,32 @@
#pragma once
#include "coding/reader.hpp"
#include "coding/write_to_sink.hpp"
#include "std/cstdint.hpp"
namespace feature
{
class RoutingSectionHeader final
{
public:
RoutingSectionHeader() : m_version(0) {}
uint8_t GetVersion() const { return m_version; }
template <class Sink>
void Serialize(Sink & sink) const
{
WriteToSink(sink, m_version);
}
template <class Source>
void Deserialize(Source & src)
{
m_version = ReadPrimitiveFromSource<decltype(m_version)>(src);
}
private:
uint8_t m_version;
};
} // namespace feature

View file

@ -14,6 +14,7 @@
#include "routing/route.hpp"
#include "routing/routing_algorithm.hpp"
#include "routing/routing_helpers.hpp"
#include "routing/single_mwm_router.hpp"
#include "search/downloader_search_callback.hpp"
#include "search/editor_delegate.hpp"
@ -2445,7 +2446,7 @@ void Framework::SetRouterImpl(RouterType type)
router.reset(
new CarRouter(m_model.GetIndex(), countryFileGetter,
CreateCarAStarBidirectionalRouter(m_model.GetIndex(), countryFileGetter)));
SingleMwmRouter::CreateCarRouter(m_model.GetIndex())));
fetcher.reset(new OnlineAbsentCountriesFetcher(countryFileGetter, localFileChecker));
m_routingSession.SetRoutingSettings(routing::GetCarRoutingSettings());
}

View file

@ -61,13 +61,13 @@ public:
using TOnVisitedVertexCallback = std::function<void(TVertexType const &, TVertexType const &)>;
Result FindPath(TGraphType const & graph,
Result FindPath(TGraphType & graph,
TVertexType const & startVertex, TVertexType const & finalVertex,
RoutingResult<TVertexType> & result,
my::Cancellable const & cancellable = my::Cancellable(),
TOnVisitedVertexCallback onVisitedVertexCallback = nullptr) const;
Result FindPathBidirectional(TGraphType const & graph,
Result FindPathBidirectional(TGraphType & graph,
TVertexType const & startVertex, TVertexType const & finalVertex,
RoutingResult<TVertexType> & result,
my::Cancellable const & cancellable = my::Cancellable(),
@ -104,7 +104,7 @@ private:
struct BidirectionalStepContext
{
BidirectionalStepContext(bool forward, TVertexType const & startVertex,
TVertexType const & finalVertex, TGraphType const & graph)
TVertexType const & finalVertex, TGraphType & graph)
: forward(forward), startVertex(startVertex), finalVertex(finalVertex), graph(graph)
{
bestVertex = forward ? startVertex : finalVertex;
@ -151,7 +151,7 @@ private:
bool const forward;
TVertexType const & startVertex;
TVertexType const & finalVertex;
TGraph const & graph;
TGraph & graph;
priority_queue<State, vector<State>, greater<State>> queue;
map<TVertexType, double> bestDistance;
@ -182,7 +182,7 @@ private:
template <typename TGraph>
typename AStarAlgorithm<TGraph>::Result AStarAlgorithm<TGraph>::FindPath(
TGraphType const & graph,
TGraphType & graph,
TVertexType const & startVertex, TVertexType const & finalVertex,
RoutingResult<TVertexType> & result,
my::Cancellable const & cancellable,
@ -257,7 +257,7 @@ typename AStarAlgorithm<TGraph>::Result AStarAlgorithm<TGraph>::FindPath(
template <typename TGraph>
typename AStarAlgorithm<TGraph>::Result AStarAlgorithm<TGraph>::FindPathBidirectional(
TGraphType const & graph,
TGraphType & graph,
TVertexType const & startVertex, TVertexType const & finalVertex,
RoutingResult<TVertexType> & result,
my::Cancellable const & cancellable,

View file

@ -244,8 +244,8 @@ bool CarRouter::CheckRoutingAbility(m2::PointD const & startPoint, m2::PointD co
}
CarRouter::CarRouter(Index & index, TCountryFileFn const & countryFileFn,
unique_ptr<IRouter> router)
: m_index(index), m_indexManager(countryFileFn, index), m_router(move(router))
unique_ptr<SingleMwmRouter> localRouter)
: m_index(index), m_indexManager(countryFileFn, index), m_router(move(localRouter))
{
}
@ -256,11 +256,6 @@ void CarRouter::ClearState()
m_cachedTargets.clear();
m_cachedTargetPoint = m2::PointD::Zero();
m_indexManager.Clear();
if (m_router)
m_router->ClearState();
else
LOG(LERROR, ("m_router is not initialized."));
}
bool CarRouter::FindRouteMSMT(TFeatureGraphNodeVec const & sources,
@ -570,10 +565,11 @@ IRouter::ResultCode CarRouter::FindSingleRouteDispatcher(FeatureGraphNode const
LOG(LERROR, ("m_router is not initialized."));
return IRouter::InternalError;
}
LOG(LINFO, (m_router->GetName(), "route from", MercatorBounds::ToLatLon(source.segmentPoint), "to",
MercatorBounds::ToLatLon(target.segmentPoint)));
result = m_router->CalculateRoute(source.segmentPoint, m2::PointD(0, 0) /* direction */,
target.segmentPoint, delegate, mwmRoute);
LOG(LINFO, (m_router->GetName(), "route from", MercatorBounds::ToLatLon(source.segmentPoint),
"to", MercatorBounds::ToLatLon(target.segmentPoint)));
result = m_router->CalculateRoute(source.mwmId, source.segmentPoint,
m2::PointD(0, 0) /* direction */, target.segmentPoint,
delegate, mwmRoute);
}
else
{

View file

@ -5,6 +5,7 @@
#include "routing/route.hpp"
#include "routing/router.hpp"
#include "routing/routing_mapping.hpp"
#include "routing/single_mwm_router.hpp"
#include "std/unique_ptr.hpp"
#include "std/vector.hpp"
@ -34,7 +35,7 @@ public:
typedef vector<double> GeomTurnCandidateT;
CarRouter(Index & index, TCountryFileFn const & countryFileFn,
unique_ptr<IRouter> roadGraphRouter);
unique_ptr<SingleMwmRouter> localRouter);
virtual string GetName() const override;
@ -114,6 +115,6 @@ private:
RoutingIndexManager m_indexManager;
unique_ptr<IRouter> m_router;
unique_ptr<SingleMwmRouter> m_router;
};
} // namespace routing

View file

@ -10,7 +10,7 @@ namespace
{
/// Function to run AStar Algorithm from the base.
IRouter::ResultCode CalculateRoute(BorderCross const & startPos, BorderCross const & finalPos,
CrossMwmGraph const & roadGraph, RouterDelegate const & delegate,
CrossMwmGraph & roadGraph, RouterDelegate const & delegate,
RoutingResult<BorderCross> & route)
{
using TAlgorithm = AStarAlgorithm<CrossMwmGraph>;

View file

@ -9,7 +9,6 @@
namespace routing
{
class IDirectionsEngine
{
public:
@ -17,8 +16,7 @@ public:
virtual void Generate(IRoadGraph const & graph, vector<Junction> const & path,
Route::TTimes & times, Route::TTurns & turns,
vector<Junction> & routeGeometry,
my::Cancellable const & cancellable) = 0;
vector<Junction> & routeGeometry, my::Cancellable const & cancellable) = 0;
protected:
/// \brief constructs route based on |graph| and |path|. Fills |routeEdges| with the route.
@ -30,5 +28,4 @@ protected:
void CalculateTimes(IRoadGraph const & graph, vector<Junction> const & path,
Route::TTimes & times) const;
};
} // namespace routing

View file

@ -0,0 +1,64 @@
#include "routing/edge_estimator.hpp"
#include "std/algorithm.hpp"
namespace routing
{
double constexpr kKMPH2MPS = 1000.0 / (60 * 60);
inline double TimeBetweenSec(m2::PointD const & from, m2::PointD const & to, double speedMPS)
{
ASSERT_GREATER(speedMPS, 0.0, ());
double const distanceM = MercatorBounds::DistanceOnEarth(from, to);
return distanceM / speedMPS;
}
class CarEdgeEstimator : public EdgeEstimator
{
public:
CarEdgeEstimator(IVehicleModel const & vehicleModel);
// EdgeEstimator overrides:
double CalcEdgesWeight(RoadGeometry const & road, uint32_t pointFrom,
uint32_t pointTo) const override;
double CalcHeuristic(m2::PointD const & from, m2::PointD const & to) const override;
private:
double const m_maxSpeedMPS;
};
CarEdgeEstimator::CarEdgeEstimator(IVehicleModel const & vehicleModel)
: m_maxSpeedMPS(vehicleModel.GetMaxSpeed() * kKMPH2MPS)
{
}
double CarEdgeEstimator::CalcEdgesWeight(RoadGeometry const & road, uint32_t pointFrom,
uint32_t pointTo) const
{
uint32_t const start = min(pointFrom, pointTo);
uint32_t const finish = max(pointFrom, pointTo);
ASSERT_LESS(finish, road.GetPointsCount(), ());
double result = 0.0;
double const speedMPS = road.GetSpeed() * kKMPH2MPS;
for (uint32_t i = start; i < finish; ++i)
result += TimeBetweenSec(road.GetPoint(i), road.GetPoint(i + 1), speedMPS);
return result;
}
double CarEdgeEstimator::CalcHeuristic(m2::PointD const & from, m2::PointD const & to) const
{
return TimeBetweenSec(from, to, m_maxSpeedMPS);
}
} // namespace
namespace routing
{
// static
shared_ptr<EdgeEstimator> EdgeEstimator::CreateForCar(IVehicleModel const & vehicleModel)
{
return make_shared<CarEdgeEstimator>(vehicleModel);
}
} // namespace routing

View file

@ -0,0 +1,24 @@
#pragma once
#include "routing/geometry.hpp"
#include "routing/vehicle_model.hpp"
#include "geometry/point2d.hpp"
#include "std/cstdint.hpp"
#include "std/shared_ptr.hpp"
namespace routing
{
class EdgeEstimator
{
public:
virtual ~EdgeEstimator() = default;
virtual double CalcEdgesWeight(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);
};
} // namespace routing

View file

@ -47,8 +47,8 @@ FeaturesRoadGraph::Value::Value(MwmSet::MwmHandle handle) : m_mwmHandle(move(han
}
FeaturesRoadGraph::CrossCountryVehicleModel::CrossCountryVehicleModel(
unique_ptr<VehicleModelFactory> vehicleModelFactory)
: m_vehicleModelFactory(move(vehicleModelFactory))
shared_ptr<VehicleModelFactory> vehicleModelFactory)
: m_vehicleModelFactory(vehicleModelFactory)
, m_maxSpeedKMPH(m_vehicleModelFactory->GetVehicleModel()->GetMaxSpeed())
{
}
@ -108,8 +108,8 @@ void FeaturesRoadGraph::RoadInfoCache::Clear()
m_cache.clear();
}
FeaturesRoadGraph::FeaturesRoadGraph(Index const & index, IRoadGraph::Mode mode,
unique_ptr<VehicleModelFactory> vehicleModelFactory)
: m_index(index), m_mode(mode), m_vehicleModel(move(vehicleModelFactory))
shared_ptr<VehicleModelFactory> vehicleModelFactory)
: m_index(index), m_mode(mode), m_vehicleModel(vehicleModelFactory)
{
}

View file

@ -26,7 +26,7 @@ private:
class CrossCountryVehicleModel : public IVehicleModel
{
public:
CrossCountryVehicleModel(unique_ptr<VehicleModelFactory> vehicleModelFactory);
CrossCountryVehicleModel(shared_ptr<VehicleModelFactory> vehicleModelFactory);
// IVehicleModel overrides:
double GetSpeed(FeatureType const & f) const override;
@ -39,7 +39,7 @@ private:
private:
IVehicleModel * GetVehicleModel(FeatureID const & featureId) const;
unique_ptr<VehicleModelFactory> const m_vehicleModelFactory;
shared_ptr<VehicleModelFactory> const m_vehicleModelFactory;
double const m_maxSpeedKMPH;
mutable map<MwmSet::MwmId, shared_ptr<IVehicleModel>> m_cache;
@ -59,7 +59,7 @@ private:
public:
FeaturesRoadGraph(Index const & index, IRoadGraph::Mode mode,
unique_ptr<VehicleModelFactory> vehicleModelFactory);
shared_ptr<VehicleModelFactory> vehicleModelFactory);
static uint32_t GetStreetReadScale();

96
routing/geometry.cpp Normal file
View file

@ -0,0 +1,96 @@
#include "routing/geometry.hpp"
#include "routing/routing_exception.hpp"
#include "geometry/mercator.hpp"
#include "base/assert.hpp"
#include "std/string.hpp"
using namespace routing;
namespace
{
class GeometryLoaderImpl final : public GeometryLoader
{
public:
GeometryLoaderImpl(Index const & index, MwmSet::MwmId const & mwmId, string const & country,
shared_ptr<IVehicleModel> vehicleModel);
// GeometryLoader overrides:
virtual void Load(uint32_t featureId, RoadGeometry & road) const override;
private:
shared_ptr<IVehicleModel> m_vehicleModel;
Index::FeaturesLoaderGuard m_guard;
string const m_country;
};
GeometryLoaderImpl::GeometryLoaderImpl(Index const & index, MwmSet::MwmId const & mwmId,
string const & country,
shared_ptr<IVehicleModel> vehicleModel)
: m_vehicleModel(vehicleModel), m_guard(index, mwmId), m_country(country)
{
ASSERT(m_vehicleModel, ());
}
void GeometryLoaderImpl::Load(uint32_t featureId, RoadGeometry & road) const
{
FeatureType feature;
bool const isFound = m_guard.GetFeatureByIndex(featureId, feature);
if (!isFound)
MYTHROW(RoutingException, ("Feature", featureId, "not found in ", m_country));
feature.ParseGeometry(FeatureType::BEST_GEOMETRY);
road.Load(*m_vehicleModel, feature);
}
} // namespace
namespace routing
{
// RoadGeometry ------------------------------------------------------------------------------------
RoadGeometry::RoadGeometry(bool oneWay, double speed, Points const & points)
: m_points(points), m_speed(speed), m_isRoad(true), m_isOneWay(oneWay)
{
ASSERT_GREATER(speed, 0.0, ());
}
void RoadGeometry::Load(IVehicleModel const & vehicleModel, FeatureType const & feature)
{
m_isRoad = vehicleModel.IsRoad(feature);
m_isOneWay = vehicleModel.IsOneWay(feature);
m_speed = vehicleModel.GetSpeed(feature);
m_points.clear();
m_points.reserve(feature.GetPointsCount());
for (size_t i = 0; i < feature.GetPointsCount(); ++i)
m_points.emplace_back(feature.GetPoint(i));
}
// Geometry ----------------------------------------------------------------------------------------
Geometry::Geometry(unique_ptr<GeometryLoader> loader) : m_loader(move(loader))
{
ASSERT(m_loader, ());
}
RoadGeometry const & Geometry::GetRoad(uint32_t featureId)
{
auto const & it = m_roads.find(featureId);
if (it != m_roads.cend())
return it->second;
RoadGeometry & road = m_roads[featureId];
m_loader->Load(featureId, road);
return road;
}
// static
unique_ptr<GeometryLoader> GeometryLoader::Create(Index const & index, MwmSet::MwmId const & mwmId,
shared_ptr<IVehicleModel> vehicleModel)
{
CHECK(mwmId.IsAlive(), ());
return make_unique<GeometryLoaderImpl>(index, mwmId, mwmId.GetInfo()->GetCountryName(),
vehicleModel);
}
} // namespace routing

80
routing/geometry.hpp Normal file
View file

@ -0,0 +1,80 @@
#pragma once
#include "routing/road_point.hpp"
#include "routing/vehicle_model.hpp"
#include "indexer/index.hpp"
#include "geometry/point2d.hpp"
#include "base/buffer_vector.hpp"
#include "std/cstdint.hpp"
#include "std/shared_ptr.hpp"
#include "std/unique_ptr.hpp"
namespace routing
{
class RoadGeometry final
{
public:
using Points = buffer_vector<m2::PointD, 32>;
RoadGeometry() = default;
RoadGeometry(bool oneWay, double speed, Points const & points);
void Load(IVehicleModel const & vehicleModel, FeatureType const & feature);
bool IsRoad() const { return m_isRoad; }
bool IsOneWay() const { return m_isOneWay; }
// Kilometers per hour.
double GetSpeed() const { return m_speed; }
m2::PointD const & GetPoint(uint32_t pointId) const
{
ASSERT_LESS(pointId, m_points.size(), ());
return m_points[pointId];
}
uint32_t GetPointsCount() const { return m_points.size(); }
private:
Points m_points;
double m_speed = 0.0;
bool m_isRoad = false;
bool m_isOneWay = false;
};
class GeometryLoader
{
public:
virtual ~GeometryLoader() = default;
virtual void Load(uint32_t featureId, RoadGeometry & road) const = 0;
// mwmId should be alive: it is caller responsibility to check it.
static unique_ptr<GeometryLoader> Create(Index const & index, MwmSet::MwmId const & mwmId,
shared_ptr<IVehicleModel> vehicleModel);
};
class Geometry final
{
public:
Geometry() = default;
explicit Geometry(unique_ptr<GeometryLoader> loader);
RoadGeometry const & GetRoad(uint32_t featureId);
m2::PointD const & GetPoint(RoadPoint const & rp)
{
return GetRoad(rp.GetFeatureId()).GetPoint(rp.GetPointId());
}
private:
// Feature id to RoadGeometry map.
unordered_map<uint32_t, RoadGeometry> m_roads;
unique_ptr<GeometryLoader> m_loader;
};
} // namespace routing

93
routing/index_graph.cpp Normal file
View file

@ -0,0 +1,93 @@
#include "index_graph.hpp"
#include "base/assert.hpp"
#include "base/exception.hpp"
namespace routing
{
IndexGraph::IndexGraph(unique_ptr<GeometryLoader> loader, shared_ptr<EdgeEstimator> estimator)
: m_geometry(move(loader)), m_estimator(move(estimator))
{
ASSERT(m_estimator, ());
}
void IndexGraph::GetEdgeList(Joint::Id jointId, bool isOutgoing, vector<JointEdge> & edges)
{
m_jointIndex.ForEachPoint(jointId, [this, &edges, isOutgoing](RoadPoint const & rp) {
GetNeighboringEdges(rp, isOutgoing, edges);
});
}
m2::PointD const & IndexGraph::GetPoint(Joint::Id jointId)
{
return m_geometry.GetPoint(m_jointIndex.GetPoint(jointId));
}
void IndexGraph::Import(vector<Joint> const & joints)
{
m_roadIndex.Import(joints);
m_jointIndex.Build(m_roadIndex, joints.size());
}
Joint::Id IndexGraph::InsertJoint(RoadPoint const & rp)
{
Joint::Id const existId = m_roadIndex.GetJointId(rp);
if (existId != Joint::kInvalidId)
return existId;
Joint::Id const jointId = m_jointIndex.InsertJoint(rp);
m_roadIndex.AddJoint(rp, jointId);
return jointId;
}
bool IndexGraph::JointLiesOnRoad(Joint::Id jointId, uint32_t featureId) const
{
bool result = false;
m_jointIndex.ForEachPoint(jointId, [&result, featureId](RoadPoint const & rp) {
if (rp.GetFeatureId() == featureId)
result = true;
});
return result;
}
void IndexGraph::GetNeighboringEdges(RoadPoint const & rp, bool isOutgoing,
vector<JointEdge> & edges)
{
RoadGeometry const & road = m_geometry.GetRoad(rp.GetFeatureId());
if (!road.IsRoad())
return;
bool const bidirectional = !road.IsOneWay();
if (!isOutgoing || bidirectional)
GetNeighboringEdge(road, rp, false /* forward */, edges);
if (isOutgoing || bidirectional)
GetNeighboringEdge(road, rp, true /* forward */, edges);
}
inline void IndexGraph::GetNeighboringEdge(RoadGeometry const & road, RoadPoint const & rp,
bool forward, vector<JointEdge> & edges) 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);
edges.push_back({neighbor.first, distance});
}
}
void IndexGraph::GetDirectedEdge(uint32_t featureId, uint32_t pointFrom, uint32_t pointTo,
Joint::Id target, bool forward, vector<JointEdge> & edges)
{
RoadGeometry const & road = m_geometry.GetRoad(featureId);
if (!road.IsRoad())
return;
if (road.IsOneWay() && forward != (pointFrom < pointTo))
return;
double const distance = m_estimator->CalcEdgesWeight(road, pointFrom, pointTo);
edges.emplace_back(target, distance);
}
} // namespace routing

92
routing/index_graph.hpp Normal file
View file

@ -0,0 +1,92 @@
#pragma once
#include "routing/edge_estimator.hpp"
#include "routing/geometry.hpp"
#include "routing/joint.hpp"
#include "routing/joint_index.hpp"
#include "routing/road_index.hpp"
#include "routing/road_point.hpp"
#include "coding/reader.hpp"
#include "coding/write_to_sink.hpp"
#include "geometry/point2d.hpp"
#include "std/cstdint.hpp"
#include "std/shared_ptr.hpp"
#include "std/unique_ptr.hpp"
#include "std/utility.hpp"
#include "std/vector.hpp"
namespace routing
{
class JointEdge final
{
public:
JointEdge(Joint::Id target, double weight) : m_target(target), m_weight(weight) {}
Joint::Id GetTarget() const { return m_target; }
double GetWeight() const { return m_weight; }
private:
// Target is vertex going to for outgoing edges, vertex going from for ingoing edges.
Joint::Id const m_target;
double const m_weight;
};
class IndexGraph final
{
public:
IndexGraph() = default;
explicit IndexGraph(unique_ptr<GeometryLoader> loader, shared_ptr<EdgeEstimator> estimator);
// Creates edge for points in same feature.
void GetDirectedEdge(uint32_t featureId, uint32_t pointFrom, uint32_t pointTo, Joint::Id target,
bool forward, vector<JointEdge> & edges);
void GetNeighboringEdges(RoadPoint const & rp, bool isOutgoing, vector<JointEdge> & edges);
// Put outgoing (or ingoing) egdes for jointId to the 'edges' vector.
void GetEdgeList(Joint::Id jointId, bool isOutgoing, vector<JointEdge> & edges);
Joint::Id GetJointId(RoadPoint const & rp) const { return m_roadIndex.GetJointId(rp); }
m2::PointD const & GetPoint(Joint::Id jointId);
Geometry & GetGeometry() { return m_geometry; }
EdgeEstimator const & GetEstimator() const { return *m_estimator; }
uint32_t GetNumRoads() const { return m_roadIndex.GetSize(); }
uint32_t GetNumJoints() const { return m_jointIndex.GetNumJoints(); }
uint32_t GetNumPoints() const { return m_jointIndex.GetNumPoints(); }
void Import(vector<Joint> const & joints);
Joint::Id InsertJoint(RoadPoint const & rp);
bool JointLiesOnRoad(Joint::Id jointId, uint32_t featureId) const;
template <typename F>
void ForEachPoint(Joint::Id jointId, F && f) const
{
m_jointIndex.ForEachPoint(jointId, forward<F>(f));
}
template <class Sink>
void Serialize(Sink & sink) const
{
WriteToSink(sink, static_cast<uint32_t>(GetNumJoints()));
m_roadIndex.Serialize(sink);
}
template <class Source>
void Deserialize(Source & src)
{
uint32_t const jointsSize = ReadPrimitiveFromSource<uint32_t>(src);
m_roadIndex.Deserialize(src);
m_jointIndex.Build(m_roadIndex, jointsSize);
}
private:
void GetNeighboringEdge(RoadGeometry const & road, RoadPoint const & rp, bool forward,
vector<JointEdge> & edges) const;
Geometry m_geometry;
shared_ptr<EdgeEstimator> m_estimator;
RoadIndex m_roadIndex;
JointIndex m_jointIndex;
};
} // namespace routing

View file

@ -0,0 +1,195 @@
#include "routing/index_graph_starter.hpp"
#include "routing/routing_exception.hpp"
namespace routing
{
IndexGraphStarter::IndexGraphStarter(IndexGraph & graph, RoadPoint const & startPoint,
RoadPoint const & finishPoint)
: m_graph(graph)
, m_start(graph, startPoint, graph.GetNumJoints())
, m_finish(graph, finishPoint, graph.GetNumJoints() + 1)
{
m_start.SetupJointId(graph);
if (startPoint == finishPoint)
m_finish.m_jointId = m_start.m_jointId;
else
m_finish.SetupJointId(graph);
}
m2::PointD const & IndexGraphStarter::GetPoint(Joint::Id jointId)
{
if (jointId == m_start.m_fakeId)
return m_graph.GetGeometry().GetPoint(m_start.m_point);
if (jointId == m_finish.m_fakeId)
return m_graph.GetGeometry().GetPoint(m_finish.m_point);
return m_graph.GetPoint(jointId);
}
void IndexGraphStarter::RedressRoute(vector<Joint::Id> const & route,
vector<RoadPoint> & roadPoints)
{
if (route.size() < 2)
{
if (route.size() == 1)
roadPoints.emplace_back(m_start.m_point);
return;
}
roadPoints.reserve(route.size() * 2);
for (size_t i = 0; i < route.size() - 1; ++i)
{
Joint::Id const prevJoint = route[i];
Joint::Id const nextJoint = route[i + 1];
RoadPoint rp0;
RoadPoint rp1;
FindPointsWithCommonFeature(prevJoint, nextJoint, rp0, rp1);
if (i == 0)
roadPoints.emplace_back(rp0);
uint32_t const featureId = rp0.GetFeatureId();
uint32_t const pointFrom = rp0.GetPointId();
uint32_t const pointTo = rp1.GetPointId();
if (pointFrom < pointTo)
{
for (uint32_t pointId = pointFrom + 1; pointId < pointTo; ++pointId)
roadPoints.emplace_back(featureId, pointId);
}
else if (pointFrom > pointTo)
{
for (uint32_t pointId = pointFrom - 1; pointId > pointTo; --pointId)
roadPoints.emplace_back(featureId, pointId);
}
else
{
CHECK(false,
("Wrong equality pointFrom = pointTo =", pointFrom, ", featureId = ", featureId));
}
roadPoints.emplace_back(rp1);
}
}
void IndexGraphStarter::GetEdgesList(Joint::Id jointId, bool isOutgoing, vector<JointEdge> & edges)
{
edges.clear();
if (jointId == m_start.m_fakeId)
{
GetFakeEdges(m_start, m_finish, isOutgoing, edges);
return;
}
if (jointId == m_finish.m_fakeId)
{
GetFakeEdges(m_finish, m_start, isOutgoing, edges);
return;
}
m_graph.GetEdgeList(jointId, isOutgoing, edges);
GetArrivalFakeEdges(jointId, m_start, isOutgoing, edges);
GetArrivalFakeEdges(jointId, m_finish, isOutgoing, edges);
}
void IndexGraphStarter::GetFakeEdges(IndexGraphStarter::FakeJoint const & from,
IndexGraphStarter::FakeJoint const & to, bool isOutgoing,
vector<JointEdge> & edges)
{
m_graph.GetNeighboringEdges(from.m_point, isOutgoing, edges);
if (!to.BelongsToGraph() && from.m_point.GetFeatureId() == to.m_point.GetFeatureId())
{
m_graph.GetDirectedEdge(from.m_point.GetFeatureId(), from.m_point.GetPointId(),
to.m_point.GetPointId(), to.m_jointId, isOutgoing, edges);
}
}
void IndexGraphStarter::GetArrivalFakeEdges(Joint::Id jointId,
IndexGraphStarter::FakeJoint const & fakeJoint,
bool isOutgoing, vector<JointEdge> & edges)
{
if (fakeJoint.BelongsToGraph())
return;
if (!m_graph.JointLiesOnRoad(jointId, fakeJoint.m_point.GetFeatureId()))
return;
vector<JointEdge> startEdges;
m_graph.GetNeighboringEdges(fakeJoint.m_point, !isOutgoing, startEdges);
for (JointEdge const & edge : startEdges)
{
if (edge.GetTarget() == jointId)
edges.emplace_back(fakeJoint.m_jointId, edge.GetWeight());
}
}
void IndexGraphStarter::FindPointsWithCommonFeature(Joint::Id jointId0, Joint::Id jointId1,
RoadPoint & result0, RoadPoint & result1)
{
bool found = false;
double minWeight = -1.0;
ForEachPoint(jointId0, [&](RoadPoint const & rp0) {
ForEachPoint(jointId1, [&](RoadPoint const & rp1) {
if (rp0.GetFeatureId() != rp1.GetFeatureId())
return;
RoadGeometry const & road = m_graph.GetGeometry().GetRoad(rp0.GetFeatureId());
if (!road.IsRoad())
return;
if (road.IsOneWay() && rp0.GetPointId() > rp1.GetPointId())
return;
if (found)
{
if (minWeight < 0.0)
{
// 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());
}
double const weight =
m_graph.GetEstimator().CalcEdgesWeight(road, rp0.GetPointId(), rp1.GetPointId());
if (weight < minWeight)
{
minWeight = weight;
result0 = rp0;
result1 = rp1;
}
}
else
{
result0 = rp0;
result1 = rp1;
found = true;
}
});
});
CHECK(found, ("Can't find common feature for joints", jointId0, jointId1));
}
// IndexGraphStarter::FakeJoint --------------------------------------------------------------------
IndexGraphStarter::FakeJoint::FakeJoint(IndexGraph const & graph, RoadPoint const & point,
Joint::Id fakeId)
: m_point(point), m_fakeId(fakeId), m_jointId(Joint::kInvalidId)
{
}
void IndexGraphStarter::FakeJoint::SetupJointId(IndexGraph const & graph)
{
m_jointId = graph.GetJointId(m_point);
if (m_jointId == Joint::kInvalidId)
m_jointId = m_fakeId;
}
} // namespace routing

View file

@ -0,0 +1,98 @@
#pragma once
#include "routing/index_graph.hpp"
#include "routing/joint.hpp"
#include "std/utility.hpp"
namespace routing
{
// The problem:
// IndexGraph contains only road points connected in joints.
// So it is possible IndexGraph doesn't contain start and finish.
//
// IndexGraphStarter adds fake start and finish joint ids for AStarAlgorithm.
//
class IndexGraphStarter final
{
public:
// AStarAlgorithm types aliases:
using TVertexType = Joint::Id;
using TEdgeType = JointEdge;
IndexGraphStarter(IndexGraph & graph, RoadPoint const & startPoint,
RoadPoint const & finishPoint);
IndexGraph & GetGraph() const { return m_graph; }
Joint::Id GetStartJoint() const { return m_start.m_jointId; }
Joint::Id GetFinishJoint() const { return m_finish.m_jointId; }
m2::PointD const & GetPoint(Joint::Id jointId);
void GetOutgoingEdgesList(Joint::Id jointId, vector<JointEdge> & edges)
{
GetEdgesList(jointId, true /* isOutgoing */, edges);
}
void GetIngoingEdgesList(Joint::Id jointId, vector<JointEdge> & edges)
{
GetEdgesList(jointId, false /* isOutgoing */, edges);
}
double HeuristicCostEstimate(Joint::Id from, Joint::Id to)
{
return m_graph.GetEstimator().CalcHeuristic(GetPoint(from), GetPoint(to));
}
// Add intermediate points to route (those don't correspond to any joint).
//
// Also convert joint ids to RoadPoints.
void RedressRoute(vector<Joint::Id> const & route, vector<RoadPoint> & roadPoints);
private:
struct FakeJoint final
{
FakeJoint(IndexGraph const & graph, RoadPoint const & point, Joint::Id fakeId);
void SetupJointId(IndexGraph const & graph);
bool BelongsToGraph() const { return m_jointId != m_fakeId; }
RoadPoint const m_point;
Joint::Id const m_fakeId;
Joint::Id m_jointId;
};
template <typename F>
void ForEachPoint(Joint::Id jointId, F && f) const
{
if (jointId == m_start.m_fakeId)
{
f(m_start.m_point);
return;
}
if (jointId == m_finish.m_fakeId)
{
f(m_finish.m_point);
return;
}
m_graph.ForEachPoint(jointId, forward<F>(f));
}
void GetEdgesList(Joint::Id jointId, bool isOutgoing, vector<JointEdge> & edges);
void GetFakeEdges(FakeJoint const & from, FakeJoint const & to, bool isOutgoing,
vector<JointEdge> & edges);
void GetArrivalFakeEdges(Joint::Id jointId, FakeJoint const & fakeJoint, bool isOutgoing,
vector<JointEdge> & edges);
// Find two road points lying on the same feature.
// If there are several pairs of such points, return pair with minimal distance.
void FindPointsWithCommonFeature(Joint::Id jointId0, Joint::Id jointId1, RoadPoint & result0,
RoadPoint & result1);
IndexGraph & m_graph;
FakeJoint m_start;
FakeJoint m_finish;
};
} // namespace routing

7
routing/joint.cpp Normal file
View file

@ -0,0 +1,7 @@
#include "routing/joint.hpp"
namespace routing
{
// static
Joint::Id constexpr Joint::kInvalidId;
} // namespace routing

29
routing/joint.hpp Normal file
View file

@ -0,0 +1,29 @@
#pragma once
#include "routing/road_point.hpp"
#include "base/buffer_vector.hpp"
#include "std/cstdint.hpp"
#include "std/limits.hpp"
namespace routing
{
// Joint represents roads connection.
// It contains RoadPoint for each connected road.
class Joint final
{
public:
using Id = uint32_t;
static Id constexpr kInvalidId = numeric_limits<Id>::max();
void AddPoint(RoadPoint const & rp) { m_points.emplace_back(rp); }
size_t GetSize() const { return m_points.size(); }
RoadPoint const & GetEntry(size_t i) const { return m_points[i]; }
private:
buffer_vector<RoadPoint, 2> m_points;
};
} // namespace routing

61
routing/joint_index.cpp Normal file
View file

@ -0,0 +1,61 @@
#include "routing/joint_index.hpp"
#include "routing/routing_exception.hpp"
namespace routing
{
Joint::Id JointIndex::InsertJoint(RoadPoint const & rp)
{
Joint::Id const jointId = GetNumJoints();
m_points.emplace_back(rp);
m_offsets.emplace_back(m_points.size());
return jointId;
}
void JointIndex::AppendToJoint(Joint::Id jointId, RoadPoint const & rp)
{
m_dynamicJoints[jointId].AddPoint(rp);
}
void JointIndex::Build(RoadIndex const & roadIndex, uint32_t numJoints)
{
m_dynamicJoints.clear();
// + 1 is protection for 'End' method from out of bounds.
// Call End(numJoints-1) requires more size, so add one more item.
// Therefore m_offsets.size() == numJoints + 1,
// And m_offsets.back() == m_points.size()
m_offsets.assign(numJoints + 1, 0);
// Calculate sizes.
// Example for numJoints = 6:
// 2, 5, 3, 4, 2, 3, 0
roadIndex.ForEachRoad([this, numJoints](uint32_t /* featureId */, RoadJointIds const & road) {
road.ForEachJoint([this, numJoints](uint32_t /* pointId */, Joint::Id jointId) {
ASSERT_LESS(jointId, numJoints, ());
++m_offsets[jointId];
});
});
// Fill offsets with end bounds.
// Example: 2, 7, 10, 14, 16, 19, 19
for (size_t i = 1; i < m_offsets.size(); ++i)
m_offsets[i] += m_offsets[i - 1];
m_points.resize(m_offsets.back());
// Now fill points.
// Offsets after this operation are begin bounds:
// 0, 2, 7, 10, 14, 16, 19
roadIndex.ForEachRoad([this](uint32_t featureId, RoadJointIds const & road) {
road.ForEachJoint([this, featureId](uint32_t pointId, Joint::Id jointId) {
uint32_t & offset = m_offsets[jointId];
--offset;
m_points[offset] = {featureId, pointId};
});
});
CHECK_EQUAL(m_offsets[0], 0, ());
CHECK_EQUAL(m_offsets.back(), m_points.size(), ());
}
} // namespace routing

69
routing/joint_index.hpp Normal file
View file

@ -0,0 +1,69 @@
#pragma once
#include "routing/joint.hpp"
#include "routing/road_index.hpp"
#include "routing/road_point.hpp"
#include "base/assert.hpp"
#include "std/vector.hpp"
namespace routing
{
// JointIndex contains mapping from Joint::Id to RoadPoints.
//
// It is vector<Joint> conceptually.
// Technically Joint entries are joined into the single vector to reduce allocations overheads.
class JointIndex final
{
public:
// Read comments in Build method about -1.
uint32_t GetNumJoints() const
{
CHECK_GREATER(m_offsets.size(), 0, ());
return m_offsets.size() - 1;
}
uint32_t GetNumPoints() const { return m_points.size(); }
RoadPoint GetPoint(Joint::Id jointId) const { return m_points[Begin(jointId)]; }
template <typename F>
void ForEachPoint(Joint::Id jointId, F && f) const
{
for (uint32_t i = Begin(jointId); i < End(jointId); ++i)
f(m_points[i]);
auto const & it = m_dynamicJoints.find(jointId);
if (it != m_dynamicJoints.end())
{
Joint const & joint = it->second;
for (size_t i = 0; i < joint.GetSize(); ++i)
f(joint.GetEntry(i));
}
}
void Build(RoadIndex const & roadIndex, uint32_t numJoints);
Joint::Id InsertJoint(RoadPoint const & rp);
void AppendToJoint(Joint::Id jointId, RoadPoint const & rp);
private:
// Begin index for jointId entries.
uint32_t Begin(Joint::Id jointId) const
{
ASSERT_LESS(jointId, m_offsets.size(), ());
return m_offsets[jointId];
}
// End index (not inclusive) for jointId entries.
uint32_t End(Joint::Id jointId) const
{
Joint::Id const nextId = jointId + 1;
ASSERT_LESS(nextId, m_offsets.size(), ());
return m_offsets[nextId];
}
vector<uint32_t> m_offsets;
vector<RoadPoint> m_points;
unordered_map<Joint::Id, Joint> m_dynamicJoints;
};
} // namespace routing

View file

@ -6,12 +6,12 @@ namespace routing
RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue)
: m_countryFileName(mwmValue.GetCountryFileName())
{
if (!mwmValue.m_cont.IsExist(ROUTING_FILE_TAG))
if (!mwmValue.m_cont.IsExist(RESTRICTIONS_FILE_TAG))
return;
try
{
m_reader = make_unique<FilesContainerR::TReader>(mwmValue.m_cont.GetReader(ROUTING_FILE_TAG));
m_reader = make_unique<FilesContainerR::TReader>(mwmValue.m_cont.GetReader(RESTRICTIONS_FILE_TAG));
ReaderSource<FilesContainerR::TReader> src(*m_reader);
m_header.Deserialize(src);
@ -21,7 +21,7 @@ RestrictionLoader::RestrictionLoader(MwmValue const & mwmValue)
{
m_header.Reset();
LOG(LERROR,
("File", m_countryFileName, "Error while reading", ROUTING_FILE_TAG, "section.", e.Msg()));
("File", m_countryFileName, "Error while reading", RESTRICTIONS_FILE_TAG, "section.", e.Msg()));
}
}
} // namespace routing

View file

@ -54,6 +54,7 @@ class Edge
public:
static Edge MakeFake(Junction const & startJunction, Junction const & endJunction);
Edge() : m_forward(true), m_segId(0) {}
Edge(FeatureID const & featureId, bool forward, uint32_t segId, Junction const & startJunction, Junction const & endJunction);
Edge(Edge const &) = default;
Edge & operator=(Edge const &) = default;

View file

@ -8,6 +8,8 @@
#include "routing/pedestrian_directions.hpp"
#include "routing/pedestrian_model.hpp"
#include "routing/route.hpp"
#include "routing/routing_helpers.hpp"
#include "routing/single_mwm_router.hpp"
#include "coding/reader_wrapper.hpp"
@ -225,7 +227,7 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(m2::PointD const & startPoin
ASSERT_EQUAL(result.path.front(), startPos, ());
ASSERT_EQUAL(result.path.back(), finalPos, ());
ASSERT_GREATER(result.distance, 0., ());
ReconstructRoute(move(result.path), route, delegate);
ReconstructRoute(m_directionsEngine.get(), *m_roadGraph, delegate, result.path, route);
}
m_roadGraph->ResetFakes();
@ -246,39 +248,6 @@ IRouter::ResultCode RoadGraphRouter::CalculateRoute(m2::PointD const & startPoin
return IRouter::RouteNotFound;
}
void RoadGraphRouter::ReconstructRoute(vector<Junction> && path, Route & route,
my::Cancellable const & cancellable) const
{
CHECK(!path.empty(), ("Can't reconstruct route from an empty list of positions."));
// By some reason there're two adjacent positions on a road with
// the same end-points. This could happen, for example, when
// direction on a road was changed. But it doesn't matter since
// this code reconstructs only geometry of a route.
path.erase(unique(path.begin(), path.end()), path.end());
if (path.size() == 1)
path.emplace_back(path.back());
Route::TTimes times;
Route::TTurns turnsDir;
vector<Junction> junctions;
// @TODO(bykoianko) streetNames is not filled in Generate(). It should be done.
Route::TStreets streetNames;
if (m_directionsEngine)
m_directionsEngine->Generate(*m_roadGraph, path, times, turnsDir, junctions, cancellable);
vector<m2::PointD> routeGeometry;
JunctionsToPoints(junctions, routeGeometry);
feature::TAltitudes altitudes;
JunctionsToAltitudes(junctions, altitudes);
route.SetGeometry(routeGeometry.begin(), routeGeometry.end());
route.SetSectionTimes(move(times));
route.SetTurnInstructions(move(turnsDir));
route.SetStreetNames(move(streetNames));
route.SetAltitudes(move(altitudes));
}
unique_ptr<IRouter> CreatePedestrianAStarRouter(Index & index, TCountryFileFn const & countryFileFn)
{
unique_ptr<VehicleModelFactory> vehicleModelFactory(new PedestrianModelFactory());
@ -311,18 +280,4 @@ unique_ptr<IRouter> CreateBicycleAStarBidirectionalRouter(Index & index, TCountr
move(vehicleModelFactory), move(algorithm), move(directionsEngine)));
return router;
}
unique_ptr<IRouter> CreateCarAStarBidirectionalRouter(Index & index,
TCountryFileFn const & countryFileFn)
{
unique_ptr<VehicleModelFactory> vehicleModelFactory = make_unique<CarModelFactory>();
unique_ptr<IRoutingAlgorithm> algorithm = make_unique<AStarBidirectionalRoutingAlgorithm>();
// @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.
unique_ptr<IDirectionsEngine> directionsEngine = make_unique<BicycleDirectionsEngine>(index);
unique_ptr<IRouter> router = make_unique<RoadGraphRouter>(
"astar-bidirectional-car", index, countryFileFn, IRoadGraph::Mode::ObeyOnewayTag,
move(vehicleModelFactory), move(algorithm), move(directionsEngine));
return router;
}
} // namespace routing

View file

@ -37,9 +37,6 @@ public:
Route & route) override;
private:
void ReconstructRoute(vector<Junction> && junctions, Route & route,
my::Cancellable const & cancellable) const;
/// Checks existance and add absent maps to route.
/// Returns true if map exists
bool CheckMapExistence(m2::PointD const & point, Route & route) const;
@ -55,6 +52,4 @@ private:
unique_ptr<IRouter> CreatePedestrianAStarRouter(Index & index, TCountryFileFn const & countryFileFn);
unique_ptr<IRouter> CreatePedestrianAStarBidirectionalRouter(Index & index, TCountryFileFn const & countryFileFn);
unique_ptr<IRouter> CreateBicycleAStarBidirectionalRouter(Index & index, TCountryFileFn const & countryFileFn);
unique_ptr<IRouter> CreateCarAStarBidirectionalRouter(Index & index,
TCountryFileFn const & countryFileFn);
} // namespace routing

29
routing/road_index.cpp Normal file
View file

@ -0,0 +1,29 @@
#include "routing/road_index.hpp"
#include "routing/routing_exception.hpp"
namespace routing
{
void RoadIndex::Import(vector<Joint> const & joints)
{
for (Joint::Id jointId = 0; jointId < joints.size(); ++jointId)
{
Joint const & joint = joints[jointId];
for (uint32_t i = 0; i < joint.GetSize(); ++i)
{
RoadPoint const & entry = joint.GetEntry(i);
RoadJointIds & roadJoints = m_roads[entry.GetFeatureId()];
roadJoints.AddJoint(entry.GetPointId(), jointId);
}
}
}
pair<Joint::Id, uint32_t> RoadIndex::FindNeighbor(RoadPoint const & rp, bool forward) const
{
auto const it = m_roads.find(rp.GetFeatureId());
if (it == m_roads.cend())
MYTHROW(RoutingException, ("RoadIndex doesn't contains feature", rp.GetFeatureId()));
return it->second.FindNeighbor(rp.GetPointId(), forward);
}
} // namespace routing

168
routing/road_index.hpp Normal file
View file

@ -0,0 +1,168 @@
#pragma once
#include "routing/joint.hpp"
#include "coding/reader.hpp"
#include "coding/write_to_sink.hpp"
#include "std/algorithm.hpp"
#include "std/cstdint.hpp"
#include "std/unordered_map.hpp"
#include "std/utility.hpp"
#include "std/vector.hpp"
namespace routing
{
class RoadJointIds final
{
public:
Joint::Id GetJointId(uint32_t pointId) const
{
if (pointId < m_jointIds.size())
return m_jointIds[pointId];
return Joint::kInvalidId;
}
void AddJoint(uint32_t pointId, Joint::Id jointId)
{
if (pointId >= m_jointIds.size())
m_jointIds.insert(m_jointIds.end(), pointId + 1 - m_jointIds.size(), Joint::kInvalidId);
ASSERT_EQUAL(m_jointIds[pointId], Joint::kInvalidId, ());
m_jointIds[pointId] = jointId;
}
template <typename F>
void ForEachJoint(F && f) const
{
for (uint32_t pointId = 0; pointId < m_jointIds.size(); ++pointId)
{
Joint::Id const jointId = m_jointIds[pointId];
if (jointId != Joint::kInvalidId)
f(pointId, jointId);
}
}
pair<Joint::Id, uint32_t> FindNeighbor(uint32_t pointId, bool forward) const
{
uint32_t const size = static_cast<uint32_t>(m_jointIds.size());
pair<Joint::Id, uint32_t> result = make_pair(Joint::kInvalidId, 0);
if (forward)
{
for (uint32_t i = pointId + 1; i < size; ++i)
{
Joint::Id const jointId = m_jointIds[i];
if (jointId != Joint::kInvalidId)
{
result = {jointId, i};
return result;
}
}
}
else
{
for (uint32_t i = min(pointId, size) - 1; i < size; --i)
{
Joint::Id const jointId = m_jointIds[i];
if (jointId != Joint::kInvalidId)
{
result = {jointId, i};
return result;
}
}
}
return result;
}
template <class Sink>
void Serialize(Sink & sink) const
{
WriteToSink(sink, static_cast<Joint::Id>(m_jointIds.size()));
for (Joint::Id jointId : m_jointIds)
WriteToSink(sink, jointId);
}
template <class Source>
void Deserialize(Source & src)
{
m_jointIds.clear();
Joint::Id const jointsSize = ReadPrimitiveFromSource<Joint::Id>(src);
m_jointIds.reserve(jointsSize);
for (Joint::Id i = 0; i < jointsSize; ++i)
{
Joint::Id const jointId = ReadPrimitiveFromSource<Joint::Id>(src);
m_jointIds.emplace_back(jointId);
}
}
private:
// Joint ids indexed by point id.
// If some point id doesn't match any joint id, this vector contains Joint::kInvalidId.
vector<Joint::Id> m_jointIds;
};
class RoadIndex final
{
public:
void Import(vector<Joint> const & joints);
void AddJoint(RoadPoint const & rp, Joint::Id jointId)
{
m_roads[rp.GetFeatureId()].AddJoint(rp.GetPointId(), jointId);
}
// Find nearest point with normal joint id.
// If forward == true: neighbor with larger point id (right neighbor)
// If forward == false: neighbor with smaller point id (left neighbor)
pair<Joint::Id, uint32_t> FindNeighbor(RoadPoint const & rp, bool forward) const;
template <class Sink>
void Serialize(Sink & sink) const
{
WriteToSink(sink, static_cast<uint32_t>(m_roads.size()));
for (auto const & it : m_roads)
{
uint32_t const featureId = it.first;
WriteToSink(sink, featureId);
it.second.Serialize(sink);
}
}
template <class Source>
void Deserialize(Source & src)
{
m_roads.clear();
size_t const roadsSize = static_cast<size_t>(ReadPrimitiveFromSource<uint32_t>(src));
for (size_t i = 0; i < roadsSize; ++i)
{
uint32_t featureId = ReadPrimitiveFromSource<decltype(featureId)>(src);
m_roads[featureId].Deserialize(src);
}
}
uint32_t GetSize() const { return m_roads.size(); }
Joint::Id GetJointId(RoadPoint const & rp) const
{
auto const it = m_roads.find(rp.GetFeatureId());
if (it == m_roads.end())
return Joint::kInvalidId;
return it->second.GetJointId(rp.GetPointId());
}
template <typename F>
void ForEachRoad(F && f) const
{
for (auto const & it : m_roads)
f(it.first, it.second);
}
private:
// Map from feature id to RoadJointIds.
unordered_map<uint32_t, RoadJointIds> m_roads;
};
} // namespace routing

41
routing/road_point.hpp Normal file
View file

@ -0,0 +1,41 @@
#pragma once
#include "std/cstdint.hpp"
#include "std/sstream.hpp"
#include "std/string.hpp"
namespace routing
{
// RoadPoint in unique identifier for any road point in mwm file.
//
// Contains feature id and point id.
// Point id is the ordinal number of point in the road.
class RoadPoint final
{
public:
RoadPoint() : m_featureId(0), m_pointId(0) {}
RoadPoint(uint32_t featureId, uint32_t pointId) : m_featureId(featureId), m_pointId(pointId) {}
uint32_t GetFeatureId() const { return m_featureId; }
uint32_t GetPointId() const { return m_pointId; }
bool operator==(RoadPoint const & rp) const
{
return m_featureId == rp.m_featureId && m_pointId == rp.m_pointId;
}
private:
uint32_t m_featureId;
uint32_t m_pointId;
};
inline string DebugPrint(RoadPoint const & rp)
{
ostringstream out;
out << "rp("
<< "(" << rp.GetFeatureId() << ", " << rp.GetPointId() << ")";
return out.str();
}
} // namespace routing

View file

@ -23,7 +23,13 @@ SOURCES += \
cross_mwm_router.cpp \
cross_routing_context.cpp \
directions_engine.cpp \
edge_estimator.cpp \
features_road_graph.cpp \
geometry.cpp \
index_graph.cpp \
index_graph_starter.cpp \
joint.cpp \
joint_index.cpp \
nearest_edge_finder.cpp \
online_absent_fetcher.cpp \
online_cross_fetcher.cpp \
@ -36,13 +42,16 @@ SOURCES += \
restriction_loader.cpp \
road_graph.cpp \
road_graph_router.cpp \
road_index.cpp \
route.cpp \
router.cpp \
router_delegate.cpp \
routing_algorithm.cpp \
routing_helpers.cpp \
routing_mapping.cpp \
routing_serialization.cpp \
routing_session.cpp \
single_mwm_router.cpp \
speed_camera.cpp \
turns.cpp \
turns_generator.cpp \
@ -64,7 +73,13 @@ HEADERS += \
cross_mwm_router.hpp \
cross_routing_context.hpp \
directions_engine.hpp \
edge_estimator.hpp \
features_road_graph.hpp \
geometry.hpp \
index_graph.hpp \
index_graph_starter.hpp \
joint.hpp \
joint_index.hpp \
loaded_path_segment.hpp \
nearest_edge_finder.hpp \
online_absent_fetcher.hpp \
@ -79,16 +94,20 @@ HEADERS += \
restriction_loader.hpp \
road_graph.hpp \
road_graph_router.hpp \
road_index.hpp \
road_point.hpp \
route.hpp \
router.hpp \
router_delegate.hpp \
routing_algorithm.hpp \
routing_exception.hpp \
routing_helpers.hpp \
routing_mapping.hpp \
routing_result_graph.hpp \
routing_serialization.hpp \
routing_session.hpp \
routing_settings.hpp \
single_mwm_router.hpp \
speed_camera.hpp \
turn_candidate.hpp \
turns.hpp \

View file

@ -151,8 +151,9 @@ IRoutingAlgorithm::Result AStarRoutingAlgorithm::CalculateRoute(IRoadGraph const
my::Cancellable const & cancellable = delegate;
progress.Initialize(startPos.GetPoint(), finalPos.GetPoint());
RoadGraph roadGraph(graph);
TAlgorithmImpl::Result const res = TAlgorithmImpl().FindPath(
RoadGraph(graph), startPos, finalPos, path, cancellable, onVisitJunctionFn);
roadGraph, startPos, finalPos, path, cancellable, onVisitJunctionFn);
return Convert(res);
}
@ -177,8 +178,9 @@ IRoutingAlgorithm::Result AStarBidirectionalRoutingAlgorithm::CalculateRoute(
my::Cancellable const & cancellable = delegate;
progress.Initialize(startPos.GetPoint(), finalPos.GetPoint());
RoadGraph roadGraph(graph);
TAlgorithmImpl::Result const res = TAlgorithmImpl().FindPathBidirectional(
RoadGraph(graph), startPos, finalPos, path, cancellable, onVisitJunctionFn);
roadGraph, startPos, finalPos, path, cancellable, onVisitJunctionFn);
return Convert(res);
}

View file

@ -0,0 +1,8 @@
#pragma once
#include "base/exception.hpp"
namespace routing
{
DECLARE_EXCEPTION(RoutingException, RootException);
} // namespace routing

View file

@ -0,0 +1,39 @@
#include "routing/routing_helpers.hpp"
namespace routing
{
void ReconstructRoute(IDirectionsEngine * engine, IRoadGraph const & graph,
my::Cancellable const & cancellable, vector<Junction> & path, Route & route)
{
if (path.empty())
{
LOG(LERROR, ("Can't reconstruct route from an empty list of positions."));
return;
}
// By some reason there're two adjacent positions on a road with
// the same end-points. This could happen, for example, when
// direction on a road was changed. But it doesn't matter since
// this code reconstructs only geometry of a route.
path.erase(unique(path.begin(), path.end()), path.end());
Route::TTimes times;
Route::TTurns turnsDir;
vector<Junction> junctions;
// @TODO(bykoianko) streetNames is not filled in Generate(). It should be done.
Route::TStreets streetNames;
if (engine)
engine->Generate(graph, path, times, turnsDir, junctions, cancellable);
vector<m2::PointD> routeGeometry;
JunctionsToPoints(junctions, routeGeometry);
feature::TAltitudes altitudes;
JunctionsToAltitudes(junctions, altitudes);
route.SetGeometry(routeGeometry.begin(), routeGeometry.end());
route.SetSectionTimes(move(times));
route.SetTurnInstructions(move(turnsDir));
route.SetStreetNames(move(streetNames));
route.SetAltitudes(move(altitudes));
}
} // namespace rouing

View file

@ -2,7 +2,14 @@
#include "routing/bicycle_model.hpp"
#include "routing/car_model.hpp"
#include "routing/directions_engine.hpp"
#include "routing/pedestrian_model.hpp"
#include "routing/road_graph.hpp"
#include "routing/route.hpp"
#include "base/cancellable.hpp"
#include "std/vector.hpp"
namespace routing
{
@ -14,4 +21,7 @@ bool IsRoad(TTypes const & types)
PedestrianModel::AllLimitsInstance().HasRoadType(types) ||
BicycleModel::AllLimitsInstance().HasRoadType(types);
}
void ReconstructRoute(IDirectionsEngine * engine, IRoadGraph const & graph,
my::Cancellable const & cancellable, vector<Junction> & path, Route & route);
} // namespace rouing

View file

@ -12,6 +12,7 @@
#include "routing/road_graph_router.hpp"
#include "routing/route.hpp"
#include "routing/router_delegate.hpp"
#include "routing/single_mwm_router.hpp"
#include "indexer/index.hpp"
@ -82,7 +83,7 @@ namespace integration
};
auto carRouter = make_unique<CarRouter>(
index, countryFileGetter, CreateCarAStarBidirectionalRouter(index, countryFileGetter));
index, countryFileGetter, SingleMwmRouter::CreateCarRouter(index));
return carRouter;
}

View file

@ -57,7 +57,7 @@ private:
map<unsigned, vector<Edge>> m_adjs;
};
void TestAStar(UndirectedGraph const & graph, vector<unsigned> const & expectedRoute, double const & expectedDistance)
void TestAStar(UndirectedGraph & graph, vector<unsigned> const & expectedRoute, double const & expectedDistance)
{
using TAlgorithm = AStarAlgorithm<UndirectedGraph>;

View file

@ -0,0 +1,338 @@
#include "testing/testing.hpp"
#include "routing/base/astar_algorithm.hpp"
#include "routing/car_model.hpp"
#include "routing/edge_estimator.hpp"
#include "routing/index_graph.hpp"
#include "routing/index_graph_starter.hpp"
#include "geometry/point2d.hpp"
#include "base/assert.hpp"
#include "std/algorithm.hpp"
#include "std/unique_ptr.hpp"
#include "std/unordered_map.hpp"
#include "std/vector.hpp"
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());
}
void TestRoute(IndexGraph & graph, RoadPoint const & start, RoadPoint const & finish,
size_t expectedLength, vector<RoadPoint> const * expectedRoute = nullptr)
{
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, {}, {});
TEST_EQUAL(resultCode, AStarAlgorithm<IndexGraphStarter>::Result::OK, ());
vector<RoadPoint> roadPoints;
starter.RedressRoute(routingResult.path, roadPoints);
TEST_EQUAL(roadPoints.size(), expectedLength, ());
if (expectedRoute)
TEST_EQUAL(roadPoints, *expectedRoute, ());
}
void TestEdges(IndexGraph & graph, Joint::Id jointId, vector<Joint::Id> const & expectedTargets,
bool forward)
{
vector<JointEdge> edges;
graph.GetEdgeList(jointId, forward, edges);
vector<Joint::Id> targets;
for (JointEdge const & edge : edges)
targets.push_back(edge.GetTarget());
sort(targets.begin(), targets.end());
TEST_EQUAL(targets, expectedTargets, ());
}
void TestOutgoingEdges(IndexGraph & graph, Joint::Id jointId,
vector<Joint::Id> const & expectedTargets)
{
TestEdges(graph, jointId, expectedTargets, true);
}
void TestIngoingEdges(IndexGraph & graph, Joint::Id jointId,
vector<Joint::Id> const & expectedTargets)
{
TestEdges(graph, jointId, expectedTargets, false);
}
uint32_t AbsDelta(uint32_t v0, uint32_t v1) { return v0 > v1 ? v0 - v1 : v1 - v0; }
} // namespace
namespace routing_test
{
// R4 (one way down)
//
// R1 J2--------J3 -1
// ^ v
// ^ v
// R0 *---J0----*---J1----* 0
// ^ v
// ^ v
// R2 J4--------J5 1
//
// R3 (one way up) y
//
// x: 0 1 2 3 4
//
UNIT_TEST(EdgesTest)
{
unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
loader->AddRoad(
0 /* featureId */, false, 1.0 /* speed */,
RoadGeometry::Points({{0.0, 0.0}, {1.0, 0.0}, {2.0, 0.0}, {3.0, 0.0}, {4.0, 0.0}}));
loader->AddRoad(1 /* featureId */, false, 1.0 /* speed */,
RoadGeometry::Points({{1.0, -1.0}, {3.0, -1.0}}));
loader->AddRoad(2 /* featureId */, false, 1.0 /* speed */,
RoadGeometry::Points({{1.0, -1.0}, {3.0, -1.0}}));
loader->AddRoad(3 /* featureId */, true, 1.0 /* speed */,
RoadGeometry::Points({{1.0, 1.0}, {1.0, 0.0}, {1.0, -1.0}}));
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());
vector<Joint> joints;
joints.emplace_back(MakeJoint({{0, 1}, {3, 1}})); // J0
joints.emplace_back(MakeJoint({{0, 3}, {4, 1}})); // J1
joints.emplace_back(MakeJoint({{1, 0}, {3, 2}})); // J2
joints.emplace_back(MakeJoint({{1, 1}, {4, 0}})); // J3
joints.emplace_back(MakeJoint({{2, 0}, {3, 0}})); // J4
joints.emplace_back(MakeJoint({{2, 1}, {4, 2}})); // J5
graph.Import(joints);
TestOutgoingEdges(graph, 0, {1, 2});
TestOutgoingEdges(graph, 1, {0, 5});
TestOutgoingEdges(graph, 2, {3});
TestOutgoingEdges(graph, 3, {1, 2});
TestOutgoingEdges(graph, 4, {0, 5});
TestOutgoingEdges(graph, 5, {4});
TestIngoingEdges(graph, 0, {1, 4});
TestIngoingEdges(graph, 1, {0, 3});
TestIngoingEdges(graph, 2, {0, 3});
TestIngoingEdges(graph, 3, {2});
TestIngoingEdges(graph, 4, {5});
TestIngoingEdges(graph, 5, {1, 4});
}
// Roads R1:
//
// -2
// -1
// R0 -2 -1 0 1 2
// 1
// 2
//
UNIT_TEST(FindPathCross)
{
unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
loader->AddRoad(
0 /* featureId */, false, 1.0 /* speed */,
RoadGeometry::Points({{-2.0, 0.0}, {-1.0, 0.0}, {0.0, 0.0}, {1.0, 0.0}, {2.0, 0.0}}));
loader->AddRoad(
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());
graph.Import({MakeJoint({{0, 2}, {1, 2}})});
vector<RoadPoint> points;
for (uint32_t i = 0; i < 5; ++i)
{
points.emplace_back(0, i);
points.emplace_back(1, i);
}
for (auto const & start : points)
{
for (auto const & finish : points)
{
uint32_t expectedLength;
// Length of the route is the number of route points.
// Example: p0 --- p1 --- p2
// 2 segments, 3 points,
// Therefore route length = geometrical length + 1
if (start.GetFeatureId() == finish.GetFeatureId())
expectedLength = AbsDelta(start.GetPointId(), finish.GetPointId()) + 1;
else
expectedLength = AbsDelta(start.GetPointId(), 2) + AbsDelta(finish.GetPointId(), 2) + 1;
TestRoute(graph, start, finish, expectedLength);
}
}
}
// Roads R4 R5 R6 R7
//
// R0 0 - * - * - *
// | | | |
// R1 * - 1 - * - *
// | | | |
// R2 * - * - 2 - *
// | | | |
// R3 * - * - * - 3
//
UNIT_TEST(FindPathManhattan)
{
uint32_t constexpr kCitySize = 4;
unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
for (uint32_t i = 0; i < kCitySize; ++i)
{
RoadGeometry::Points street;
RoadGeometry::Points avenue;
for (uint32_t j = 0; j < kCitySize; ++j)
{
street.emplace_back(static_cast<double>(i), static_cast<double>(j));
avenue.emplace_back(static_cast<double>(j), static_cast<double>(i));
}
loader->AddRoad(i, false, 1.0 /* speed */, street);
loader->AddRoad(i + kCitySize, false, 1.0 /* speed */, avenue);
}
IndexGraph graph(move(loader), CreateEstimator());
vector<Joint> joints;
for (uint32_t i = 0; i < kCitySize; ++i)
{
for (uint32_t j = 0; j < kCitySize; ++j)
joints.emplace_back(MakeJoint({{i, j}, {j + kCitySize, i}}));
}
graph.Import(joints);
for (uint32_t startY = 0; startY < kCitySize; ++startY)
{
for (uint32_t startX = 0; startX < kCitySize; ++startX)
{
for (uint32_t finishY = 0; finishY < kCitySize; ++finishY)
{
for (uint32_t finishX = 0; finishX < kCitySize; ++finishX)
TestRoute(graph, {startX, startY}, {finishX, finishY},
AbsDelta(startX, finishX) + AbsDelta(startY, finishY) + 1);
}
}
}
}
// Roads y:
//
// R0: * - * - * -1
// / \
// R1: J0 * -* - * - *- * J1 0
// \ /
// R2: * - * - * 1
//
// x: 0 1 2 3 4
//
UNIT_TEST(RedressRace)
{
unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
loader->AddRoad(
0 /* 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}}));
loader->AddRoad(
1 /* featureId */, false, 1.0 /* speed */,
RoadGeometry::Points({{0.0, 0.0}, {1.0, 0.0}, {2.0, 0.0}, {3.0, 0.0}, {4.0, 0.0}}));
loader->AddRoad(
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());
vector<Joint> joints;
joints.emplace_back(MakeJoint({{0, 0}, {1, 0}, {2, 0}})); // J0
joints.emplace_back(MakeJoint({{0, 4}, {1, 4}, {2, 4}})); // J1
graph.Import(joints);
vector<RoadPoint> const expectedRoute({{1, 0}, {1, 1}, {1, 2}, {1, 3}, {1, 4}});
TestRoute(graph, {0, 0}, {0, 4}, 5, &expectedRoute);
}
// Roads y:
//
// fast road R0 * - * - * -1
// / \
// slow road R1 J0 * - - * - - * J1 0
//
// x: 0 1 2 3 4
//
UNIT_TEST(RoadSpeed)
{
unique_ptr<TestGeometryLoader> loader = make_unique<TestGeometryLoader>();
loader->AddRoad(
0 /* featureId */, false, 10.0 /* speed */,
RoadGeometry::Points({{0.0, 0.0}, {1.0, -1.0}, {2.0, -1.0}, {3.0, -1.0}, {4.0, 0.0}}));
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());
vector<Joint> joints;
joints.emplace_back(MakeJoint({{0, 0}, {1, 0}})); // J0
joints.emplace_back(MakeJoint({{0, 4}, {1, 2}})); // J1
graph.Import(joints);
vector<RoadPoint> const expectedRoute({{0, 0}, {0, 1}, {0, 2}, {0, 3}, {0, 4}});
TestRoute(graph, {0, 0}, {0, 4}, 5, &expectedRoute);
}
} // namespace routing_test

View file

@ -27,6 +27,7 @@ SOURCES += \
async_router_test.cpp \
cross_routing_tests.cpp \
followed_polyline_test.cpp \
index_graph_test.cpp \
nearest_edge_finder_tests.cpp \
online_cross_fetcher_test.cpp \
osrm_router_test.cpp \

View file

@ -0,0 +1,225 @@
#include "routing/single_mwm_router.hpp"
#include "routing/base/astar_algorithm.hpp"
#include "routing/base/astar_progress.hpp"
#include "routing/bicycle_directions.hpp"
#include "routing/bicycle_model.hpp"
#include "routing/car_model.hpp"
#include "routing/index_graph.hpp"
#include "routing/index_graph_starter.hpp"
#include "routing/pedestrian_model.hpp"
#include "routing/route.hpp"
#include "routing/routing_helpers.hpp"
#include "routing/turns_generator.hpp"
#include "indexer/feature_altitude.hpp"
#include "indexer/routing_section.hpp"
#include "geometry/distance.hpp"
#include "geometry/mercator.hpp"
#include "geometry/point2d.hpp"
#include "base/exception.hpp"
using namespace routing;
namespace
{
size_t constexpr kMaxRoadCandidates = 6;
float constexpr kProgressInterval = 2;
uint32_t constexpr kDrawPointsPeriod = 10;
vector<Junction> ConvertToJunctions(IndexGraphStarter & starter, vector<Joint::Id> const & joints)
{
vector<RoadPoint> roadPoints;
starter.RedressRoute(joints, roadPoints);
vector<Junction> junctions;
junctions.reserve(roadPoints.size());
Geometry & geometry = starter.GetGraph().GetGeometry();
// TODO: Use real altitudes for pedestrian and bicycle routing.
for (RoadPoint const & point : roadPoints)
junctions.emplace_back(geometry.GetPoint(point), feature::kDefaultAltitudeMeters);
return junctions;
}
} // namespace
namespace routing
{
SingleMwmRouter::SingleMwmRouter(string const & name, Index const & index,
shared_ptr<VehicleModelFactory> vehicleModelFactory,
shared_ptr<EdgeEstimator> estimator,
unique_ptr<IDirectionsEngine> directionsEngine)
: m_name(name)
, m_index(index)
, m_roadGraph(index, IRoadGraph::Mode::ObeyOnewayTag, vehicleModelFactory)
, m_vehicleModelFactory(vehicleModelFactory)
, m_estimator(estimator)
, m_directionsEngine(move(directionsEngine))
{
ASSERT(!m_name.empty(), ());
ASSERT(m_vehicleModelFactory, ());
ASSERT(m_estimator, ());
ASSERT(m_directionsEngine, ());
}
IRouter::ResultCode SingleMwmRouter::CalculateRoute(MwmSet::MwmId const & mwmId,
m2::PointD const & startPoint,
m2::PointD const & startDirection,
m2::PointD const & finalPoint,
RouterDelegate const & delegate, Route & route)
{
try
{
return DoCalculateRoute(mwmId, startPoint, startDirection, finalPoint, delegate, route);
}
catch (RootException const & e)
{
LOG(LERROR, ("Can't find path from", MercatorBounds::ToLatLon(startPoint), "to",
MercatorBounds::ToLatLon(finalPoint), ":\n ", e.what()));
return IRouter::InternalError;
}
}
IRouter::ResultCode SingleMwmRouter::DoCalculateRoute(MwmSet::MwmId const & mwmId,
m2::PointD const & startPoint,
m2::PointD const & /* startDirection */,
m2::PointD const & finalPoint,
RouterDelegate const & delegate,
Route & route)
{
if (!mwmId.IsAlive())
return IRouter::RouteFileNotExist;
string const & country = mwmId.GetInfo()->GetCountryName();
Edge startEdge;
if (!FindClosestEdge(mwmId, startPoint, startEdge))
return IRouter::StartPointNotFound;
Edge finishEdge;
if (!FindClosestEdge(mwmId, finalPoint, finishEdge))
return IRouter::EndPointNotFound;
RoadPoint const start(startEdge.GetFeatureId().m_index, startEdge.GetSegId());
RoadPoint const finish(finishEdge.GetFeatureId().m_index, finishEdge.GetSegId());
IndexGraph graph(GeometryLoader::Create(
m_index, mwmId, m_vehicleModelFactory->GetVehicleModelForCountry(country)),
m_estimator);
if (!LoadIndex(mwmId, country, graph))
return IRouter::RouteFileNotExist;
IndexGraphStarter starter(graph, start, finish);
AStarProgress progress(0, 100);
progress.Initialize(graph.GetGeometry().GetPoint(start), graph.GetGeometry().GetPoint(finish));
uint32_t drawPointsStep = 0;
auto onVisitJunction = [&](Joint::Id const & from, Joint::Id const & to) {
m2::PointD const & pointFrom = starter.GetPoint(from);
m2::PointD const & pointTo = starter.GetPoint(to);
auto const lastValue = progress.GetLastValue();
auto const newValue = progress.GetProgressForBidirectedAlgo(pointFrom, pointTo);
if (newValue - lastValue > kProgressInterval)
delegate.OnProgress(newValue);
if (drawPointsStep % kDrawPointsPeriod == 0)
delegate.OnPointCheck(pointFrom);
++drawPointsStep;
};
AStarAlgorithm<IndexGraphStarter> algorithm;
RoutingResult<Joint::Id> routingResult;
auto const resultCode =
algorithm.FindPathBidirectional(starter, starter.GetStartJoint(), starter.GetFinishJoint(),
routingResult, delegate, onVisitJunction);
switch (resultCode)
{
case AStarAlgorithm<IndexGraphStarter>::Result::NoPath: return IRouter::RouteNotFound;
case AStarAlgorithm<IndexGraphStarter>::Result::Cancelled: return IRouter::Cancelled;
case AStarAlgorithm<IndexGraphStarter>::Result::OK:
vector<Junction> path = ConvertToJunctions(starter, routingResult.path);
ReconstructRoute(m_directionsEngine.get(), m_roadGraph, delegate, path, route);
return IRouter::NoError;
}
}
bool SingleMwmRouter::FindClosestEdge(MwmSet::MwmId const & mwmId, m2::PointD const & point,
Edge & closestEdge) const
{
vector<pair<Edge, Junction>> candidates;
m_roadGraph.FindClosestEdges(point, kMaxRoadCandidates, candidates);
double minDistance = numeric_limits<double>::max();
size_t minIndex = candidates.size();
for (size_t i = 0; i < candidates.size(); ++i)
{
Edge const & edge = candidates[i].first;
if (edge.GetFeatureId().m_mwmId != mwmId)
continue;
m2::DistanceToLineSquare<m2::PointD> squaredDistance;
squaredDistance.SetBounds(edge.GetStartJunction().GetPoint(), edge.GetEndJunction().GetPoint());
double const distance = squaredDistance(point);
if (distance < minDistance)
{
minDistance = distance;
minIndex = i;
}
}
if (minIndex == candidates.size())
return false;
closestEdge = candidates[minIndex].first;
return true;
}
bool SingleMwmRouter::LoadIndex(MwmSet::MwmId const & mwmId, string const & country,
IndexGraph & graph)
{
MwmSet::MwmHandle mwmHandle = m_index.GetMwmHandleById(mwmId);
if (!mwmHandle.IsAlive())
return false;
MwmValue const * mwmValue = mwmHandle.GetValue<MwmValue>();
try
{
my::Timer timer;
FilesContainerR::TReader reader(mwmValue->m_cont.GetReader(ROUTING_FILE_TAG));
ReaderSource<FilesContainerR::TReader> src(reader);
feature::RoutingSectionHeader header;
header.Deserialize(src);
graph.Deserialize(src);
LOG(LINFO,
(ROUTING_FILE_TAG, "section for", country, "loaded in", timer.ElapsedSeconds(), "seconds"));
return true;
}
catch (Reader::OpenException const & e)
{
LOG(LERROR, ("File", mwmValue->GetCountryFileName(), "Error while reading", ROUTING_FILE_TAG,
"section:", e.Msg()));
return false;
}
}
// static
unique_ptr<SingleMwmRouter> SingleMwmRouter::CreateCarRouter(Index const & index)
{
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 router =
make_unique<SingleMwmRouter>("astar-bidirectional-car", index, move(vehicleModelFactory),
estimator, move(directionsEngine));
return router;
}
} // namespace routing

View file

@ -0,0 +1,52 @@
#pragma once
#include "routing/directions_engine.hpp"
#include "routing/edge_estimator.hpp"
#include "routing/features_road_graph.hpp"
#include "routing/router.hpp"
#include "routing/vehicle_model.hpp"
#include "indexer/index.hpp"
#include "std/shared_ptr.hpp"
#include "std/unique_ptr.hpp"
#include "std/vector.hpp"
namespace routing
{
class IndexGraph;
class SingleMwmRouter
{
public:
SingleMwmRouter(string const & name, Index const & index,
shared_ptr<VehicleModelFactory> vehicleModelFactory,
shared_ptr<EdgeEstimator> estimator,
unique_ptr<IDirectionsEngine> directionsEngine);
string const & GetName() const { return m_name; }
IRouter::ResultCode CalculateRoute(MwmSet::MwmId const & mwmId, m2::PointD const & startPoint,
m2::PointD const & startDirection,
m2::PointD const & finalPoint, RouterDelegate const & delegate,
Route & route);
static unique_ptr<SingleMwmRouter> CreateCarRouter(Index const & index);
private:
IRouter::ResultCode DoCalculateRoute(MwmSet::MwmId const & mwmId, m2::PointD const & startPoint,
m2::PointD const & startDirection,
m2::PointD const & finalPoint,
RouterDelegate const & delegate, Route & route);
bool FindClosestEdge(MwmSet::MwmId const & mwmId, m2::PointD const & point,
Edge & closestEdge) const;
bool LoadIndex(MwmSet::MwmId const & mwmId, string const & country, IndexGraph & graph);
string const m_name;
Index const & m_index;
FeaturesRoadGraph m_roadGraph;
shared_ptr<VehicleModelFactory> m_vehicleModelFactory;
shared_ptr<EdgeEstimator> m_estimator;
unique_ptr<IDirectionsEngine> m_directionsEngine;
};
} // namespace routing

View file

@ -7,6 +7,8 @@
objects = {
/* Begin PBXBuildFile section */
0C5FEC701DDE19E50017688C /* routing_index_generator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC6E1DDE19E50017688C /* routing_index_generator.cpp */; };
0C5FEC711DDE19E50017688C /* routing_index_generator.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC6F1DDE19E50017688C /* routing_index_generator.hpp */; };
34F558791DBF4C7800A4FC11 /* booking_quality_check.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34F558771DBF4C7800A4FC11 /* booking_quality_check.cpp */; };
34F5587B1DBF4C8300A4FC11 /* feature_segments_checker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34F5587A1DBF4C8300A4FC11 /* feature_segments_checker.cpp */; };
34F558871DBF4C9600A4FC11 /* opentable_dataset.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34F5587E1DBF4C9600A4FC11 /* opentable_dataset.cpp */; };
@ -86,6 +88,8 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0C5FEC6E1DDE19E50017688C /* routing_index_generator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = routing_index_generator.cpp; sourceTree = "<group>"; };
0C5FEC6F1DDE19E50017688C /* routing_index_generator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_index_generator.hpp; sourceTree = "<group>"; };
34AF87CF1DBE52DC00E5E7DC /* common-debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-debug.xcconfig"; path = "../common-debug.xcconfig"; sourceTree = "<group>"; };
34AF87D01DBE52DC00E5E7DC /* common-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-release.xcconfig"; path = "../common-release.xcconfig"; sourceTree = "<group>"; };
34F558771DBF4C7800A4FC11 /* booking_quality_check.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = booking_quality_check.cpp; path = booking_quality_check/booking_quality_check.cpp; sourceTree = "<group>"; };
@ -269,6 +273,8 @@
6753404D1A3F2A7400A0A8C3 /* polygonizer.hpp */,
6753404E1A3F2A7400A0A8C3 /* routing_generator.cpp */,
6753404F1A3F2A7400A0A8C3 /* routing_generator.hpp */,
0C5FEC6E1DDE19E50017688C /* routing_index_generator.cpp */,
0C5FEC6F1DDE19E50017688C /* routing_index_generator.hpp */,
675340501A3F2A7400A0A8C3 /* statistics.cpp */,
675340511A3F2A7400A0A8C3 /* statistics.hpp */,
675340521A3F2A7400A0A8C3 /* tesselator.cpp */,
@ -331,6 +337,7 @@
34F5588B1DBF4C9600A4FC11 /* sponsored_dataset.hpp in Headers */,
6753405F1A3F2A7400A0A8C3 /* borders_loader.hpp in Headers */,
675340801A3F2A7400A0A8C3 /* polygonizer.hpp in Headers */,
0C5FEC711DDE19E50017688C /* routing_index_generator.hpp in Headers */,
675340941C5231BA002CF0D9 /* search_index_builder.hpp in Headers */,
3D51BC591D5E512500F1FA8D /* srtm_parser.hpp in Headers */,
677E2A181CAACC5F001DC42A /* towns_dumper.hpp in Headers */,
@ -438,6 +445,7 @@
buildActionMask = 2147483647;
files = (
6753406C1A3F2A7400A0A8C3 /* feature_generator.cpp in Sources */,
0C5FEC701DDE19E50017688C /* routing_index_generator.cpp in Sources */,
3D51BC561D5E512500F1FA8D /* region_meta.cpp in Sources */,
3D51BC521D5E512500F1FA8D /* altitude_generator.cpp in Sources */,
3D51BC581D5E512500F1FA8D /* srtm_parser.cpp in Sources */,

View file

@ -7,6 +7,7 @@
objects = {
/* Begin PBXBuildFile section */
0C5FEC731DDE1A140017688C /* routing_section.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC721DDE1A140017688C /* routing_section.hpp */; };
340DF9D01C1FF04D00B5C7EC /* osm_editor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 340DF9CF1C1FF04D00B5C7EC /* osm_editor.cpp */; };
34583BC71C88552100F94664 /* cuisines.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 34583BC11C88552100F94664 /* cuisines.cpp */; };
34583BC81C88552100F94664 /* cuisines.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 34583BC21C88552100F94664 /* cuisines.hpp */; };
@ -223,6 +224,7 @@
/* End PBXCopyFilesBuildPhase section */
/* Begin PBXFileReference section */
0C5FEC721DDE1A140017688C /* routing_section.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_section.hpp; sourceTree = "<group>"; };
340DF9CF1C1FF04D00B5C7EC /* osm_editor.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = osm_editor.cpp; sourceTree = "<group>"; };
34583BC11C88552100F94664 /* cuisines.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = cuisines.cpp; sourceTree = "<group>"; };
34583BC21C88552100F94664 /* cuisines.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = cuisines.hpp; sourceTree = "<group>"; };
@ -651,6 +653,7 @@
56C74C151C749E4700B71B9F /* displacement_manager.hpp */,
56C74C161C749E4700B71B9F /* edits_migration.cpp */,
56C74C171C749E4700B71B9F /* edits_migration.hpp */,
0C5FEC721DDE1A140017688C /* routing_section.hpp */,
56C74C181C749E4700B71B9F /* search_delimiters.cpp */,
56C74C191C749E4700B71B9F /* search_delimiters.hpp */,
56C74C1A1C749E4700B71B9F /* search_string_utils.cpp */,
@ -822,6 +825,7 @@
675341411A3F540F00A0A8C3 /* scales.hpp in Headers */,
675341321A3F540F00A0A8C3 /* interval_index_builder.hpp in Headers */,
347F337C1C454242009758CC /* rank_table.hpp in Headers */,
0C5FEC731DDE1A140017688C /* routing_section.hpp in Headers */,
6753414B1A3F540F00A0A8C3 /* tesselator_decl.hpp in Headers */,
347F33801C454242009758CC /* trie_reader.hpp in Headers */,
675341191A3F540F00A0A8C3 /* feature_decl.hpp in Headers */,

View file

@ -7,6 +7,26 @@
objects = {
/* Begin PBXBuildFile section */
0C0DF9211DE898B70055A22F /* index_graph_starter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C0DF91F1DE898B70055A22F /* index_graph_starter.cpp */; };
0C0DF9221DE898B70055A22F /* index_graph_starter.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C0DF9201DE898B70055A22F /* index_graph_starter.hpp */; };
0C0DF9251DE898CF0055A22F /* single_mwm_router.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C0DF9231DE898CF0055A22F /* single_mwm_router.cpp */; };
0C0DF9261DE898CF0055A22F /* single_mwm_router.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C0DF9241DE898CF0055A22F /* single_mwm_router.hpp */; };
0C0DF9291DE898FF0055A22F /* routing_exception.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C0DF9271DE898FF0055A22F /* routing_exception.hpp */; };
0C0DF92A1DE898FF0055A22F /* routing_helpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C0DF9281DE898FF0055A22F /* routing_helpers.cpp */; };
0C5FEC541DDE191E0017688C /* edge_estimator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC521DDE191E0017688C /* edge_estimator.cpp */; };
0C5FEC551DDE191E0017688C /* edge_estimator.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC531DDE191E0017688C /* edge_estimator.hpp */; };
0C5FEC5E1DDE192A0017688C /* geometry.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC561DDE192A0017688C /* geometry.cpp */; };
0C5FEC5F1DDE192A0017688C /* geometry.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC571DDE192A0017688C /* geometry.hpp */; };
0C5FEC601DDE192A0017688C /* index_graph.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC581DDE192A0017688C /* index_graph.cpp */; };
0C5FEC611DDE192A0017688C /* index_graph.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC591DDE192A0017688C /* index_graph.hpp */; };
0C5FEC621DDE192A0017688C /* joint_index.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC5A1DDE192A0017688C /* joint_index.cpp */; };
0C5FEC631DDE192A0017688C /* joint_index.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC5B1DDE192A0017688C /* joint_index.hpp */; };
0C5FEC641DDE192A0017688C /* joint.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC5C1DDE192A0017688C /* joint.cpp */; };
0C5FEC651DDE192A0017688C /* joint.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC5D1DDE192A0017688C /* joint.hpp */; };
0C5FEC691DDE193F0017688C /* road_index.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC661DDE193F0017688C /* road_index.cpp */; };
0C5FEC6A1DDE193F0017688C /* road_index.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC671DDE193F0017688C /* road_index.hpp */; };
0C5FEC6B1DDE193F0017688C /* road_point.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 0C5FEC681DDE193F0017688C /* road_point.hpp */; };
0C5FEC6D1DDE19A40017688C /* index_graph_test.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0C5FEC6C1DDE19A40017688C /* index_graph_test.cpp */; };
3462FDAD1DC1E5BF00906FD7 /* libopening_hours.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 3462FDAC1DC1E5BF00906FD7 /* libopening_hours.a */; };
56099E291CC7C97D00A7772A /* loaded_path_segment.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56099E251CC7C97D00A7772A /* loaded_path_segment.hpp */; };
56099E2A1CC7C97D00A7772A /* routing_result_graph.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 56099E261CC7C97D00A7772A /* routing_result_graph.hpp */; };
@ -219,6 +239,26 @@
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
0C0DF91F1DE898B70055A22F /* index_graph_starter.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = index_graph_starter.cpp; sourceTree = "<group>"; };
0C0DF9201DE898B70055A22F /* index_graph_starter.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = index_graph_starter.hpp; sourceTree = "<group>"; };
0C0DF9231DE898CF0055A22F /* single_mwm_router.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = single_mwm_router.cpp; sourceTree = "<group>"; };
0C0DF9241DE898CF0055A22F /* single_mwm_router.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = single_mwm_router.hpp; sourceTree = "<group>"; };
0C0DF9271DE898FF0055A22F /* routing_exception.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = routing_exception.hpp; sourceTree = "<group>"; };
0C0DF9281DE898FF0055A22F /* routing_helpers.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = routing_helpers.cpp; sourceTree = "<group>"; };
0C5FEC521DDE191E0017688C /* edge_estimator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = edge_estimator.cpp; sourceTree = "<group>"; };
0C5FEC531DDE191E0017688C /* edge_estimator.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = edge_estimator.hpp; sourceTree = "<group>"; };
0C5FEC561DDE192A0017688C /* geometry.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = geometry.cpp; sourceTree = "<group>"; };
0C5FEC571DDE192A0017688C /* geometry.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = geometry.hpp; sourceTree = "<group>"; };
0C5FEC581DDE192A0017688C /* index_graph.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = index_graph.cpp; sourceTree = "<group>"; };
0C5FEC591DDE192A0017688C /* index_graph.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = index_graph.hpp; sourceTree = "<group>"; };
0C5FEC5A1DDE192A0017688C /* joint_index.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = joint_index.cpp; sourceTree = "<group>"; };
0C5FEC5B1DDE192A0017688C /* joint_index.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = joint_index.hpp; sourceTree = "<group>"; };
0C5FEC5C1DDE192A0017688C /* joint.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = joint.cpp; sourceTree = "<group>"; };
0C5FEC5D1DDE192A0017688C /* joint.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = joint.hpp; sourceTree = "<group>"; };
0C5FEC661DDE193F0017688C /* road_index.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = road_index.cpp; sourceTree = "<group>"; };
0C5FEC671DDE193F0017688C /* road_index.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = road_index.hpp; sourceTree = "<group>"; };
0C5FEC681DDE193F0017688C /* road_point.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = road_point.hpp; sourceTree = "<group>"; };
0C5FEC6C1DDE19A40017688C /* index_graph_test.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = index_graph_test.cpp; sourceTree = "<group>"; };
3462FDAC1DC1E5BF00906FD7 /* libopening_hours.a */ = {isa = PBXFileReference; lastKnownFileType = archive.ar; name = libopening_hours.a; path = "../../../omim-build/xcode/Debug/libopening_hours.a"; sourceTree = "<group>"; };
34F558351DBF2A2600A4FC11 /* common-debug.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-debug.xcconfig"; path = "../common-debug.xcconfig"; sourceTree = "<group>"; };
34F558361DBF2A2600A4FC11 /* common-release.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; name = "common-release.xcconfig"; path = "../common-release.xcconfig"; sourceTree = "<group>"; };
@ -506,6 +546,7 @@
6742ACA91C68A0B1009CB89E /* async_router_test.cpp */,
6742ACAA1C68A0B1009CB89E /* cross_routing_tests.cpp */,
6742ACAB1C68A0B1009CB89E /* followed_polyline_test.cpp */,
0C5FEC6C1DDE19A40017688C /* index_graph_test.cpp */,
6742ACAC1C68A0B1009CB89E /* nearest_edge_finder_tests.cpp */,
6742ACAD1C68A0B1009CB89E /* online_cross_fetcher_test.cpp */,
6742ACAE1C68A0B1009CB89E /* osrm_router_test.cpp */,
@ -622,8 +663,20 @@
675343FA1A3F640D00A0A8C3 /* routing */ = {
isa = PBXGroup;
children = (
0C5FEC521DDE191E0017688C /* edge_estimator.cpp */,
0C5FEC531DDE191E0017688C /* edge_estimator.hpp */,
56EA2FD41D8FD8590083F01A /* routing_helpers.hpp */,
56099E2C1CC8FBDA00A7772A /* osrm_path_segment_factory.cpp */,
0C5FEC561DDE192A0017688C /* geometry.cpp */,
0C5FEC571DDE192A0017688C /* geometry.hpp */,
0C5FEC581DDE192A0017688C /* index_graph.cpp */,
0C5FEC591DDE192A0017688C /* index_graph.hpp */,
0C5FEC5A1DDE192A0017688C /* joint_index.cpp */,
0C5FEC5B1DDE192A0017688C /* joint_index.hpp */,
0C0DF91F1DE898B70055A22F /* index_graph_starter.cpp */,
0C0DF9201DE898B70055A22F /* index_graph_starter.hpp */,
0C5FEC5C1DDE192A0017688C /* joint.cpp */,
0C5FEC5D1DDE192A0017688C /* joint.hpp */,
56099E2D1CC8FBDA00A7772A /* osrm_path_segment_factory.hpp */,
56826BCE1DB51C4E00807C62 /* car_router.cpp */,
56826BCF1DB51C4E00807C62 /* car_router.hpp */,
@ -637,6 +690,13 @@
563B91C41CC4F1DC00222BC1 /* bicycle_model.hpp */,
A17B42961BCFBD0E00A1EAE4 /* osrm_helpers.cpp */,
A17B42971BCFBD0E00A1EAE4 /* osrm_helpers.hpp */,
0C5FEC661DDE193F0017688C /* road_index.cpp */,
0C5FEC671DDE193F0017688C /* road_index.hpp */,
0C5FEC681DDE193F0017688C /* road_point.hpp */,
0C0DF9271DE898FF0055A22F /* routing_exception.hpp */,
0C0DF9281DE898FF0055A22F /* routing_helpers.cpp */,
0C0DF9231DE898CF0055A22F /* single_mwm_router.cpp */,
0C0DF9241DE898CF0055A22F /* single_mwm_router.hpp */,
6741AA9A1BF35331002C974C /* turns_notification_manager.cpp */,
6741AA9B1BF35331002C974C /* turns_notification_manager.hpp */,
A1876BC41BB19C4300C9C743 /* speed_camera.cpp */,
@ -724,10 +784,12 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
0C5FEC631DDE192A0017688C /* joint_index.hpp in Headers */,
67AB92E51B7B3E6E00AB5194 /* routing_mapping.hpp in Headers */,
674F9BCB1B0A580E00704FFA /* async_router.hpp in Headers */,
674F9BD11B0A580E00704FFA /* online_cross_fetcher.hpp in Headers */,
A120B3531B4A7C1C002F3808 /* astar_algorithm.hpp in Headers */,
0C5FEC5F1DDE192A0017688C /* geometry.hpp in Headers */,
674A28B21B1605D2001A525C /* osrm_engine.hpp in Headers */,
67AB92E71B7B3E6E00AB5194 /* turns_tts_text.hpp in Headers */,
56099E2A1CC7C97D00A7772A /* routing_result_graph.hpp in Headers */,
@ -735,12 +797,15 @@
674F9BD31B0A580E00704FFA /* road_graph_router.hpp in Headers */,
675344141A3F644F00A0A8C3 /* osrm_data_facade.hpp in Headers */,
6753441F1A3F644F00A0A8C3 /* turns.hpp in Headers */,
0C5FEC611DDE192A0017688C /* index_graph.hpp in Headers */,
6753441A1A3F644F00A0A8C3 /* osrm2feature_map.hpp in Headers */,
6741AA9D1BF35331002C974C /* turns_notification_manager.hpp in Headers */,
674F9BD71B0A580E00704FFA /* turns_generator.hpp in Headers */,
0C0DF9261DE898CF0055A22F /* single_mwm_router.hpp in Headers */,
A120B3461B4A7BE5002F3808 /* cross_mwm_road_graph.hpp in Headers */,
6753441C1A3F644F00A0A8C3 /* route.hpp in Headers */,
A1616E2C1B6B60AB003F078E /* router_delegate.hpp in Headers */,
0C0DF9291DE898FF0055A22F /* routing_exception.hpp in Headers */,
A17B42991BCFBD0E00A1EAE4 /* osrm_helpers.hpp in Headers */,
67C7D42E1B4EB48F00FE41AA /* turns_sound_settings.hpp in Headers */,
56099E341CC9247E00A7772A /* bicycle_directions.hpp in Headers */,
@ -749,6 +814,7 @@
670EE55F1B6001E7001E8064 /* routing_settings.hpp in Headers */,
671F58BE1B874EC80032311E /* followed_polyline.hpp in Headers */,
67C7D42C1B4EB48F00FE41AA /* pedestrian_model.hpp in Headers */,
0C5FEC6A1DDE193F0017688C /* road_index.hpp in Headers */,
674F9BCD1B0A580E00704FFA /* features_road_graph.hpp in Headers */,
670EE5741B664796001E8064 /* pedestrian_directions.hpp in Headers */,
6753441D1A3F644F00A0A8C3 /* router.hpp in Headers */,
@ -756,6 +822,7 @@
670EE5721B664796001E8064 /* directions_engine.hpp in Headers */,
A1876BC71BB19C4300C9C743 /* speed_camera.hpp in Headers */,
56EA2FD51D8FD8590083F01A /* routing_helpers.hpp in Headers */,
0C0DF9221DE898B70055A22F /* index_graph_starter.hpp in Headers */,
56099E2F1CC8FBDA00A7772A /* osrm_path_segment_factory.hpp in Headers */,
67C7D42A1B4EB48F00FE41AA /* car_model.hpp in Headers */,
670D049F1B0B4A970013A7AC /* nearest_edge_finder.hpp in Headers */,
@ -763,10 +830,13 @@
674F9BD51B0A580E00704FFA /* road_graph.hpp in Headers */,
56826BD11DB51C4E00807C62 /* car_router.hpp in Headers */,
A120B3511B4A7C0A002F3808 /* routing_algorithm.hpp in Headers */,
0C5FEC6B1DDE193F0017688C /* road_point.hpp in Headers */,
675344211A3F644F00A0A8C3 /* vehicle_model.hpp in Headers */,
56099E2B1CC7C97D00A7772A /* turn_candidate.hpp in Headers */,
0C5FEC551DDE191E0017688C /* edge_estimator.hpp in Headers */,
670B84C11A9381D900CE4492 /* cross_routing_context.hpp in Headers */,
563B91C61CC4F1DC00222BC1 /* bicycle_model.hpp in Headers */,
0C5FEC651DDE192A0017688C /* joint.hpp in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -983,6 +1053,7 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
0C5FEC641DDE192A0017688C /* joint.cpp in Sources */,
56826BD01DB51C4E00807C62 /* car_router.cpp in Sources */,
56099E2E1CC8FBDA00A7772A /* osrm_path_segment_factory.cpp in Sources */,
675344201A3F644F00A0A8C3 /* vehicle_model.cpp in Sources */,
@ -990,6 +1061,8 @@
A1616E2B1B6B60AB003F078E /* router_delegate.cpp in Sources */,
6741AA9C1BF35331002C974C /* turns_notification_manager.cpp in Sources */,
67C7D42B1B4EB48F00FE41AA /* pedestrian_model.cpp in Sources */,
0C0DF9251DE898CF0055A22F /* single_mwm_router.cpp in Sources */,
0C0DF9211DE898B70055A22F /* index_graph_starter.cpp in Sources */,
A120B3471B4A7BE5002F3808 /* cross_mwm_router.cpp in Sources */,
670EE5731B664796001E8064 /* pedestrian_directions.cpp in Sources */,
6753441B1A3F644F00A0A8C3 /* route.cpp in Sources */,
@ -1001,6 +1074,7 @@
563B91C51CC4F1DC00222BC1 /* bicycle_model.cpp in Sources */,
674F9BD21B0A580E00704FFA /* road_graph_router.cpp in Sources */,
A1876BC61BB19C4300C9C743 /* speed_camera.cpp in Sources */,
0C5FEC691DDE193F0017688C /* road_index.cpp in Sources */,
671F58BD1B874EC80032311E /* followed_polyline.cpp in Sources */,
670EE55D1B6001E7001E8064 /* routing_session.cpp in Sources */,
A120B3451B4A7BE5002F3808 /* cross_mwm_road_graph.cpp in Sources */,
@ -1008,15 +1082,21 @@
56099E331CC9247E00A7772A /* bicycle_directions.cpp in Sources */,
674A28B11B1605D2001A525C /* osrm_engine.cpp in Sources */,
674F9BD41B0A580E00704FFA /* road_graph.cpp in Sources */,
0C0DF92A1DE898FF0055A22F /* routing_helpers.cpp in Sources */,
67AB92E61B7B3E6E00AB5194 /* turns_tts_text.cpp in Sources */,
0C5FEC601DDE192A0017688C /* index_graph.cpp in Sources */,
0C5FEC6D1DDE19A40017688C /* index_graph_test.cpp in Sources */,
6753441E1A3F644F00A0A8C3 /* turns.cpp in Sources */,
670B84C01A9381D900CE4492 /* cross_routing_context.cpp in Sources */,
A120B3501B4A7C0A002F3808 /* routing_algorithm.cpp in Sources */,
674F9BCC1B0A580E00704FFA /* features_road_graph.cpp in Sources */,
0C5FEC5E1DDE192A0017688C /* geometry.cpp in Sources */,
674F9BD01B0A580E00704FFA /* online_cross_fetcher.cpp in Sources */,
670EE5751B664796001E8064 /* router.cpp in Sources */,
0C5FEC621DDE192A0017688C /* joint_index.cpp in Sources */,
670C62131AC5A15700C38A8C /* routing_mapping.cpp in Sources */,
67C7D42D1B4EB48F00FE41AA /* turns_sound_settings.cpp in Sources */,
0C5FEC541DDE191E0017688C /* edge_estimator.cpp in Sources */,
A120B34E1B4A7C0A002F3808 /* online_absent_fetcher.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;