diff --git a/indexer/ftypes_matcher.cpp b/indexer/ftypes_matcher.cpp index 1f7e14b65f..ebfe538e75 100644 --- a/indexer/ftypes_matcher.cpp +++ b/indexer/ftypes_matcher.cpp @@ -394,34 +394,16 @@ string DebugPrint(HighwayClass const cls) out << "[ "; switch (cls) { - case HighwayClass::Undefined: - out << "Undefined"; - break; - case HighwayClass::Error: - out << "Error"; - break; - case HighwayClass::Trunk: - out << "Trunk"; - break; - case HighwayClass::Primary: - out << "Primary"; - break; - case HighwayClass::Secondary: - out << "Secondary"; - break; - case HighwayClass::Tertiary: - out << "Tertiary"; - break; - case HighwayClass::LivingStreet: - out << "LivingStreet"; - break; - case HighwayClass::Service: - out << "Service"; - break; + case HighwayClass::Undefined: out << "Undefined"; break; + case HighwayClass::Error: out << "Error"; break; + case HighwayClass::Trunk: out << "Trunk"; break; + case HighwayClass::Primary: out << "Primary"; break; + case HighwayClass::Secondary: out << "Secondary"; break; + case HighwayClass::Tertiary: out << "Tertiary"; break; + case HighwayClass::LivingStreet: out << "LivingStreet"; break; + case HighwayClass::Service: out << "Service"; break; case HighwayClass::Pedestrian: out << "Pedestrian"; break; - case HighwayClass::Count: - out << "Count"; - break; + case HighwayClass::Count: out << "Count"; break; } out << " ]"; return out.str(); diff --git a/routing/bicycle_directions.cpp b/routing/bicycle_directions.cpp index 606128e7aa..ffdb95c67e 100644 --- a/routing/bicycle_directions.cpp +++ b/routing/bicycle_directions.cpp @@ -38,16 +38,10 @@ public: virtual void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint, m2::PointD const & junctionPoint, size_t & ingoingCount, - TTurnCandidates & outgoingTurns) const override + TurnCandidates & outgoingTurns) const override { ingoingCount = 0; - outgoingTurns.clear(); - - if (node >= m_routeEdges.size()) - { - ASSERT(false, (m_routeEdges.size())); - return; - } + outgoingTurns.candidates.clear(); auto adjacentEdges = m_adjacentEdges.find(node); if (adjacentEdges == m_adjacentEdges.cend()) @@ -57,7 +51,7 @@ public: } ingoingCount = adjacentEdges->second.m_ingoingTurnsCount; - outgoingTurns = adjacentEdges->second.m_outgoingTurns; + outgoingTurns.candidates = adjacentEdges->second.m_outgoingTurns.candidates; } virtual double GetPathLength() const override { return m_routeLength; } @@ -95,6 +89,34 @@ ftypes::HighwayClass GetHighwayClass(FeatureID const & featureId, Index const & ASSERT_NOT_EQUAL(highWayClass, ftypes::HighwayClass::Undefined, ()); return highWayClass; } + +void LoadPathGeometry(FeatureID const & featureId, Index const & index, + vector const & path, LoadedPathSegment & pathSegment) +{ + pathSegment.Clear(); + + MwmSet::MwmId const & mwmId = featureId.m_mwmId; + if (!featureId.IsValid()) + { + ASSERT(false, ()); + return; + } + + FeatureType ft; + Index::FeaturesLoaderGuard loader(index, mwmId); + loader.GetFeatureByIndex(featureId.m_index, ft); + pathSegment.m_highwayClass = ftypes::GetHighwayClass(ft); + ASSERT_NOT_EQUAL(pathSegment.m_highwayClass, ftypes::HighwayClass::Error, ()); + ASSERT_NOT_EQUAL(pathSegment.m_highwayClass, ftypes::HighwayClass::Undefined, ()); + pathSegment.m_isLink = ftypes::IsLinkChecker::Instance()(ft); + + ft.GetName(FeatureType::DEFAULT_LANG, pathSegment.m_name); + + pathSegment.m_nodeId = featureId.m_index; + pathSegment.m_onRoundabout = ftypes::IsRoundAboutChecker::Instance()(ft); + pathSegment.m_path = path; + // @TODO(bykoianko) It's better to fill pathSegment.m_weight. +} } // namespace namespace routing @@ -155,26 +177,30 @@ void BicycleDirectionsEngine::Generate(IRoadGraph const & graph, vector m_lanes; string m_name; TEdgeWeight m_weight; /*!< Time in seconds to pass the segment. */ - TNodeId m_nodeId; + TNodeId m_nodeId; /*!< May be NodeId for OSRM router or FeatureId::index for graph router. */ ftypes::HighwayClass m_highwayClass; bool m_onRoundabout; bool m_isLink; diff --git a/routing/osrm_router.cpp b/routing/osrm_router.cpp index ed57dc3a64..e1ca7e9ba2 100644 --- a/routing/osrm_router.cpp +++ b/routing/osrm_router.cpp @@ -67,7 +67,7 @@ public: virtual void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint, m2::PointD const & junctionPoint, size_t & ingoingCount, - turns::TTurnCandidates & outgoingTurns) const override + turns::TurnCandidates & outgoingTurns) const override { double const kReadCrossEpsilon = 1.0E-4; @@ -139,12 +139,13 @@ public: ASSERT_LESS(MercatorBounds::DistanceOnEarth(junctionPoint, ft.GetPoint(seg.m_pointStart)), turns::kFeaturesNearTurnMeters, ()); + outgoingTurns.isCandidatesAngleValid = true; double const a = my::RadToDeg(turns::PiMinusTwoVectorsAngle(junctionPoint, ingoingPoint, outgoingPoint)); - outgoingTurns.emplace_back(a, targetNode, ftypes::GetHighwayClass(ft)); + outgoingTurns.candidates.emplace_back(a, targetNode, ftypes::GetHighwayClass(ft)); } - sort(outgoingTurns.begin(), outgoingTurns.end(), + sort(outgoingTurns.candidates.begin(), outgoingTurns.candidates.end(), [](turns::TurnCandidate const & t1, turns::TurnCandidate const & t2) { return t1.angle < t2.angle; diff --git a/routing/routing_integration_tests/bicycle_turn_test.cpp b/routing/routing_integration_tests/bicycle_turn_test.cpp index a158231573..448a55d887 100644 --- a/routing/routing_integration_tests/bicycle_turn_test.cpp +++ b/routing/routing_integration_tests/bicycle_turn_test.cpp @@ -10,18 +10,47 @@ using namespace routing::turns; UNIT_TEST(RussiaMoscowSevTushinoParkBicycleWayTurnTest) { TRouteResult const routeResult = integration::CalculateRoute( - integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.87445, 37.43711), + integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.87467, 37.43658), {0.0, 0.0}, MercatorBounds::FromLatLon(55.8719, 37.4464)); Route const & route = *routeResult.first; IRouter::ResultCode const result = routeResult.second; TEST_EQUAL(result, IRouter::NoError, ()); - integration::TestTurnCount(route, 3); + integration::TestTurnCount(route, 1); - integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnRight); - integration::GetNthTurn(route, 1).TestValid().TestDirection(TurnDirection::TurnLeft); - integration::GetNthTurn(route, 2).TestValid().TestDirection(TurnDirection::TurnRight); + integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft); - integration::TestRouteLength(route, 711.); + integration::TestRouteLength(route, 752.); +} + +UNIT_TEST(RussiaMoscowGerPanfilovtsev22BicycleWayTurnTest) +{ + TRouteResult const routeResult = integration::CalculateRoute( + integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.85630, 37.41004), + {0.0, 0.0}, MercatorBounds::FromLatLon(55.85717, 37.41052)); + + Route const & route = *routeResult.first; + IRouter::ResultCode const result = routeResult.second; + TEST_EQUAL(result, IRouter::NoError, ()); + + integration::TestTurnCount(route, 2); + + integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnLeft); + integration::GetNthTurn(route, 1).TestValid().TestDirection(TurnDirection::TurnLeft); +} + +UNIT_TEST(RussiaMoscowSalameiNerisPossibleTurnCorrectionBicycleWayTurnTest) +{ + TRouteResult const routeResult = integration::CalculateRoute( + integration::GetBicycleComponents(), MercatorBounds::FromLatLon(55.85159, 37.38903), + {0.0, 0.0}, MercatorBounds::FromLatLon(55.85157, 37.38813)); + + Route const & route = *routeResult.first; + IRouter::ResultCode const result = routeResult.second; + TEST_EQUAL(result, IRouter::NoError, ()); + + integration::TestTurnCount(route, 1); + + integration::GetNthTurn(route, 0).TestValid().TestDirection(TurnDirection::TurnSlightRight); } diff --git a/routing/routing_result_graph.hpp b/routing/routing_result_graph.hpp index d3a9e24059..fe74b25702 100644 --- a/routing/routing_result_graph.hpp +++ b/routing/routing_result_graph.hpp @@ -23,7 +23,7 @@ public: virtual void GetPossibleTurns(TNodeId node, m2::PointD const & ingoingPoint, m2::PointD const & junctionPoint, size_t & ingoingCount, - TTurnCandidates & outgoingTurns) const = 0; + TurnCandidates & outgoingTurns) const = 0; virtual double GetPathLength() const = 0; virtual m2::PointD const & GetStartPoint() const = 0; virtual m2::PointD const & GetEndPoint() const = 0; diff --git a/routing/turn_candidate.hpp b/routing/turn_candidate.hpp index 9df250c490..07e13285b9 100644 --- a/routing/turn_candidate.hpp +++ b/routing/turn_candidate.hpp @@ -41,6 +41,13 @@ struct TurnCandidate } }; -using TTurnCandidates = vector; +struct TurnCandidates +{ + vector candidates; + bool isCandidatesAngleValid; + + TurnCandidates(bool angleValid = true) : isCandidatesAngleValid(angleValid) {} +}; + } // namespace routing } // namespace turns diff --git a/routing/turns_generator.cpp b/routing/turns_generator.cpp index c84c267be6..3bd9e443a0 100644 --- a/routing/turns_generator.cpp +++ b/routing/turns_generator.cpp @@ -32,18 +32,18 @@ double constexpr kNotSoCloseMinDistMeters = 30.; * - and the other possible turns lead to small roads; * - and the turn is GoStraight or TurnSlight*. */ -bool KeepTurnByHighwayClass(TurnDirection turn, TTurnCandidates const & possibleTurns, +bool KeepTurnByHighwayClass(TurnDirection turn, TurnCandidates const & possibleTurns, TurnInfo const & turnInfo) { if (!IsGoStraightOrSlightTurn(turn)) return true; // The road significantly changes its direction here. So this turn shall be kept. // There's only one exit from this junction. NodeID of the exit is outgoingNode. - if (possibleTurns.size() == 1) + if (possibleTurns.candidates.size() == 1) return true; ftypes::HighwayClass maxClassForPossibleTurns = ftypes::HighwayClass::Error; - for (auto const & t : possibleTurns) + for (auto const & t : possibleTurns.candidates) { if (t.node == turnInfo.m_outgoing.m_nodeId) continue; @@ -79,10 +79,10 @@ bool KeepTurnByHighwayClass(TurnDirection turn, TTurnCandidates const & possible /*! * \brief Returns false when other possible turns leads to service roads; */ -bool KeepRoundaboutTurnByHighwayClass(TurnDirection turn, TTurnCandidates const & possibleTurns, +bool KeepRoundaboutTurnByHighwayClass(TurnDirection turn, TurnCandidates const & possibleTurns, TurnInfo const & turnInfo) { - for (auto const & t : possibleTurns) + for (auto const & t : possibleTurns.candidates) { if (t.node == turnInfo.m_outgoing.m_nodeId) continue; @@ -593,26 +593,26 @@ void GetTurnDirection(IRoutingResult const & result, TurnInfo & turnInfo, TurnIt ASSERT_GREATER(turnInfo.m_ingoing.m_path.size(), 1, ()); m2::PointD const ingoingPointOneSegment = turnInfo.m_ingoing.m_path[turnInfo.m_ingoing.m_path.size() - 2]; - TTurnCandidates nodes; + TurnCandidates nodes; size_t ingoingCount; result.GetPossibleTurns(turnInfo.m_ingoing.m_nodeId, ingoingPointOneSegment, junctionPoint, ingoingCount, nodes); - size_t const numNodes = nodes.size(); + size_t const numNodes = nodes.candidates.size(); bool const hasMultiTurns = numNodes > 1; if (numNodes == 0) return; - if (!hasMultiTurns) + if (!hasMultiTurns || !nodes.isCandidatesAngleValid) { turn.m_turn = intermediateDirection; } else { - if (nodes.front().node == turnInfo.m_outgoing.m_nodeId) + if (nodes.candidates.front().node == turnInfo.m_outgoing.m_nodeId) turn.m_turn = LeftmostDirection(turnAngle); - else if (nodes.back().node == turnInfo.m_outgoing.m_nodeId) + else if (nodes.candidates.back().node == turnInfo.m_outgoing.m_nodeId) turn.m_turn = RightmostDirection(turnAngle); else turn.m_turn = intermediateDirection; @@ -640,7 +640,7 @@ void GetTurnDirection(IRoutingResult const & result, TurnInfo & turnInfo, TurnIt kNotSoCloseMinDistMeters, GetIngoingPointIndex); if (!KeepTurnByIngoingEdges(junctionPoint, notSoCloseToTheTurnPoint, outgoingPoint, hasMultiTurns, - nodes.size() + ingoingCount)) + nodes.candidates.size() + ingoingCount)) { turn.m_turn = TurnDirection::NoTurn; return;