| 39 | } |
| 40 | |
| 41 | void FixupCarTurns(vector<RouteSegment> & routeSegments) |
| 42 | { |
| 43 | double constexpr kMergeDistMeters = 15.0; |
| 44 | // For turns that are not EnterRoundAbout/ExitRoundAbout exitNum is always equal to zero. |
| 45 | // If a turn is EnterRoundAbout exitNum is a number of turns between two junctions: |
| 46 | // (1) the route enters to the roundabout; |
| 47 | // (2) the route leaves the roundabout; |
| 48 | uint32_t exitNum = 0; |
| 49 | size_t constexpr kInvalidEnter = numeric_limits<size_t>::max(); |
| 50 | size_t enterRoundAbout = kInvalidEnter; |
| 51 | |
| 52 | for (size_t idx = 0; idx < routeSegments.size(); ++idx) |
| 53 | { |
| 54 | auto & t = routeSegments[idx].GetTurn(); |
| 55 | if (t.IsTurnNone()) |
| 56 | continue; |
| 57 | |
| 58 | if (enterRoundAbout != kInvalidEnter && t.m_turn != CarDirection::StayOnRoundAbout && |
| 59 | t.m_turn != CarDirection::LeaveRoundAbout && t.m_turn != CarDirection::ReachedYourDestination) |
| 60 | { |
| 61 | ASSERT(false, |
| 62 | ("Only StayOnRoundAbout, LeaveRoundAbout or ReachedYourDestination are expected after EnterRoundAbout.")); |
| 63 | exitNum = 0; |
| 64 | enterRoundAbout = kInvalidEnter; |
| 65 | } |
| 66 | else if (t.m_turn == CarDirection::EnterRoundAbout) |
| 67 | { |
| 68 | ASSERT(enterRoundAbout == kInvalidEnter, |
| 69 | ("It's not expected to find new EnterRoundAbout until previous EnterRoundAbout was leaved.")); |
| 70 | enterRoundAbout = idx; |
| 71 | ASSERT(exitNum == 0, ("exitNum is reset at start and after LeaveRoundAbout.")); |
| 72 | exitNum = t.m_exitNum; // Normally it is 0, but sometimes it can be 1. |
| 73 | } |
| 74 | else if (t.m_turn == CarDirection::StayOnRoundAbout) |
| 75 | { |
| 76 | ++exitNum; |
| 77 | routeSegments[idx].ClearTurn(); |
| 78 | continue; |
| 79 | } |
| 80 | else if (t.m_turn == CarDirection::LeaveRoundAbout) |
| 81 | { |
| 82 | // It's possible for car to be on roundabout without entering it |
| 83 | // if route calculation started at roundabout (e.g. if user made full turn on roundabout). |
| 84 | if (enterRoundAbout != kInvalidEnter) |
| 85 | routeSegments[enterRoundAbout].SetTurnExits(exitNum + 1); |
| 86 | routeSegments[idx].SetTurnExits(exitNum + 1); // For LeaveRoundAbout turn. |
| 87 | enterRoundAbout = kInvalidEnter; |
| 88 | exitNum = 0; |
| 89 | } |
| 90 | |
| 91 | // Merging turns which are closed to each other under some circumstance. |
| 92 | // distance(turnsDir[idx - 1].m_index, turnsDir[idx].m_index) < kMergeDistMeters |
| 93 | // means the distance in meters between the former turn (idx - 1) |
| 94 | // and the current turn (idx). |
| 95 | if (idx > 0 && IsStayOnRoad(routeSegments[idx - 1].GetTurn().m_turn) && IsLeftOrRightTurn(t.m_turn)) |
| 96 | { |
| 97 | auto const & junction = routeSegments[idx].GetJunction(); |
| 98 | auto const & prevJunction = routeSegments[idx - 1].GetJunction(); |