From db2dc29c6a87aa2d3aef520b471b5dea1adecc93 Mon Sep 17 00:00:00 2001 From: Mikhail Gorbushin Date: Fri, 23 Aug 2019 19:39:51 +0300 Subject: [PATCH] [routing] Refact EdgeEstimator add penalty for Ferries --- generator/osm2meta.cpp | 1 - routing/edge_estimator.cpp | 52 +++++++++++++----- routing/edge_estimator.hpp | 9 ++- routing/geometry.cpp | 34 ++++++++++++ routing/geometry.hpp | 3 + routing/index_graph.cpp | 55 +++++++++++++++---- routing/index_graph.hpp | 14 ++++- routing/index_graph_starter.cpp | 15 ++++- routing/index_graph_starter.hpp | 3 +- routing/index_router.cpp | 6 +- routing/leaps_postprocessor.cpp | 6 +- .../transit_route_test.cpp | 22 ++++---- routing/routing_tests/index_graph_tools.cpp | 3 +- routing/routing_tests/index_graph_tools.hpp | 3 +- routing/single_vehicle_world_graph.cpp | 14 ++++- routing/single_vehicle_world_graph.hpp | 3 +- routing/transit_world_graph.cpp | 21 ++++++- routing/transit_world_graph.hpp | 4 +- routing/world_graph.hpp | 3 +- 19 files changed, 214 insertions(+), 57 deletions(-) diff --git a/generator/osm2meta.cpp b/generator/osm2meta.cpp index df12b8383e..a24dd2edd1 100644 --- a/generator/osm2meta.cpp +++ b/generator/osm2meta.cpp @@ -11,7 +11,6 @@ #include "base/string_utils.hpp" #include -#include #include #include #include diff --git a/routing/edge_estimator.cpp b/routing/edge_estimator.cpp index 3c3d41e1a2..bbda70cd73 100644 --- a/routing/edge_estimator.cpp +++ b/routing/edge_estimator.cpp @@ -20,12 +20,6 @@ namespace { feature::TAltitude constexpr kMountainSicknessAltitudeM = 2500; -enum class Purpose -{ - Weight, - ETA -}; - double TimeBetweenSec(m2::PointD const & from, m2::PointD const & to, double speedMpS) { CHECK_GREATER(speedMpS, 0.0, @@ -78,15 +72,15 @@ double GetBicycleClimbPenalty(double tangent, feature::TAltitude altitudeM) double GetCarClimbPenalty(double /* tangent */, feature::TAltitude /* altitude */) { return 1.0; } template -double CalcClimbSegment(Purpose purpose, Segment const & segment, RoadGeometry const & road, - GetClimbPenalty && getClimbPenalty) +double CalcClimbSegment(EdgeEstimator::Purpose purpose, Segment const & segment, + RoadGeometry const & road, GetClimbPenalty && getClimbPenalty) { Junction const & from = road.GetJunction(segment.GetPointId(false /* front */)); Junction const & to = road.GetJunction(segment.GetPointId(true /* front */)); SpeedKMpH const & speed = road.GetSpeed(segment.IsForward()); double const distance = MercatorBounds::DistanceOnEarth(from.GetPoint(), to.GetPoint()); - double const speedMpS = KMPH2MPS(purpose == Purpose::Weight ? speed.m_weight : speed.m_eta); + double const speedMpS = KMPH2MPS(purpose == EdgeEstimator::Purpose::Weight ? speed.m_weight : speed.m_eta); CHECK_GREATER(speedMpS, 0.0, ()); double const timeSec = distance / speedMpS; @@ -138,7 +132,17 @@ public: } // EdgeEstimator overrides: - double GetUTurnPenalty() const override { return 0.0 /* seconds */; } + double GetUTurnPenalty(Purpose /* purpose */) const override { return 0.0 /* seconds */; } + // Based on: https://confluence.mail.ru/display/MAPSME/Ferries + double GetFerryLandingPenalty(Purpose purpose) const override + { + switch (purpose) + { + case Purpose::Weight: return 20 * 60; // seconds + case Purpose::ETA: return 8 * 60; // seconds + } + UNREACHABLE(); + } double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road) const override { @@ -161,7 +165,17 @@ public: } // EdgeEstimator overrides: - double GetUTurnPenalty() const override { return 20.0 /* seconds */; } + double GetUTurnPenalty(Purpose /* purpose */) const override { return 20.0 /* seconds */; } + // Based on: https://confluence.mail.ru/display/MAPSME/Ferries + double GetFerryLandingPenalty(Purpose purpose) const override + { + switch (purpose) + { + case Purpose::Weight: return 20 * 60; // seconds + case Purpose::ETA: return 8 * 60; // seconds + } + UNREACHABLE(); + } double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road) const override { @@ -184,7 +198,8 @@ public: // EdgeEstimator overrides: double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road) const override; double CalcSegmentETA(Segment const & segment, RoadGeometry const & road) const override; - double GetUTurnPenalty() const override; + double GetUTurnPenalty(Purpose /* purpose */) const override; + double GetFerryLandingPenalty(Purpose purpose) const override; private: double CalcSegment(Purpose purpose, Segment const & segment, RoadGeometry const & road) const; @@ -207,7 +222,7 @@ double CarEstimator::CalcSegmentETA(Segment const & segment, RoadGeometry const return CalcSegment(Purpose::ETA, segment, road); } -double CarEstimator::GetUTurnPenalty() const +double CarEstimator::GetUTurnPenalty(Purpose /* purpose */) const { // Adds 2 minutes penalty for U-turn. The value is quite arbitrary // and needs to be properly selected after a number of real-world @@ -215,6 +230,17 @@ double CarEstimator::GetUTurnPenalty() const return 2 * 60; // seconds } +double CarEstimator::GetFerryLandingPenalty(Purpose purpose) const +{ + switch (purpose) + { + case Purpose::Weight: return 40 * 60; // seconds + // Based on https://confluence.mail.ru/display/MAPSME/Ferries + case Purpose::ETA: return 20 * 60; // seconds + } + UNREACHABLE(); +} + double CarEstimator::CalcSegment(Purpose purpose, Segment const & segment, RoadGeometry const & road) const { double result = CalcClimbSegment(purpose, segment, road, GetCarClimbPenalty); diff --git a/routing/edge_estimator.hpp b/routing/edge_estimator.hpp index 42fa906475..524a8d7179 100644 --- a/routing/edge_estimator.hpp +++ b/routing/edge_estimator.hpp @@ -21,6 +21,12 @@ namespace routing class EdgeEstimator { public: + enum class Purpose + { + Weight, + ETA + }; + EdgeEstimator(double maxWeightSpeedKMpH, double offroadSpeedKMpH); virtual ~EdgeEstimator() = default; @@ -39,7 +45,8 @@ public: virtual double CalcSegmentWeight(Segment const & segment, RoadGeometry const & road) const = 0; virtual double CalcSegmentETA(Segment const & segment, RoadGeometry const & road) const = 0; - virtual double GetUTurnPenalty() const = 0; + virtual double GetUTurnPenalty(Purpose purpose) const = 0; + virtual double GetFerryLandingPenalty(Purpose purpose) const = 0; static std::shared_ptr Create(VehicleType vehicleType, double maxWeighSpeedKMpH, double offroadSpeedKMpH, diff --git a/routing/geometry.cpp b/routing/geometry.cpp index f7f10d693d..ca340f08e0 100644 --- a/routing/geometry.cpp +++ b/routing/geometry.cpp @@ -13,6 +13,7 @@ #include "geometry/mercator.hpp" #include "base/assert.hpp" +#include "base/string_utils.hpp" #include #include @@ -178,6 +179,27 @@ void RoadGeometry::Load(VehicleModelInterface const & vehicleModel, FeatureType altitudes ? (*altitudes)[i] : feature::kDefaultAltitudeMeters); } + if (m_routingOptions.Has(RoutingOptions::Road::Ferry)) + { + // Look for more info: https://confluence.mail.ru/display/MAPSME/Ferries + // Shortly: the coefs were received from statistic about ferries with durations in OSM. + double constexpr kBias = 0.2490726747447476; + double constexpr kCoef = 0.02078913; + + auto const durationHours = feature.GetMetadata().Get(feature::Metadata::FMD_DURATION); + auto const roadLenKm = GetRoadLengthM() / 1000.0; + double durationH = 0.0; + + if (!durationHours.empty()) + CHECK(strings::to_double(durationHours.c_str(), durationH), (durationHours)); + else + durationH = kBias + kCoef * roadLenKm; + + CHECK(!base::AlmostEqualAbs(durationH, 0.0, 1e-5), ()); + m_forwardSpeed = m_backwardSpeed = + SpeedKMpH(std::min(vehicleModel.GetMaxWeightSpeed(), roadLenKm / durationH)); + } + if (m_valid && (!m_forwardSpeed.IsValid() || !m_backwardSpeed.IsValid())) { auto const & id = feature.GetID(); @@ -196,6 +218,18 @@ SpeedKMpH const & RoadGeometry::GetSpeed(bool forward) const return forward ? m_forwardSpeed : m_backwardSpeed; } +double RoadGeometry::GetRoadLengthM() const +{ + double lenM = 0.0; + for (size_t i = 1; i < GetPointsCount(); ++i) + { + lenM += + MercatorBounds::DistanceOnEarth(m_junctions[i - 1].GetPoint(), m_junctions[i].GetPoint()); + } + + return lenM; +} + // Geometry ---------------------------------------------------------------------------------------- Geometry::Geometry(unique_ptr loader) : m_loader(move(loader)) diff --git a/routing/geometry.hpp b/routing/geometry.hpp index d5e819303c..f32255e5af 100644 --- a/routing/geometry.hpp +++ b/routing/geometry.hpp @@ -77,6 +77,9 @@ public: RoutingOptions GetRoutingOptions() const { return m_routingOptions; } private: + + double GetRoadLengthM() const; + buffer_vector m_junctions; SpeedKMpH m_forwardSpeed; SpeedKMpH m_backwardSpeed; diff --git a/routing/index_graph.cpp b/routing/index_graph.cpp index 87bbc7eaeb..f2a1c5f286 100644 --- a/routing/index_graph.cpp +++ b/routing/index_graph.cpp @@ -342,8 +342,8 @@ void IndexGraph::ReconstructJointSegment(JointSegment const & parentJoint, do { - RouteWeight const weight = CalcSegmentWeight(isOutgoing ? current : prev) + - GetPenalties(isOutgoing ? prev : current, isOutgoing ? current : prev); + RouteWeight const weight = + CalculateEdgeWeight(EdgeEstimator::Purpose::Weight, isOutgoing, prev, current); if (isOutgoing || prev != parent) summaryWeight += weight; @@ -378,25 +378,37 @@ void IndexGraph::GetNeighboringEdge(Segment const & from, Segment const & to, bo if (m_roadAccess.GetPointType(rp) == RoadAccess::Type::No) return; - RouteWeight const weight = CalcSegmentWeight(isOutgoing ? to : from) + - GetPenalties(isOutgoing ? from : to, isOutgoing ? to : from); - edges.emplace_back(to, weight); + RouteWeight weight = CalculateEdgeWeight(EdgeEstimator::Purpose::Weight, isOutgoing, from, to); + edges.emplace_back(to, std::move(weight)); } -RouteWeight IndexGraph::GetPenalties(Segment const & u, Segment const & v) +IndexGraph::PenaltyData IndexGraph::GetRoadPenaltyData(Segment const & segment) { - bool const fromPassThroughAllowed = m_geometry->GetRoad(u.GetFeatureId()).IsPassThroughAllowed(); - bool const toPassThroughAllowed = m_geometry->GetRoad(v.GetFeatureId()).IsPassThroughAllowed(); + auto const & road = m_geometry->GetRoad(segment.GetFeatureId()); + + PenaltyData result; + result.m_passThroughAllowed = road.IsPassThroughAllowed(); + result.m_isFerry = road.GetRoutingOptions().Has(RoutingOptions::Road::Ferry); + + return result; +} + +RouteWeight IndexGraph::GetPenalties(EdgeEstimator::Purpose purpose, + Segment const & u, Segment const & v) +{ + auto const & fromPenaltyData = GetRoadPenaltyData(u); + auto const & toPenaltyData = GetRoadPenaltyData(v); // Route crosses border of pass-through/non-pass-through area if |u| and |v| have different // pass through restrictions. - int32_t const passThroughPenalty = fromPassThroughAllowed == toPassThroughAllowed ? 0 : 1; + int8_t const passThroughPenalty = + fromPenaltyData.m_passThroughAllowed == toPenaltyData.m_passThroughAllowed ? 0 : 1; // We do not distinguish between RoadAccess::Type::Private and RoadAccess::Type::Destination for now. bool const fromAccessAllowed = m_roadAccess.GetFeatureType(u.GetFeatureId()) == RoadAccess::Type::Yes; bool const toAccessAllowed = m_roadAccess.GetFeatureType(v.GetFeatureId()) == RoadAccess::Type::Yes; // Route crosses border of access=yes/access={private, destination} area if |u| and |v| have different // access restrictions. - int32_t accessPenalty = fromAccessAllowed == toAccessAllowed ? 0 : 1; + int8_t accessPenalty = fromAccessAllowed == toAccessAllowed ? 0 : 1; // RoadPoint between u and v is front of u. auto const rp = u.GetRoadPoint(true /* front */); @@ -404,9 +416,14 @@ RouteWeight IndexGraph::GetPenalties(Segment const & u, Segment const & v) if (m_roadAccess.GetPointType(rp) != RoadAccess::Type::Yes) accessPenalty = 1; - auto const uTurnPenalty = IsUTurn(u, v) ? m_estimator->GetUTurnPenalty() : 0.0; + double weightPenalty = 0.0; + if (IsUTurn(u, v)) + weightPenalty += m_estimator->GetUTurnPenalty(purpose); - return RouteWeight(uTurnPenalty /* weight */, passThroughPenalty, accessPenalty, 0.0 /* transitTime */); + if (!fromPenaltyData.m_isFerry && toPenaltyData.m_isFerry) + weightPenalty += m_estimator->GetFerryLandingPenalty(purpose); + + return {weightPenalty /* weight */, passThroughPenalty, accessPenalty, 0.0 /* transitTime */}; } WorldGraphMode IndexGraph::GetMode() const { return WorldGraphMode::Undefined; } @@ -436,4 +453,18 @@ bool IndexGraph::IsUTurnAndRestricted(Segment const & parent, Segment const & ch ASSERT_GREATER_OR_EQUAL(n, 1, ()); return uTurn.m_atTheEnd && turnPoint == n - 1; } + +RouteWeight IndexGraph::CalculateEdgeWeight(EdgeEstimator::Purpose purpose, bool isOutgoing, + Segment const & from, Segment const & to) +{ + auto const & segment = isOutgoing ? to : from; + auto const & weight = + purpose == EdgeEstimator::Purpose::Weight ? + RouteWeight(m_estimator->CalcSegmentWeight(segment, m_geometry->GetRoad(segment.GetFeatureId()))) : + RouteWeight(m_estimator->CalcSegmentETA(segment, m_geometry->GetRoad(segment.GetFeatureId()))); + + auto const & penalties = GetPenalties(purpose, isOutgoing ? from : to, isOutgoing ? to : from); + + return weight + penalties; +} } // namespace routing diff --git a/routing/index_graph.hpp b/routing/index_graph.hpp index d9797168c1..d6b3d13c6b 100644 --- a/routing/index_graph.hpp +++ b/routing/index_graph.hpp @@ -116,6 +116,10 @@ public: std::map & parents) const; bool IsUTurnAndRestricted(Segment const & parent, Segment const & child, bool isOutgoing) const; + + RouteWeight CalculateEdgeWeight(EdgeEstimator::Purpose purpose, bool isOutgoing, + Segment const & from, Segment const & to); + private: RouteWeight CalcSegmentWeight(Segment const & segment); @@ -125,7 +129,15 @@ private: std::map & parents); void GetNeighboringEdge(Segment const & from, Segment const & to, bool isOutgoing, std::vector & edges, std::map & parents); - RouteWeight GetPenalties(Segment const & u, Segment const & v); + + struct PenaltyData + { + bool m_passThroughAllowed = false; + bool m_isFerry = false; + }; + + PenaltyData GetRoadPenaltyData(Segment const & segment); + RouteWeight GetPenalties(EdgeEstimator::Purpose purpose, Segment const & u, Segment const & v); void GetSegmentCandidateForRoadPoint(RoadPoint const & rp, NumMwmId numMwmId, bool isOutgoing, std::vector & children); diff --git a/routing/index_graph_starter.cpp b/routing/index_graph_starter.cpp index 847f4f30cb..5199806e27 100644 --- a/routing/index_graph_starter.cpp +++ b/routing/index_graph_starter.cpp @@ -270,13 +270,24 @@ RouteWeight IndexGraphStarter::CalcSegmentWeight(Segment const & segment) const return m_graph.CalcOffroadWeight(vertex.GetPointFrom(), vertex.GetPointTo()); } -double IndexGraphStarter::CalcSegmentETA(Segment const & segment) const +double IndexGraphStarter::CalculateETA(Segment const & from, Segment const & to) const { // We don't distinguish fake segment weight and fake segment transit time. + if (IsFakeSegment(to)) + return CalcSegmentWeight(to).GetWeight(); + + if (IsFakeSegment(from)) + return CalculateETAWithoutPenalty(to); + + return m_graph.CalculateETA(from, to); +} + +double IndexGraphStarter::CalculateETAWithoutPenalty(Segment const & segment) const +{ if (IsFakeSegment(segment)) return CalcSegmentWeight(segment).GetWeight(); - return m_graph.CalcSegmentETA(segment); + return m_graph.CalculateETAWithoutPenalty(segment); } void IndexGraphStarter::AddEnding(FakeEnding const & thisEnding, FakeEnding const & otherEnding, diff --git a/routing/index_graph_starter.hpp b/routing/index_graph_starter.hpp index 0888fb9225..fcbfe3d89e 100644 --- a/routing/index_graph_starter.hpp +++ b/routing/index_graph_starter.hpp @@ -135,7 +135,8 @@ public: } RouteWeight CalcSegmentWeight(Segment const & segment) const; - double CalcSegmentETA(Segment const & segment) const; + double CalculateETA(Segment const & from, Segment const & to) const; + double CalculateETAWithoutPenalty(Segment const & segment) const; // For compatibility with IndexGraphStarterJoints // @{ diff --git a/routing/index_router.cpp b/routing/index_router.cpp index 2835ea4892..5052d9a566 100644 --- a/routing/index_router.cpp +++ b/routing/index_router.cpp @@ -1313,12 +1313,14 @@ RouterResultCode IndexRouter::RedressRoute(vector const & segments, double time = 0.0; times.emplace_back(static_cast(0), 0.0); - for (size_t i = 0; i + 1 < numPoints; ++i) + for (size_t i = 0; i < segments.size() - 1; ++i) { - time += starter.CalcSegmentETA(segments[i]); + time += starter.CalculateETA(segments[i], segments[i + 1]); times.emplace_back(static_cast(i + 1), time); } + times.emplace_back(static_cast(segments.size()), time); + CHECK(m_directionsEngine, ()); ReconstructRoute(*m_directionsEngine, roadGraph, m_trafficStash, delegate, junctions, move(times), route); diff --git a/routing/leaps_postprocessor.cpp b/routing/leaps_postprocessor.cpp index e0b1c244e6..24d6938672 100644 --- a/routing/leaps_postprocessor.cpp +++ b/routing/leaps_postprocessor.cpp @@ -103,7 +103,7 @@ void LeapsPostProcessor::Init() for (size_t i = 1; i < m_path.size(); ++i) { auto const & segment = m_path[i]; - m_prefixSumETA[i] = m_prefixSumETA[i - 1] + m_starter.CalcSegmentETA(segment); + m_prefixSumETA[i] = m_prefixSumETA[i - 1] + m_starter.CalculateETAWithoutPenalty(segment); CHECK_EQUAL(m_segmentToIndex.count(segment), 0, ()); m_segmentToIndex[segment] = i; @@ -146,7 +146,7 @@ auto LeapsPostProcessor::CalculateIntervalsToRelax() -> std::set segmentsData; auto const & segment = m_path[right]; - segmentsData.emplace(segment, SegmentData(0, m_starter.CalcSegmentETA(segment))); + segmentsData.emplace(segment, SegmentData(0, m_starter.CalculateETAWithoutPenalty(segment))); FillIngoingPaths(segment, segmentsData); @@ -192,7 +192,7 @@ void LeapsPostProcessor::FillIngoingPaths( auto & current = segmentsData[state.m_vertex]; current.m_summaryETA = - parent.m_summaryETA + m_starter.CalcSegmentETA(state.m_vertex); + parent.m_summaryETA + m_starter.CalculateETAWithoutPenalty(state.m_vertex); current.m_steps = parent.m_steps + 1; diff --git a/routing/routing_integration_tests/transit_route_test.cpp b/routing/routing_integration_tests/transit_route_test.cpp index b9c04bcf69..88db1f831a 100644 --- a/routing/routing_integration_tests/transit_route_test.cpp +++ b/routing/routing_integration_tests/transit_route_test.cpp @@ -8,7 +8,7 @@ using namespace routing; namespace { -UNIT_TEST(Moscow_CenterToKotelniki_CrossMwm) +UNIT_TEST(Transit_Moscow_CenterToKotelniki_CrossMwm) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -22,7 +22,7 @@ UNIT_TEST(Moscow_CenterToKotelniki_CrossMwm) integration::CheckSubwayExistence(*routeResult.first); } -UNIT_TEST(Moscow_DubrovkaToTrtykovskya) +UNIT_TEST(Transit_Moscow_DubrovkaToTrtykovskya) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -36,7 +36,7 @@ UNIT_TEST(Moscow_DubrovkaToTrtykovskya) integration::CheckSubwayExistence(*routeResult.first); } -UNIT_TEST(Moscow_NoSubwayTest) +UNIT_TEST(Transit_Moscow_NoSubwayTest) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -50,7 +50,7 @@ UNIT_TEST(Moscow_NoSubwayTest) integration::CheckSubwayAbsent(*routeResult.first); } -UNIT_TEST(Piter_FrunzenskyaToPlochadVosstaniya) +UNIT_TEST(Transit_Piter_FrunzenskyaToPlochadVosstaniya) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -64,7 +64,7 @@ UNIT_TEST(Piter_FrunzenskyaToPlochadVosstaniya) integration::CheckSubwayExistence(*routeResult.first); } -UNIT_TEST(Piter_TooLongPedestrian) +UNIT_TEST(Transit_Piter_TooLongPedestrian) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -74,7 +74,7 @@ UNIT_TEST(Piter_TooLongPedestrian) TEST_EQUAL(routeResult.second, RouterResultCode::TransitRouteNotFoundTooLongPedestrian, ()); } -UNIT_TEST(Vatikan_NotEnoughGraphDataAtThenEnd) +UNIT_TEST(Transit_Vatikan_NotEnoughGraphDataAtThenEnd) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -85,7 +85,7 @@ UNIT_TEST(Vatikan_NotEnoughGraphDataAtThenEnd) TEST_EQUAL(routeResult.second, RouterResultCode::TransitRouteNotFoundTooLongPedestrian, ()); } -UNIT_TEST(Vatikan_CorneliaToOttaviano) +UNIT_TEST(Transit_Vatikan_CorneliaToOttaviano) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -100,7 +100,7 @@ UNIT_TEST(Vatikan_CorneliaToOttaviano) integration::CheckSubwayExistence(*routeResult.first); } -UNIT_TEST(London_PoplarToOval) +UNIT_TEST(Transit_London_PoplarToOval) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -115,7 +115,7 @@ UNIT_TEST(London_PoplarToOval) integration::CheckSubwayExistence(*routeResult.first); } -UNIT_TEST(London_DeptfordBridgeToCyprus) +UNIT_TEST(Transit_London_DeptfordBridgeToCyprus) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -130,7 +130,7 @@ UNIT_TEST(London_DeptfordBridgeToCyprus) integration::CheckSubwayExistence(*routeResult.first); } -UNIT_TEST(Washington_FoggyToShaw) +UNIT_TEST(Transit_Washington_FoggyToShaw) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), @@ -145,7 +145,7 @@ UNIT_TEST(Washington_FoggyToShaw) integration::CheckSubwayExistence(*routeResult.first); } -UNIT_TEST(NewYork_GrassmereToPleasantPlains) +UNIT_TEST(Transit_NewYork_GrassmereToPleasantPlains) { TRouteResult routeResult = integration::CalculateRoute(integration::GetVehicleComponents(VehicleType::Transit), diff --git a/routing/routing_tests/index_graph_tools.cpp b/routing/routing_tests/index_graph_tools.cpp index a80800bc7f..b88c0e1715 100644 --- a/routing/routing_tests/index_graph_tools.cpp +++ b/routing/routing_tests/index_graph_tools.cpp @@ -146,7 +146,8 @@ double WeightedEdgeEstimator::CalcSegmentWeight(Segment const & segment, return it->second; } -double WeightedEdgeEstimator::GetUTurnPenalty() const { return 0.0; } +double WeightedEdgeEstimator::GetUTurnPenalty(Purpose purpose) const { return 0.0; } +double WeightedEdgeEstimator::GetFerryLandingPenalty(Purpose purpose) const { return 0.0; } // TestIndexGraphTopology -------------------------------------------------------------------------- TestIndexGraphTopology::TestIndexGraphTopology(uint32_t numVertices) : m_numVertices(numVertices) {} diff --git a/routing/routing_tests/index_graph_tools.hpp b/routing/routing_tests/index_graph_tools.hpp index f7a2fd2d60..2b854e3af9 100644 --- a/routing/routing_tests/index_graph_tools.hpp +++ b/routing/routing_tests/index_graph_tools.hpp @@ -173,7 +173,8 @@ public: double CalcSegmentWeight(Segment const & segment, RoadGeometry const & /* road */) const override; double CalcSegmentETA(Segment const & segment, RoadGeometry const & road) const override { return 0.0; } - double GetUTurnPenalty() const override; + double GetUTurnPenalty(Purpose purpose) const override; + double GetFerryLandingPenalty(Purpose purpose) const override; private: std::map m_segmentWeights; diff --git a/routing/single_vehicle_world_graph.cpp b/routing/single_vehicle_world_graph.cpp index 08ab333704..637a9e7e4c 100644 --- a/routing/single_vehicle_world_graph.cpp +++ b/routing/single_vehicle_world_graph.cpp @@ -192,9 +192,19 @@ RouteWeight SingleVehicleWorldGraph::CalcOffroadWeight(m2::PointD const & from, return RouteWeight(m_estimator->CalcOffroadWeight(from, to)); } -double SingleVehicleWorldGraph::CalcSegmentETA(Segment const & segment) +double SingleVehicleWorldGraph::CalculateETA(Segment const & from, Segment const & to) { - return m_estimator->CalcSegmentETA(segment, GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId())); + if (from.GetMwmId() != to.GetMwmId()) + return CalculateETAWithoutPenalty(to); + + auto & indexGraph = m_loader->GetIndexGraph(from.GetMwmId()); + return indexGraph.CalculateEdgeWeight(EdgeEstimator::Purpose::ETA, true /* isOutgoing */, from, to).GetWeight(); +} + +double SingleVehicleWorldGraph::CalculateETAWithoutPenalty(Segment const & segment) +{ + return m_estimator->CalcSegmentETA(segment, + GetRoadGeometry(segment.GetMwmId(), segment.GetFeatureId())); } vector const & SingleVehicleWorldGraph::GetTransitions(NumMwmId numMwmId, bool isEnter) diff --git a/routing/single_vehicle_world_graph.hpp b/routing/single_vehicle_world_graph.hpp index ee67666c0d..3f50a8723f 100644 --- a/routing/single_vehicle_world_graph.hpp +++ b/routing/single_vehicle_world_graph.hpp @@ -62,7 +62,8 @@ public: RouteWeight CalcSegmentWeight(Segment const & segment) override; RouteWeight CalcLeapWeight(m2::PointD const & from, m2::PointD const & to) const override; RouteWeight CalcOffroadWeight(m2::PointD const & from, m2::PointD const & to) const override; - double CalcSegmentETA(Segment const & segment) override; + double CalculateETA(Segment const & from, Segment const & to) override; + double CalculateETAWithoutPenalty(Segment const & segment) override; std::vector const & GetTransitions(NumMwmId numMwmId, bool isEnter) override; diff --git a/routing/transit_world_graph.cpp b/routing/transit_world_graph.cpp index b582bc5266..0f5f0eecae 100644 --- a/routing/transit_world_graph.cpp +++ b/routing/transit_world_graph.cpp @@ -156,13 +156,28 @@ RouteWeight TransitWorldGraph::CalcOffroadWeight(m2::PointD const & from, return RouteWeight(m_estimator->CalcOffroadWeight(from, to)); } -double TransitWorldGraph::CalcSegmentETA(Segment const & segment) +double TransitWorldGraph::CalculateETA(Segment const & from, Segment const & to) +{ + if (TransitGraph::IsTransitSegment(from)) + return CalcSegmentWeight(to).GetWeight(); + + if (TransitGraph::IsTransitSegment(to)) + return CalcSegmentWeight(to).GetWeight(); + + if (from.GetMwmId() != to.GetMwmId()) + return m_estimator->CalcSegmentETA(to, GetRealRoadGeometry(to.GetMwmId(), to.GetFeatureId())); + + auto & indexGraph = m_indexLoader->GetIndexGraph(from.GetMwmId()); + return indexGraph.CalculateEdgeWeight(EdgeEstimator::Purpose::ETA, true /* isOutgoing */, from, to).GetWeight(); +} + +double TransitWorldGraph::CalculateETAWithoutPenalty(Segment const & segment) { - // TODO: Separate weight and ETA of transit segments. if (TransitGraph::IsTransitSegment(segment)) return CalcSegmentWeight(segment).GetWeight(); - return m_estimator->CalcSegmentETA(segment, GetRealRoadGeometry(segment.GetMwmId(), segment.GetFeatureId())); + return m_estimator->CalcSegmentETA(segment, + GetRealRoadGeometry(segment.GetMwmId(), segment.GetFeatureId())); } unique_ptr TransitWorldGraph::GetTransitInfo(Segment const & segment) diff --git a/routing/transit_world_graph.hpp b/routing/transit_world_graph.hpp index 7283707fe5..53c2de722e 100644 --- a/routing/transit_world_graph.hpp +++ b/routing/transit_world_graph.hpp @@ -63,7 +63,9 @@ public: RouteWeight CalcSegmentWeight(Segment const & segment) override; RouteWeight CalcLeapWeight(m2::PointD const & from, m2::PointD const & to) const override; RouteWeight CalcOffroadWeight(m2::PointD const & from, m2::PointD const & to) const override; - double CalcSegmentETA(Segment const & segment) override; + double CalculateETA(Segment const & from, Segment const & to) override; + double CalculateETAWithoutPenalty(Segment const & segment) override; + std::unique_ptr GetTransitInfo(Segment const & segment) override; IndexGraph & GetIndexGraph(NumMwmId numMwmId) override diff --git a/routing/world_graph.hpp b/routing/world_graph.hpp index 9821ef8779..8897a9bc7a 100644 --- a/routing/world_graph.hpp +++ b/routing/world_graph.hpp @@ -79,7 +79,8 @@ public: virtual RouteWeight CalcOffroadWeight(m2::PointD const & from, m2::PointD const & to) const = 0; - virtual double CalcSegmentETA(Segment const & segment) = 0; + virtual double CalculateETA(Segment const & from, Segment const & to) = 0; + virtual double CalculateETAWithoutPenalty(Segment const & segment) = 0; /// \returns transitions for mwm with id |numMwmId|. virtual std::vector const & GetTransitions(NumMwmId numMwmId, bool isEnter);