From bbb6a7d8a237f670bbe66aeb798aa2aa4c3e69d3 Mon Sep 17 00:00:00 2001 From: tatiana-kondakova Date: Wed, 29 Nov 2017 11:05:41 +0300 Subject: [PATCH] Transit cross mwm routing --- generator/routing_index_generator.cpp | 5 +- routing/cross_mwm_connector.hpp | 11 ++- routing/cross_mwm_graph.cpp | 99 +++++++++++++++---- routing/cross_mwm_graph.hpp | 19 ++-- routing/cross_mwm_index_graph.hpp | 23 ++++- routing/index_graph_starter.hpp | 5 +- .../cross_mwm_connector_test.cpp | 18 ++-- routing/transit_graph.cpp | 8 +- routing/transit_world_graph.cpp | 18 ++-- 9 files changed, 157 insertions(+), 49 deletions(-) diff --git a/generator/routing_index_generator.cpp b/generator/routing_index_generator.cpp index 59f4f652fc..489ec0edd2 100644 --- a/generator/routing_index_generator.cpp +++ b/generator/routing_index_generator.cpp @@ -307,10 +307,9 @@ void CalcCrossMwmTransitions(string const & mwmFile, string const & mappingFile, }; // Index |i| is a zero based edge index. This zero based index should be increased with - // |FakeFeatureIds::kTransitGraphFeaturesStart| and then used in Segment class as + // |FakeFeatureIds::kTransitGraphFeaturesStart| by setting it as |featureNumerationOffset| for + // CrossMwmConnector (see CrossMwmIndexGraph::Deserialize()) and then used in Segment class as // feature id in transit case. - // @todo(tatiana-kondakova) The comment above should be rewritten when the zero based edge - // index is used. for (size_t i = 0; i < edges.size(); ++i) { auto const & e = edges[i]; diff --git a/routing/cross_mwm_connector.hpp b/routing/cross_mwm_connector.hpp index ae0b5e3c25..0cfcec2a52 100644 --- a/routing/cross_mwm_connector.hpp +++ b/routing/cross_mwm_connector.hpp @@ -40,12 +40,17 @@ class CrossMwmConnector final { public: CrossMwmConnector() : m_mwmId(kFakeNumMwmId) {} - explicit CrossMwmConnector(NumMwmId mwmId) : m_mwmId(mwmId) {} + CrossMwmConnector(NumMwmId mwmId, uint32_t featureNumerationOffset) + : m_mwmId(mwmId), m_featureNumerationOffset(featureNumerationOffset) + { + } void AddTransition(CrossMwmId const & crossMwmId, uint32_t featureId, uint32_t segmentIdx, bool oneWay, bool forwardIsEnter, m2::PointD const & backPoint, m2::PointD const & frontPoint) { + featureId += m_featureNumerationOffset; + Transition transition(connector::kFakeIndex, connector::kFakeIndex, crossMwmId, oneWay, forwardIsEnter, backPoint, frontPoint); @@ -299,6 +304,10 @@ private: std::unordered_map, HashKey> m_transitions; std::unordered_map m_crossMwmIdToFeatureId; connector::WeightsLoadState m_weightsLoadState = connector::WeightsLoadState::Unknown; + // For some connectors we may need to shift features with some offset. + // For example for versions and transit section compatibility we number transit features + // starting from 0 in mwm and shift them with |m_featureNumerationOffset| in runtime. + uint32_t const m_featureNumerationOffset = 0; uint64_t m_weightsOffset = 0; connector::Weight m_granularity = 0; // |m_weights| stores edge weights. diff --git a/routing/cross_mwm_graph.cpp b/routing/cross_mwm_graph.cpp index 07e428e878..78b0b139e4 100644 --- a/routing/cross_mwm_graph.cpp +++ b/routing/cross_mwm_graph.cpp @@ -1,5 +1,6 @@ #include "routing/cross_mwm_graph.hpp" #include "routing/routing_exceptions.hpp" +#include "routing/transit_graph.hpp" #include "indexer/scales.hpp" @@ -44,24 +45,34 @@ void CrossMwmGraph::ClosestSegment::Update(double distM, Segment const & bestSeg } // CrossMwmGraph ---------------------------------------------------------------------------------- -CrossMwmGraph::CrossMwmGraph(shared_ptr numMwmIds, shared_ptr> numMwmTree, - shared_ptr vehicleModelFactory, VehicleType vehicleType, - CourntryRectFn const & countryRectFn, Index & index, - RoutingIndexManager & indexManager) +CrossMwmGraph::CrossMwmGraph(shared_ptr numMwmIds, + shared_ptr> numMwmTree, + shared_ptr vehicleModelFactory, + VehicleType vehicleType, CourntryRectFn const & countryRectFn, + Index & index, RoutingIndexManager & indexManager) : m_index(index) , m_numMwmIds(numMwmIds) , m_numMwmTree(numMwmTree) , m_vehicleModelFactory(vehicleModelFactory) , m_countryRectFn(countryRectFn) , m_crossMwmIndexGraph(index, numMwmIds, vehicleType) + , m_crossMwmTransitGraph(index, numMwmIds, VehicleType::Transit) , m_crossMwmOsrmGraph(numMwmIds, indexManager) { CHECK(m_numMwmIds, ()); CHECK(m_vehicleModelFactory, ()); + CHECK_NOT_EQUAL(vehicleType, VehicleType::Transit, ()); } bool CrossMwmGraph::IsTransition(Segment const & s, bool isOutgoing) { + if (TransitGraph::IsTransitSegment(s)) + { + return TransitCrossMwmSectionExists(s.GetMwmId()) + ? m_crossMwmTransitGraph.IsTransition(s, isOutgoing) + : false; + } + return CrossMwmSectionExists(s.GetMwmId()) ? m_crossMwmIndexGraph.IsTransition(s, isOutgoing) : m_crossMwmOsrmGraph.IsTransition(s, isOutgoing); } @@ -115,10 +126,10 @@ void CrossMwmGraph::GetAllLoadedNeighbors(NumMwmId numMwmId, m_numMwmTree->ForEachInRect(rect, [&](NumMwmId id) { if (id == numMwmId) return; - MwmStatus const status = GetMwmStatus(id); + MwmStatus const status = GetCrossMwmStatus(id); if (status == MwmStatus::NotLoaded) return; - if (status == MwmStatus::NoCrossMwmSection) + if (status == MwmStatus::NoSection) allNeighborsHaveCrossMwmSection = false; neighbors.push_back(id); @@ -128,7 +139,17 @@ void CrossMwmGraph::GetAllLoadedNeighbors(NumMwmId numMwmId, void CrossMwmGraph::DeserializeTransitions(vector const & mwmIds) { for (auto mwmId : mwmIds) - m_crossMwmIndexGraph.GetCrossMwmConnectorWithTransitions(mwmId); + m_crossMwmIndexGraph.LoadCrossMwmConnectorWithTransitions(mwmId); +} + +void CrossMwmGraph::DeserializeTransitTransitions(vector const & mwmIds) +{ + for (auto mwmId : mwmIds) + { + // Some mwms may not have cross mwm transit section. + if (TransitCrossMwmSectionExists(mwmId)) + m_crossMwmTransitGraph.LoadCrossMwmConnectorWithTransitions(mwmId); + } } void CrossMwmGraph::GetTwins(Segment const & s, bool isOutgoing, vector & twins) @@ -146,11 +167,17 @@ void CrossMwmGraph::GetTwins(Segment const & s, bool isOutgoing, vector vector neighbors; bool allNeighborsHaveCrossMwmSection = false; GetAllLoadedNeighbors(s.GetMwmId(), neighbors, allNeighborsHaveCrossMwmSection); - MwmStatus const currentMwmStatus = GetMwmStatus(s.GetMwmId()); + MwmStatus const currentMwmStatus = GetCrossMwmStatus(s.GetMwmId()); CHECK_NOT_EQUAL(currentMwmStatus, MwmStatus::NotLoaded, ("Current mwm is not loaded. Mwm:", m_numMwmIds->GetFile(s.GetMwmId()), "currentMwmStatus:", currentMwmStatus)); - if (allNeighborsHaveCrossMwmSection && currentMwmStatus == MwmStatus::CrossMwmSectionExists) + + if (TransitGraph::IsTransitSegment(s) && TransitCrossMwmSectionExists(s.GetMwmId())) + { + DeserializeTransitTransitions(neighbors); + m_crossMwmTransitGraph.GetTwinsByCrossMwmId(s, isOutgoing, neighbors, twins); + } + else if (allNeighborsHaveCrossMwmSection && currentMwmStatus == MwmStatus::SectionExists) { DeserializeTransitions(neighbors); m_crossMwmIndexGraph.GetTwinsByCrossMwmId(s, isOutgoing, neighbors, twins); @@ -200,6 +227,13 @@ void CrossMwmGraph::GetEdgeList(Segment const & s, bool isOutgoing, vectorGetFile(numMwmId)); if (!handle.IsAlive()) return MwmStatus::NotLoaded; MwmValue * value = handle.GetValue(); CHECK(value != nullptr, ("Country file:", m_numMwmIds->GetFile(numMwmId))); - return value->m_cont.IsExist(CROSS_MWM_FILE_TAG) ? MwmStatus::CrossMwmSectionExists - : MwmStatus::NoCrossMwmSection; + return value->m_cont.IsExist(sectionName) ? MwmStatus::SectionExists : MwmStatus::NoSection; } -bool CrossMwmGraph::CrossMwmSectionExists(NumMwmId numMwmId) +CrossMwmGraph::MwmStatus CrossMwmGraph::GetCrossMwmStatus(NumMwmId numMwmId) const { - CrossMwmGraph::MwmStatus const status = GetMwmStatus(numMwmId); + if (m_crossMwmIndexGraph.InCache(numMwmId)) + return MwmStatus::SectionExists; + return GetMwmStatus(numMwmId, CROSS_MWM_FILE_TAG); +} + +CrossMwmGraph::MwmStatus CrossMwmGraph::GetTransitCrossMwmStatus(NumMwmId numMwmId) const +{ + if (m_crossMwmTransitGraph.InCache(numMwmId)) + return MwmStatus::SectionExists; + return GetMwmStatus(numMwmId, TRANSIT_CROSS_MWM_FILE_TAG); +} + +bool CrossMwmGraph::CrossMwmSectionExists(NumMwmId numMwmId) const +{ + CrossMwmGraph::MwmStatus const status = GetCrossMwmStatus(numMwmId); if (status == MwmStatus::NotLoaded) MYTHROW(RoutingException, ("Mwm", m_numMwmIds->GetFile(numMwmId), "cannot be loaded.")); - return status == MwmStatus::CrossMwmSectionExists; + return status == MwmStatus::SectionExists; +} + +bool CrossMwmGraph::TransitCrossMwmSectionExists(NumMwmId numMwmId) const +{ + CrossMwmGraph::MwmStatus const status = GetTransitCrossMwmStatus(numMwmId); + if (status == MwmStatus::NotLoaded) + MYTHROW(RoutingException, ("Mwm", m_numMwmIds->GetFile(numMwmId), "cannot be loaded.")); + + return status == MwmStatus::SectionExists; } void CrossMwmGraph::GetTwinCandidates(FeatureType const & ft, bool isOutgoing, @@ -268,9 +326,8 @@ string DebugPrint(CrossMwmGraph::MwmStatus status) switch (status) { case CrossMwmGraph::MwmStatus::NotLoaded: return "CrossMwmGraph::NotLoaded"; - case CrossMwmGraph::MwmStatus::CrossMwmSectionExists: - return "CrossMwmGraph::CrossMwmSectionExists"; - case CrossMwmGraph::MwmStatus::NoCrossMwmSection: return "CrossMwmGraph::NoCrossMwmSection"; + case CrossMwmGraph::MwmStatus::SectionExists: return "CrossMwmGraph::SectionExists"; + case CrossMwmGraph::MwmStatus::NoSection: return "CrossMwmGraph::NoSection"; } return string("Unknown CrossMwmGraph::MwmStatus."); } diff --git a/routing/cross_mwm_graph.hpp b/routing/cross_mwm_graph.hpp index c2228b0606..c45540ffa0 100644 --- a/routing/cross_mwm_graph.hpp +++ b/routing/cross_mwm_graph.hpp @@ -31,8 +31,8 @@ public: enum class MwmStatus { NotLoaded, - CrossMwmSectionExists, - NoCrossMwmSection, + SectionExists, + NoSection, }; CrossMwmGraph(std::shared_ptr numMwmIds, shared_ptr> numMwmTree, @@ -93,6 +93,10 @@ public: void Clear(); + // Applies |fn| to each nontransit transition. We never need to apply function to both transit + // and nontransit transitions. + // We may need to implement ForEachTransitTransition() or |isTransit| flag here when we'll have + // leaps for transit. template void ForEachTransition(NumMwmId numMwmId, bool isEnter, Fn && fn) { @@ -121,8 +125,11 @@ private: /// one or very small in rare cases in OSRM. TransitionPoints GetTransitionPoints(Segment const & s, bool isOutgoing); - MwmStatus GetMwmStatus(NumMwmId numMwmId) const; - bool CrossMwmSectionExists(NumMwmId numMwmId); + MwmStatus GetMwmStatus(NumMwmId numMwmId, std::string const & sectionName) const; + MwmStatus GetCrossMwmStatus(NumMwmId numMwmId) const; + MwmStatus GetTransitCrossMwmStatus(NumMwmId numMwmId) const; + bool CrossMwmSectionExists(NumMwmId numMwmId) const; + bool TransitCrossMwmSectionExists(NumMwmId numMwmId) const; /// \brief Fills |twins| with transition segments of feature |ft| of type |isOutgoing|. void GetTwinCandidates(FeatureType const & ft, bool isOutgoing, @@ -150,15 +157,15 @@ private: bool & allNeighborsHaveCrossMwmSection); /// \brief Deserizlize transitions for mwm with |ids|. void DeserializeTransitions(std::vector const & mwmIds); + void DeserializeTransitTransitions(std::vector const & mwmIds); Index & m_index; std::shared_ptr m_numMwmIds; std::shared_ptr> m_numMwmTree; std::shared_ptr m_vehicleModelFactory; CourntryRectFn const & m_countryRectFn; - // @todo(@tatiana-kondakova) For the time being CrossMwmGraph is implemented for osm id. - // To add cross mwm for transit graph it's necessary to add CrossMwmIndexGraph. CrossMwmIndexGraph m_crossMwmIndexGraph; + CrossMwmIndexGraph m_crossMwmTransitGraph; CrossMwmOsrmGraph m_crossMwmOsrmGraph; }; diff --git a/routing/cross_mwm_index_graph.hpp b/routing/cross_mwm_index_graph.hpp index 363f3a4215..87d1040f9d 100644 --- a/routing/cross_mwm_index_graph.hpp +++ b/routing/cross_mwm_index_graph.hpp @@ -3,6 +3,7 @@ #include "routing/cross_mwm_connector.hpp" #include "routing/cross_mwm_connector_serialization.hpp" #include "routing/cross_mwm_road_graph.hpp" +#include "routing/fake_feature_ids.hpp" #include "routing/routing_exceptions.hpp" #include "routing/segment.hpp" #include "routing/transition_points.hpp" @@ -35,6 +36,18 @@ inline FilesContainerR::TReader GetReader(FilesContainerR const & con { return cont.GetReader(TRANSIT_CROSS_MWM_FILE_TAG); } + +template +uint32_t constexpr GetFeaturesOffset() noexcept +{ + return 0; +} + +template <> +uint32_t constexpr GetFeaturesOffset() noexcept +{ + return FakeFeatureIds::kTransitGraphFeaturesStart; +} } // namespace connector template @@ -112,6 +125,11 @@ public: CrossMwmConnectorSerializer::DeserializeTransitions); } + void LoadCrossMwmConnectorWithTransitions(NumMwmId numMwmId) + { + GetCrossMwmConnectorWithTransitions(numMwmId); + } + template void ForEachTransition(NumMwmId numMwmId, bool isEnter, Fn && fn) { @@ -151,7 +169,10 @@ private: ReaderSourceFile src(reader); auto it = m_connectors.find(numMwmId); if (it == m_connectors.end()) - it = m_connectors.emplace(numMwmId, CrossMwmConnector(numMwmId)).first; + it = m_connectors + .emplace(numMwmId, CrossMwmConnector( + numMwmId, connector::GetFeaturesOffset())) + .first; fn(m_vehicleType, it->second, src); return it->second; diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp index e849b619a2..b01c3699a3 100644 --- a/routing/index_graph_starter.hpp +++ b/routing/index_graph_starter.hpp @@ -105,7 +105,10 @@ public: private: static Segment GetFakeSegment(uint32_t segmentIdx) { - return Segment(kFakeNumMwmId, kFakeFeatureId, segmentIdx, false); + // We currently ignore |isForward| and use FakeGraph to get ingoing/outgoing. + // But all fake segments are oneway and placement of segment head and tail + // correspond forward direction. + return Segment(kFakeNumMwmId, kFakeFeatureId, segmentIdx, true /* isForward */); } static Segment GetFakeSegmentAndIncr(uint32_t & segmentIdx) diff --git a/routing/routing_tests/cross_mwm_connector_test.cpp b/routing/routing_tests/cross_mwm_connector_test.cpp index b0cc7345e1..034f64a99d 100644 --- a/routing/routing_tests/cross_mwm_connector_test.cpp +++ b/routing/routing_tests/cross_mwm_connector_test.cpp @@ -15,6 +15,12 @@ namespace { NumMwmId constexpr mwmId = 777; +template +CrossMwmConnector CreateConnector() +{ + return CrossMwmConnector(mwmId, 0 /* featuresNumerationOffset */); +} + template void TestConnectorConsistency(CrossMwmConnector const & connector) { @@ -45,7 +51,7 @@ void TestOneWayEnter(CrossMwmId const & crossMwmId) { uint32_t constexpr featureId = 1; uint32_t constexpr segmentIdx = 1; - CrossMwmConnector connector(mwmId); + auto connector = CreateConnector(); connector.AddTransition(crossMwmId, featureId, segmentIdx, true /* oneWay */, true /* forwardIsEnter */, {} /* backPoint */, {} /* frontPoint */); @@ -71,7 +77,7 @@ void TestOneWayExit(CrossMwmId const & crossMwmId) { uint32_t constexpr featureId = 1; uint32_t constexpr segmentIdx = 1; - CrossMwmConnector connector(mwmId); + auto connector = CreateConnector(); connector.AddTransition(crossMwmId, featureId, segmentIdx, true /* oneWay */, false /* forwardIsEnter */, {} /* backPoint */, {} /* frontPoint */); @@ -97,7 +103,7 @@ void TestTwoWayEnter(CrossMwmId const & crossMwmId) { uint32_t constexpr featureId = 1; uint32_t constexpr segmentIdx = 1; - CrossMwmConnector connector(mwmId); + auto connector = CreateConnector(); connector.AddTransition(crossMwmId, featureId, segmentIdx, false /* oneWay */, true /* forwardIsEnter */, {} /* backPoint */, {} /* frontPoint */); @@ -122,7 +128,7 @@ void TestTwoWayExit(CrossMwmId const & crossMwmId) { uint32_t constexpr featureId = 1; uint32_t constexpr segmentIdx = 1; - CrossMwmConnector connector(mwmId); + auto connector = CreateConnector(); connector.AddTransition(crossMwmId, featureId, segmentIdx, false /* oneWay */, false /* forwardIsEnter */, {} /* backPoint */, {} /* frontPoint */); @@ -163,7 +169,7 @@ void TestSerialization(vector connector(mwmId); + auto connector = CreateConnector(); { MemReader reader(buffer.data(), buffer.size()); ReaderSource source(reader); @@ -281,7 +287,7 @@ void TestWeightsSerialization() CrossMwmConnectorSerializer::Serialize(transitions, connectors, codingParams, writer); } - CrossMwmConnector connector(mwmId); + auto connector = CreateConnector(); { MemReader reader(buffer.data(), buffer.size()); ReaderSource source(reader); diff --git a/routing/transit_graph.cpp b/routing/transit_graph.cpp index c6a3d6992c..39546ed2ed 100644 --- a/routing/transit_graph.cpp +++ b/routing/transit_graph.cpp @@ -199,7 +199,13 @@ transit::Edge const & TransitGraph::GetEdge(Segment const & segment) const Segment TransitGraph::GetTransitSegment(uint32_t featureId) const { CHECK(IsTransitFeature(featureId), ("Feature id is out of transit id interval.")); - return Segment(m_mwmId, featureId, 0 /* segmentIdx*/, false /* isForward */); + // All transit segments are oneway forward segments. + // Edge segment has tail in stop1 and head in stop2. + // Gate segment has tail in gate and head in stop. + // Pedestrian projection and parts of real have tail in |0| and head in |1|. + // We rely on this rule in cross-mwm to have same behaviour of transit and + // non-transit segments. + return Segment(m_mwmId, featureId, 0 /* segmentIdx*/, true /* isForward */); } Segment TransitGraph::GetNewTransitSegment() const diff --git a/routing/transit_world_graph.cpp b/routing/transit_world_graph.cpp index f6a4622d43..6101b2a638 100644 --- a/routing/transit_world_graph.cpp +++ b/routing/transit_world_graph.cpp @@ -33,7 +33,6 @@ void TransitWorldGraph::GetEdgeList(Segment const & segment, bool isOutgoing, bo if (TransitGraph::IsTransitSegment(segment)) { transitGraph.GetTransitEdges(segment, isOutgoing, edges); - // TODO (@t.yan) GetTwins for transit edges Segment real; if (transitGraph.FindReal(segment, real)) @@ -43,6 +42,8 @@ void TransitWorldGraph::GetEdgeList(Segment const & segment, bool isOutgoing, bo if ((isOutgoing && haveSameFront) || (!isOutgoing && haveSameBack)) AddRealEdges(real, isOutgoing, edges); } + + GetTwins(segment, isOutgoing, edges); } else { @@ -159,8 +160,12 @@ unique_ptr TransitWorldGraph::GetTransitInfo(Segment const & segmen void TransitWorldGraph::GetTwins(Segment const & segment, bool isOutgoing, vector & edges) { - // TODO (@t.yan) GetTwins for fake transit segments. - CHECK(!TransitGraph::IsTransitSegment(segment), ("Not implemented")); + if (m_mode == Mode::SingleMwm || !m_crossMwmGraph || + !m_crossMwmGraph->IsTransition(segment, isOutgoing)) + { + return; + } + m_twins.clear(); m_crossMwmGraph->GetTwins(segment, isOutgoing, m_twins); for (Segment const & twin : m_twins) @@ -186,12 +191,7 @@ void TransitWorldGraph::AddRealEdges(Segment const & segment, bool isOutgoing, { auto & indexGraph = GetIndexGraph(segment.GetMwmId()); indexGraph.GetEdgeList(segment, isOutgoing, edges); - - if (m_mode != Mode::SingleMwm && m_crossMwmGraph && - m_crossMwmGraph->IsTransition(segment, isOutgoing)) - { - GetTwins(segment, isOutgoing, edges); - } + GetTwins(segment, isOutgoing, edges); } IndexGraph & TransitWorldGraph::GetIndexGraph(NumMwmId mwmId)