diff --git a/routing/bicycle_directions.cpp b/routing/bicycle_directions.cpp index b6a583b683..97d6429094 100644 --- a/routing/bicycle_directions.cpp +++ b/routing/bicycle_directions.cpp @@ -368,8 +368,8 @@ void BicycleDirectionsEngine::FillPathSegmentsAndAdjacentEdgesMap( { auto const it = m_adjacentEdges.find(segmentRange); // A route may be built through intermediate points. So it may contain the same |segmentRange| - // several times. But in that case |adjacentEdges| corresponds to |segmentRange| - // should be the same as well except for one case. + // several times. But in that case |adjacentEdges| corresponding to |segmentRange| + // should be the same. ASSERT(it == m_adjacentEdges.cend() || it->second.IsAlmostEqual(adjacentEdges), ("segmentRange:", segmentRange, "corresponds to adjacent edges which aren't equal.")); diff --git a/routing/turns.cpp b/routing/turns.cpp index fe31c039ff..a969c3dfa8 100644 --- a/routing/turns.cpp +++ b/routing/turns.cpp @@ -120,13 +120,14 @@ bool SegmentRange::IsCorrect() const return (m_forward && m_startSegId <= m_endSegId) || (!m_forward && m_endSegId <= m_startSegId); } -Segment SegmentRange::GetFirstSegment(NumMwmIds const & numMwmIds) const +bool SegmentRange::GetFirstSegment(NumMwmIds const & numMwmIds, Segment & segment) const { if (!m_featureId.IsValid()) - return Segment(); + return false; - return Segment(numMwmIds.GetId(platform::CountryFile(m_featureId.GetMwmName())), - m_featureId.m_index, m_startSegId, m_forward); + segment = Segment(numMwmIds.GetId(platform::CountryFile(m_featureId.GetMwmName())), + m_featureId.m_index, m_startSegId, m_forward); + return true; } string DebugPrint(SegmentRange const & segmentRange) diff --git a/routing/turns.hpp b/routing/turns.hpp index a61b3e14dc..4d2415b46c 100644 --- a/routing/turns.hpp +++ b/routing/turns.hpp @@ -32,8 +32,9 @@ struct SegmentRange FeatureID const & GetFeature() const; /// \returns true if the instance of SegmentRange is correct. bool IsCorrect() const; - /// \returns First Segment of this SegmentRange. - Segment GetFirstSegment(NumMwmIds const & numMwmIds) const; + /// \brief Fills |segment| with the first segment of this SegmentRange. + /// \returns true if |segment| is filled and false otherwise. + bool GetFirstSegment(NumMwmIds const & numMwmIds, Segment & segment) const; private: FeatureID m_featureId; diff --git a/routing/turns_generator.cpp b/routing/turns_generator.cpp index ac01a1a407..acda31dcd6 100644 --- a/routing/turns_generator.cpp +++ b/routing/turns_generator.cpp @@ -32,6 +32,7 @@ double constexpr kNotSoCloseMinDistMeters = 30.; * - the route leads from one big road to another one; * - and the other possible turns lead to small roads; * - and the turn is GoStraight or TurnSlight*. + * Returns true otherwise. */ bool KeepTurnByHighwayClass(CarDirection turn, TurnCandidates const & possibleTurns, TurnInfo const & turnInfo, NumMwmIds const & numMwmIds) @@ -39,15 +40,22 @@ bool KeepTurnByHighwayClass(CarDirection turn, TurnCandidates const & possibleTu 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. This turn should be left. - // It may be kept later according to the result of the method KeepTurnByIngoingEdges(). + // There's only one exit from this junction. This turn should be kept here. + // That means the the decision to keep this turn or not is left for KeepTurnByIngoingEdges() + // method which should be called after this one. if (possibleTurns.candidates.size() == 1) return true; + // The turn should be kept if there's no any information about feature id of outgoing segment + // just to be on the safe side. It may happen in case of outgoing segment is a finish segment. + Segment firstOutgoingSegment; + if (!turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds, firstOutgoingSegment)) + return true; + ftypes::HighwayClass maxClassForPossibleTurns = ftypes::HighwayClass::Error; for (auto const & t : possibleTurns.candidates) { - if (t.m_segment == turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds)) + if (t.m_segment == firstOutgoingSegment) continue; ftypes::HighwayClass const highwayClass = t.highwayClass; if (static_cast(highwayClass) > static_cast(maxClassForPossibleTurns)) @@ -59,7 +67,7 @@ bool KeepTurnByHighwayClass(CarDirection turn, TurnCandidates const & possibleTu return true; } if (maxClassForPossibleTurns == ftypes::HighwayClass::Undefined) - return false; // Fake edges has HighwayClass::Undefined. + return false; // Fake edges have HighwayClass::Undefined. ftypes::HighwayClass const minClassForTheRoute = static_cast(min(static_cast(turnInfo.m_ingoing.m_highwayClass), @@ -71,7 +79,7 @@ bool KeepTurnByHighwayClass(CarDirection turn, TurnCandidates const & possibleTu return false; } if (minClassForTheRoute == ftypes::HighwayClass::Undefined) - return false; // Fake edges has HighwayClass::Undefined. + return false; // Fake edges have HighwayClass::Undefined. int const kMaxHighwayClassDiffToKeepTheTurn = 2; if (static_cast(maxClassForPossibleTurns) - static_cast(minClassForTheRoute) >= @@ -89,9 +97,13 @@ bool KeepTurnByHighwayClass(CarDirection turn, TurnCandidates const & possibleTu bool KeepRoundaboutTurnByHighwayClass(CarDirection turn, TurnCandidates const & possibleTurns, TurnInfo const & turnInfo, NumMwmIds const & numMwmIds) { + Segment firstOutgoingSegment; + bool const validFirstOutgoingSeg = + turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds, firstOutgoingSegment); + for (auto const & t : possibleTurns.candidates) { - if (t.m_segment == turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds)) + if (!validFirstOutgoingSeg || t.m_segment == firstOutgoingSegment) continue; if (static_cast(t.highwayClass) != static_cast(ftypes::HighwayClass::Service)) return true; @@ -598,12 +610,20 @@ void GetTurnDirection(IRoutingResult const & result, NumMwmIds const & numMwmIds } else { - if (nodes.candidates.front().m_segment == turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds)) - turn.m_turn = LeftmostDirection(turnAngle); - else if (nodes.candidates.back().m_segment == turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds)) - turn.m_turn = RightmostDirection(turnAngle); + Segment firstOutgoingSeg; + if (turnInfo.m_outgoing.m_segmentRange.GetFirstSegment(numMwmIds, firstOutgoingSeg)) + { + if (nodes.candidates.front().m_segment == firstOutgoingSeg) + turn.m_turn = LeftmostDirection(turnAngle); + else if (nodes.candidates.back().m_segment == firstOutgoingSeg) + turn.m_turn = RightmostDirection(turnAngle); + else + turn.m_turn = intermediateDirection; + } else + { turn.m_turn = intermediateDirection; + } } if (turnInfo.m_ingoing.m_onRoundabout || turnInfo.m_outgoing.m_onRoundabout)