From b73d8016d9676928c00677f0fd101811f640d091 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Fri, 2 Oct 2015 16:03:49 +0300 Subject: [PATCH 1/8] Adding GetNextTurns method to get two next turns. --- routing/route.cpp | 23 +++++++++++++++++++++-- routing/route.hpp | 3 ++- routing/routing_session.cpp | 6 +----- routing/turns.cpp | 9 +++++++++ routing/turns.hpp | 13 +++++++++++++ routing/turns_sound.cpp | 4 ++-- 6 files changed, 48 insertions(+), 10 deletions(-) diff --git a/routing/route.cpp b/routing/route.cpp index 4819a8d502..bcdb08f475 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -148,7 +148,9 @@ Route::TTurns::const_iterator Route::GetCurrentTurn() const }); } -void Route::GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const +// @TODO After current GPS possition passes the finish of the route the method GetCurrentTurn +// continues returning the last turn of the route. It looks like an issue. +bool Route::GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const { auto it = GetCurrentTurn(); if (it == m_turns.end()) @@ -156,13 +158,14 @@ void Route::GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn ASSERT(it != m_turns.end(), ()); distanceToTurnMeters = 0; turn = turns::TurnItem(); - return; + return false; } size_t const segIdx = (*it).m_index; turn = (*it); distanceToTurnMeters = m_poly.GetDistanceM(m_poly.GetCurrentIter(), m_poly.GetIterToIndex(segIdx)); + return true; } bool Route::GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const @@ -185,6 +188,22 @@ bool Route::GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) c return true; } +bool Route::GetNextTurns(vector & turns) +{ + turns.clear(); + + turns::TurnItemDist currentTurn; + if (!GetCurrentTurn(currentTurn.m_distMeters, currentTurn.m_turnItem)) + return false; + turns.push_back(move(currentTurn)); + + turns::TurnItemDist nextTurn; + if (!GetNextTurn(nextTurn.m_distMeters, nextTurn.m_turnItem)) + return false; + turns.push_back(move(nextTurn)); + return true; +} + void Route::GetCurrentDirectionPoint(m2::PointD & pt) const { if (m_routingSettings.m_keepPedestrianInfo && m_simplifiedPoly.IsValid()) diff --git a/routing/route.hpp b/routing/route.hpp index e323f8b2cc..148929aa2a 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -72,12 +72,13 @@ public: double GetCurrentDistanceToEndMeters() const; double GetMercatorDistanceFromBegin() const; - void GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const; + bool GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const; /// @return true if GetNextTurn() returns a valid result in parameters, false otherwise. /// \param distanceToTurnMeters is a distance from current possition to the second turn. /// \param turn is information about the second turn. /// \note All parameters are filled while a GetNextTurn function call. bool GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const; + bool GetNextTurns(vector & turns); void GetCurrentDirectionPoint(m2::PointD & pt) const; diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index c1fb2827b8..867bfe0ca1 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -23,10 +23,6 @@ double constexpr kShowLanesDistInMeters = 500.; // The distance before the next turn in meters when notification // about the turn after the next one will be shown if available. double constexpr kShowTheTurnAfterTheNextM = 500.; -// If the distance between two sequential turns is more than kMaxTurnDistM -// the information about the second turn will be shown when the user is -// approaching to the first one. -double constexpr kMaxTurnDistM = 400.; // @todo(kshalnev) The distance may depend on the current speed. double constexpr kShowPedestrianTurnInMeters = 5.; @@ -222,7 +218,7 @@ void RoutingSession::GetRouteFollowingInfo(FollowingInfo & info) const ASSERT_LESS_OR_EQUAL(0, distBetweenTurnsM, ()); if (m_routingSettings.m_showTurnAfterNext && - distanceToTurnMeters < kShowTheTurnAfterTheNextM && distBetweenTurnsM < kMaxTurnDistM) + distanceToTurnMeters < kShowTheTurnAfterTheNextM && distBetweenTurnsM < turns::kMaxTurnDistM) { info.m_nextTurn = nextTurn.m_turn; } diff --git a/routing/turns.cpp b/routing/turns.cpp index 41761b7281..24f606f51d 100644 --- a/routing/turns.cpp +++ b/routing/turns.cpp @@ -70,6 +70,15 @@ string DebugPrint(TurnItem const & turnItem) return out.str(); } +string DebugPrint(TurnItemDist const & turnItemDist) +{ + stringstream out; + out << "TurnItemDist [ m_turnItem = " << DebugPrint(turnItemDist.m_turnItem) + << ", m_distMeters = " << turnItemDist.m_distMeters + << " ]" << endl; + return out.str(); +} + string const GetTurnString(TurnDirection turn) { for (auto const & p : g_turnNames) diff --git a/routing/turns.hpp b/routing/turns.hpp index f842303fac..a91a2123b6 100644 --- a/routing/turns.hpp +++ b/routing/turns.hpp @@ -16,6 +16,11 @@ namespace turns /// @todo(vbykoianko) It's a good idea to gather all the turns information into one entity. /// For the time being several separate entities reflect the turn information. Like Route::TTurns +// If the distance between two sequential turns is more than kMaxTurnDistM +// the information about the second turn will be shown or pronounced when the user is +// approaching to the first one. +double constexpr kMaxTurnDistM = 400.; + /*! * \warning The order of values below shall not be changed. * TurnRight(TurnLeft) must have a minimal value and @@ -152,6 +157,14 @@ struct TurnItem string DebugPrint(TurnItem const & turnItem); +struct TurnItemDist +{ + TurnItem m_turnItem; + double m_distMeters; +}; + +string DebugPrint(TurnItemDist const & turnItemDist); + string const GetTurnString(TurnDirection turn); bool IsLeftTurn(TurnDirection t); diff --git a/routing/turns_sound.cpp b/routing/turns_sound.cpp index 378b466f9e..71296b3738 100644 --- a/routing/turns_sound.cpp +++ b/routing/turns_sound.cpp @@ -1,4 +1,4 @@ -#include "routing/turns_sound.hpp" + #include "routing/turns_sound.hpp" #include "platform/location.hpp" @@ -77,7 +77,7 @@ void TurnsSound::GenerateTurnSound(TurnItem const & turn, double distanceToTurnM uint32_t const distToPronounce = m_settings.RoundByPresetSoundedDistancesUnits(turnNotificationDistUnits); string const text = GenerateTurnText(distToPronounce, turn.m_exitNum, false, turn.m_turn, - m_settings.GetLengthUnits()); + m_settings.GetLengthUnits()); if (!text.empty()) turnNotifications.emplace_back(text); // @TODO(vbykoianko) Check if there's a turn immediately after the current turn. From bb2e22f0e2b307405684b39b5cf445c033283dcf Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Fri, 2 Oct 2015 16:04:36 +0300 Subject: [PATCH 2/8] Testing GetNextTurns method. --- routing/routing_tests/route_tests.cpp | 50 +++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/routing/routing_tests/route_tests.cpp b/routing/routing_tests/route_tests.cpp index 20763bf9d0..8763368354 100644 --- a/routing/routing_tests/route_tests.cpp +++ b/routing/routing_tests/route_tests.cpp @@ -107,3 +107,53 @@ UNIT_TEST(NextTurnTest) TEST_EQUAL(turn, kTestTurns[2], ()); TEST_EQUAL(nextTurn, turns::TurnItem(), ()); } + +UNIT_TEST(NextTurnsTest) +{ + Route route("TestRouter"); + route.SetGeometry(kTestGeometry.begin(), kTestGeometry.end()); + vector turns(kTestTurns); + route.SetTurnInstructions(turns); + vector turnsDist; + + { + TEST(route.GetNextTurns(turnsDist), ()); + TEST_EQUAL(turnsDist.size(), 2, ()); + double const firstSegLenM = MercatorBounds::DistanceOnEarth(kTestGeometry[0], kTestGeometry[1]); + double const secondSegLenM = MercatorBounds::DistanceOnEarth(kTestGeometry[1], kTestGeometry[2]); + TEST(my::AlmostEqualAbs(turnsDist[0].m_distMeters, firstSegLenM, 0.1), ()); + TEST(my::AlmostEqualAbs(turnsDist[1].m_distMeters, firstSegLenM + secondSegLenM, 0.1), ()); + TEST_EQUAL(turnsDist[0].m_turnItem, kTestTurns[0], ()); + TEST_EQUAL(turnsDist[1].m_turnItem, kTestTurns[1], ()); + } + { + double const x = 0.; + double const y = 0.5; + route.MoveIterator(GetGps(x, y)); + TEST(route.GetNextTurns(turnsDist), ()); + TEST_EQUAL(turnsDist.size(), 2, ()); + double const firstSegLenM = MercatorBounds::DistanceOnEarth({x, y}, kTestGeometry[1]); + double const secondSegLenM = MercatorBounds::DistanceOnEarth(kTestGeometry[1], kTestGeometry[2]); + TEST(my::AlmostEqualAbs(turnsDist[0].m_distMeters, firstSegLenM, 0.1), ()); + TEST(my::AlmostEqualAbs(turnsDist[1].m_distMeters, firstSegLenM + secondSegLenM, 0.1), ()); + TEST_EQUAL(turnsDist[0].m_turnItem, kTestTurns[0], ()); + TEST_EQUAL(turnsDist[1].m_turnItem, kTestTurns[1], ()); + } + { + double const x = 1.; + double const y = 2.5; + route.MoveIterator(GetGps(x, y)); + TEST(!route.GetNextTurns(turnsDist), ()); + TEST_EQUAL(turnsDist.size(), 1, ()); + double const firstSegLenM = MercatorBounds::DistanceOnEarth({x, y}, kTestGeometry[4]); + TEST(my::AlmostEqualAbs(turnsDist[0].m_distMeters, firstSegLenM, 0.1), ()); + TEST_EQUAL(turnsDist[0].m_turnItem, kTestTurns[2], ()); + } + { + double const x = 1.; + double const y = 3.5; + route.MoveIterator(GetGps(x, y)); + TEST(!route.GetNextTurns(turnsDist), ()); + TEST_EQUAL(turnsDist.size(), 1, ()); + } +} From 96e90d3e657335b74c16c069b91da16b90daafe3 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Mon, 5 Oct 2015 13:51:01 +0300 Subject: [PATCH 3/8] GetNextTurns returns true if at least the first next turn is valid. --- routing/route.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/routing/route.cpp b/routing/route.cpp index bcdb08f475..5f2fe8d275 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -199,7 +199,7 @@ bool Route::GetNextTurns(vector & turns) turns::TurnItemDist nextTurn; if (!GetNextTurn(nextTurn.m_distMeters, nextTurn.m_turnItem)) - return false; + return true; turns.push_back(move(nextTurn)); return true; } From 124a03769f457b2da93d381b112aacc22384469c Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Mon, 5 Oct 2015 13:52:57 +0300 Subject: [PATCH 4/8] Fixing unit test after the behaviour of GetNextTurns was changed. --- routing/routing_tests/route_tests.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/routing/routing_tests/route_tests.cpp b/routing/routing_tests/route_tests.cpp index 8763368354..fd65001cbe 100644 --- a/routing/routing_tests/route_tests.cpp +++ b/routing/routing_tests/route_tests.cpp @@ -143,7 +143,7 @@ UNIT_TEST(NextTurnsTest) double const x = 1.; double const y = 2.5; route.MoveIterator(GetGps(x, y)); - TEST(!route.GetNextTurns(turnsDist), ()); + TEST(route.GetNextTurns(turnsDist), ()); TEST_EQUAL(turnsDist.size(), 1, ()); double const firstSegLenM = MercatorBounds::DistanceOnEarth({x, y}, kTestGeometry[4]); TEST(my::AlmostEqualAbs(turnsDist[0].m_distMeters, firstSegLenM, 0.1), ()); @@ -153,7 +153,7 @@ UNIT_TEST(NextTurnsTest) double const x = 1.; double const y = 3.5; route.MoveIterator(GetGps(x, y)); - TEST(!route.GetNextTurns(turnsDist), ()); + TEST(route.GetNextTurns(turnsDist), ()); TEST_EQUAL(turnsDist.size(), 1, ()); } } From 27a2e94b794f5f03ce24fc7dc81b2810c699c96a Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Mon, 5 Oct 2015 14:31:45 +0300 Subject: [PATCH 5/8] Implementaion turn notification with word Then in some cases. --- routing/routing_session.cpp | 8 +++---- routing/turns_sound.cpp | 48 +++++++++++++++++++++++++++---------- routing/turns_sound.hpp | 4 ++-- routing/turns_tts_text.cpp | 9 ++++--- 4 files changed, 46 insertions(+), 23 deletions(-) diff --git a/routing/routing_session.cpp b/routing/routing_session.cpp index 867bfe0ca1..eff898c433 100644 --- a/routing/routing_session.cpp +++ b/routing/routing_session.cpp @@ -282,11 +282,9 @@ void RoutingSession::GenerateTurnSound(vector & turnNotifications) if (!m_route.IsValid() || !IsNavigable()) return; - double distanceToTurnMeters = 0.; - turns::TurnItem turn; - m_route.GetCurrentTurn(distanceToTurnMeters, turn); - - m_turnsSound.GenerateTurnSound(turn, distanceToTurnMeters, turnNotifications); + vector turns; + if (m_route.GetNextTurns(turns)) + m_turnsSound.GenerateTurnSound(turns, turnNotifications); } void RoutingSession::AssignRoute(Route & route, IRouter::ResultCode e) diff --git a/routing/turns_sound.cpp b/routing/turns_sound.cpp index 71296b3738..88edea9ca5 100644 --- a/routing/turns_sound.cpp +++ b/routing/turns_sound.cpp @@ -44,14 +44,40 @@ string TurnsSound::GenerateTurnText(uint32_t distanceUnits, uint8_t exitNum, boo return m_getTtsText(notification); } -void TurnsSound::GenerateTurnSound(TurnItem const & turn, double distanceToTurnMeters, - vector & turnNotifications) +void TurnsSound::GenerateTurnSound(vector const & turns, vector & turnNotifications) { turnNotifications.clear(); - if (!m_enabled) + const size_t turnsSz = turns.size(); + if (!m_enabled || turnsSz == 0) return; + TurnItemDist const & firstTurn = turns.front(); + string const firstNotification = GenerateFirstTurnSound(firstTurn.m_turnItem, firstTurn.m_distMeters); + if (m_nextTurnNotificationProgress == PronouncedNotification::Nothing) + return; + if (firstNotification.empty()) + return; + turnNotifications.push_back(move(firstNotification)); + + // Generating notifications like Then turn left if necessary. + if (turnsSz <= 1) + return; + TurnItemDist const & secondTurn = turns[1]; + ASSERT_LESS_OR_EQUAL(firstTurn.m_distMeters, secondTurn.m_distMeters, ()); + if (secondTurn.m_distMeters - firstTurn.m_distMeters > kMaxTurnDistM) + return; + string const secondNotification = GenerateTurnText(0 /*distanceUnits is not used because of then is used*/, + secondTurn.m_turnItem.m_exitNum, true, + secondTurn.m_turnItem.m_turn, + m_settings.GetLengthUnits()); + if (secondNotification.empty()) + return; + turnNotifications.push_back(move(secondNotification)); +} + +string TurnsSound::GenerateFirstTurnSound(TurnItem const & turn, double distanceToTurnMeters) +{ if (m_nextTurnIndex != turn.m_index) { m_nextTurnNotificationProgress = PronouncedNotification::Nothing; @@ -76,13 +102,12 @@ void TurnsSound::GenerateTurnSound(TurnItem const & turn, double distanceToTurnM // First turn sound notification. uint32_t const distToPronounce = m_settings.RoundByPresetSoundedDistancesUnits(turnNotificationDistUnits); - string const text = GenerateTurnText(distToPronounce, turn.m_exitNum, false, turn.m_turn, - m_settings.GetLengthUnits()); - if (!text.empty()) - turnNotifications.emplace_back(text); + // @TODO(vbykoianko) Check if there's a turn immediately after the current turn. // If so add an extra item to turnNotifications with "then parameter". m_nextTurnNotificationProgress = PronouncedNotification::First; + return GenerateTurnText(distToPronounce, turn.m_exitNum, false, turn.m_turn, + m_settings.GetLengthUnits()); } } else @@ -91,21 +116,18 @@ void TurnsSound::GenerateTurnSound(TurnItem const & turn, double distanceToTurnM // It happens if one turn follows shortly behind another one. m_nextTurnNotificationProgress = PronouncedNotification::First; } - return; + return ""; } if (m_nextTurnNotificationProgress == PronouncedNotification::First && distanceToTurnMeters < distanceToPronounceNotificationMeters) { - string const text = GenerateTurnText(0, turn.m_exitNum, false, turn.m_turn, - m_settings.GetLengthUnits()); - if (!text.empty()) - turnNotifications.emplace_back(text); - // @TODO(vbykoianko) Check if there's a turn immediately after the current turn. // If so add an extra item to info.turnNotifications with "then parameter". m_nextTurnNotificationProgress = PronouncedNotification::Second; + return GenerateTurnText(0, turn.m_exitNum, false, turn.m_turn, m_settings.GetLengthUnits()); } + return ""; } void TurnsSound::Enable(bool enable) diff --git a/routing/turns_sound.hpp b/routing/turns_sound.hpp index 27f50bc04d..e6e0eae191 100644 --- a/routing/turns_sound.hpp +++ b/routing/turns_sound.hpp @@ -63,6 +63,7 @@ class TurnsSound string GenerateTurnText(uint32_t distanceUnits, uint8_t exitNum, bool useThenInsteadOfDistance, TurnDirection turnDir, LengthUnits lengthUnits) const; + string GenerateFirstTurnSound(TurnItem const & turn, double distanceToTurnMeters); public: TurnsSound() : m_enabled(false), m_speedMetersPerSecond(0.), m_settings(), m_nextTurnNotificationProgress(PronouncedNotification::Nothing), m_nextTurnIndex(0) {} @@ -83,8 +84,7 @@ public: /// \param distanceToTurnMeters is distance to the next turn in meters. /// \param turnNotifications is a parameter to fill it if it's necessary. /// \note The client implies turnNotifications does not contain empty strings. - void GenerateTurnSound(TurnItem const & turn, double distanceToTurnMeters, - vector & turnNotifications); + void GenerateTurnSound(vector const & turns, vector & turnNotifications); /// Reset states which reflects current route position. /// The method shall be called after creating a new route or after rerouting. void Reset(); diff --git a/routing/turns_tts_text.cpp b/routing/turns_tts_text.cpp index 3c43db3441..7d8aec4197 100644 --- a/routing/turns_tts_text.cpp +++ b/routing/turns_tts_text.cpp @@ -50,11 +50,14 @@ string GetTtsText::operator()(Notification const & notification) const { if (notification.m_distanceUnits == 0 && !notification.m_useThenInsteadOfDistance) return GetTextById(GetDirectionTextId(notification)); + if (notification.m_useThenInsteadOfDistance && notification.m_turnDir == TurnDirection::NoTurn) + return ""; + + string const dirStr = GetTextById(GetDirectionTextId(notification)); + if (dirStr.empty()) + return ""; string const distStr = GetTextById(GetDistanceTextId(notification)); - string const dirStr = GetTextById(GetDirectionTextId(notification)); - if (distStr.empty() && dirStr.empty()) - return ""; return distStr + " " + dirStr; } From 93d8c30483de7ab31fe59e93b2e5e26f4b98c2f1 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Mon, 5 Oct 2015 14:33:38 +0300 Subject: [PATCH 6/8] Fixing unit tests. --- routing/routing_tests/turns_sound_test.cpp | 101 ++++++++++++--------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/routing/routing_tests/turns_sound_test.cpp b/routing/routing_tests/turns_sound_test.cpp index feece5f9d6..5fbdc26cc2 100644 --- a/routing/routing_tests/turns_sound_test.cpp +++ b/routing/routing_tests/turns_sound_test.cpp @@ -107,18 +107,17 @@ UNIT_TEST(TurnsSoundMetersTest) turnSound.Reset(); turnSound.SetSpeedMetersPerSecond(30.); - TurnItem turnItem(5 /* idx */, TurnDirection::TurnRight); + vector turns = {{{5 /* idx */, TurnDirection::TurnRight}, 1000.}}; vector turnNotifications; - ASSERT(turnNotifications.empty(), ()); - // Starting nearing the turnItem. // 1000 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 1000. /* distanceToTurnMeters */, turnNotifications); + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 700 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 700. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 700.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 699 meters till the turn. It's time to pronounce the first voice notification. @@ -127,42 +126,47 @@ UNIT_TEST(TurnsSoundMetersTest) // Besides that we need 5 seconds (but 100 meters maximum) for playing the notification. // So we start playing the first notification when the distance till the turn is less // then 20 seconds * 30 meters per seconds + 100 meters = 700 meters. - turnSound.GenerateTurnSound(turnItem, 699. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 699.; + turnSound.GenerateTurnSound(turns, turnNotifications); vector const expectedNotification1 = {{"In 600 meters. Make a right turn."}}; TEST_EQUAL(turnNotifications, expectedNotification1, ()); // 650 meters till the turn. No sound notifications is required. - turnNotifications.clear(); - turnSound.GenerateTurnSound(turnItem, 650. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 650.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); turnSound.SetSpeedMetersPerSecond(32.); // 150 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 150. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 150.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 100 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 100. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 100.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 99 meters till the turn. It's time to pronounce the second voice notification. - turnSound.GenerateTurnSound(turnItem, 99. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 99.; + turnSound.GenerateTurnSound(turns, turnNotifications); vector const expectedNotification2 = {{"Make a right turn."}}; TEST_EQUAL(turnNotifications, expectedNotification2, ()); // 99 meters till the turn again. No sound notifications is required. - turnNotifications.clear(); - turnSound.GenerateTurnSound(turnItem, 99. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 99.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 50 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 50. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 50.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 0 meters till the turn. No sound notifications is required. - turnNotifications.clear(); - turnSound.GenerateTurnSound(turnItem, 0. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 0.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); TEST(turnSound.IsEnabled(), ()); @@ -190,47 +194,52 @@ UNIT_TEST(TurnsSoundMetersTwoTurnsTest) turnSound.Reset(); turnSound.SetSpeedMetersPerSecond(35.); - TurnItem turnItem1(5 /* idx */, TurnDirection::TurnSharpRight); + //TurnItem turnItem1(5 /* idx */, TurnDirection::TurnSharpRight); + vector turns = {{{5 /* idx */, TurnDirection::TurnSharpRight}, 800.}}; vector turnNotifications; - ASSERT(turnNotifications.empty(), ()); - // Starting nearing the first turn. // 800 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem1, 800. /* distanceToTurnMeters */, turnNotifications); + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 700 meters till the turn. It's time to pronounce the first voice notification. - turnSound.GenerateTurnSound(turnItem1, 700. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 700.; + turnSound.GenerateTurnSound(turns, turnNotifications); vector const expectedNotification1 = {{"In 700 meters. Make a sharp right turn."}}; TEST_EQUAL(turnNotifications, expectedNotification1, ()); turnSound.SetSpeedMetersPerSecond(32.); // 150 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem1, 150. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 150.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 99 meters till the turn. It's time to pronounce the second voice notification. - turnSound.GenerateTurnSound(turnItem1, 99. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 99.; + turnSound.GenerateTurnSound(turns, turnNotifications); vector const expectedNotification2 = {{"Make a sharp right turn."}}; TEST_EQUAL(turnNotifications, expectedNotification2, ()); turnSound.SetSpeedMetersPerSecond(10.); // 0 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem1, 0. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 0.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); - TurnItem turnItem2(11 /* idx */, TurnDirection::EnterRoundAbout, 2 /* exitNum */); + vector turns2 = {{{11 /* idx */, TurnDirection::EnterRoundAbout, + 2 /* exitNum */}, 60.}}; // Starting nearing the second turn. - turnSound.GenerateTurnSound(turnItem2, 60. /* distanceToTurnMeters */, turnNotifications); + turnSound.GenerateTurnSound(turns2, turnNotifications); TEST(turnNotifications.empty(), ()); // 40 meters till the second turn. It's time to pronounce the second voice notification // without the first one. - turnSound.GenerateTurnSound(turnItem2, 40. /* distanceToTurnMeters */, turnNotifications); + turns2.front().m_distMeters = 40.; + turnSound.GenerateTurnSound(turns2, turnNotifications); vector const expectedNotification3 = {{"Enter the roundabout."}}; TEST_EQUAL(turnNotifications, expectedNotification3, ()); @@ -254,18 +263,18 @@ UNIT_TEST(TurnsSoundFeetTest) turnSound.Reset(); turnSound.SetSpeedMetersPerSecond(30.); - TurnItem turnItem(7 /* idx */, TurnDirection::EnterRoundAbout, 3 /* exitNum */); + vector turns = {{{7 /* idx */, TurnDirection::EnterRoundAbout, + 3 /* exitNum */}, 1000.}}; vector turnNotifications; - ASSERT(turnNotifications.empty(), ()); - // Starting nearing the turnItem. // 1000 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 1000. /* distanceToTurnMeters */, turnNotifications); + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 700 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 700. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 700.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 699 meters till the turn. It's time to pronounce the first voice notification. @@ -274,41 +283,45 @@ UNIT_TEST(TurnsSoundFeetTest) // Besides that we need 5 seconds (but 100 meters maximum) for playing the notification. // So we start playing the first notification when the distance till the turn is less // then 20 seconds * 30 meters per seconds + 100 meters = 700 meters. - turnSound.GenerateTurnSound(turnItem, 699. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 699.; + turnSound.GenerateTurnSound(turns, turnNotifications); vector const expectedNotification1 = {{"In 2000 feet. Enter the roundabout."}}; TEST_EQUAL(turnNotifications, expectedNotification1, ()); // 650 meters till the turn. No sound notifications is required. - turnNotifications.clear(); - turnSound.GenerateTurnSound(turnItem, 650. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 650.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 150 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 150. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 150.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 100 meters till the turn. No sound notifications is required. - turnSound.GenerateTurnSound(turnItem, 100. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 100.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 99 meters till the turn. It's time to pronounce the second voice notification. - turnSound.GenerateTurnSound(turnItem, 99. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 99.; + turnSound.GenerateTurnSound(turns, turnNotifications); vector const expectedNotification2 = {{"Enter the roundabout."}}; TEST_EQUAL(turnNotifications, expectedNotification2, ()); // 99 meters till the turn again. No sound notifications is required. - turnNotifications.clear(); - turnSound.GenerateTurnSound(turnItem, 99. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 99.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 50 meters till the turn. No sound notifications is required. - turnNotifications.clear(); - turnSound.GenerateTurnSound(turnItem, 50. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 50.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); // 0 meters till the turn. No sound notifications is required. - turnNotifications.clear(); - turnSound.GenerateTurnSound(turnItem, 0. /* distanceToTurnMeters */, turnNotifications); + turns.front().m_distMeters = 0.; + turnSound.GenerateTurnSound(turns, turnNotifications); TEST(turnNotifications.empty(), ()); TEST(turnSound.IsEnabled(), ()); From e782b810259fb0f8fb0aca01f0b3afb446a0a695 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Mon, 5 Oct 2015 15:09:17 +0300 Subject: [PATCH 7/8] Cleaning up the code in the PR. --- routing/routing_tests/turns_sound_test.cpp | 1 - routing/turns_sound.cpp | 9 ++------- 2 files changed, 2 insertions(+), 8 deletions(-) diff --git a/routing/routing_tests/turns_sound_test.cpp b/routing/routing_tests/turns_sound_test.cpp index 5fbdc26cc2..3ad98fb75c 100644 --- a/routing/routing_tests/turns_sound_test.cpp +++ b/routing/routing_tests/turns_sound_test.cpp @@ -194,7 +194,6 @@ UNIT_TEST(TurnsSoundMetersTwoTurnsTest) turnSound.Reset(); turnSound.SetSpeedMetersPerSecond(35.); - //TurnItem turnItem1(5 /* idx */, TurnDirection::TurnSharpRight); vector turns = {{{5 /* idx */, TurnDirection::TurnSharpRight}, 800.}}; vector turnNotifications; diff --git a/routing/turns_sound.cpp b/routing/turns_sound.cpp index 88edea9ca5..96354456ac 100644 --- a/routing/turns_sound.cpp +++ b/routing/turns_sound.cpp @@ -1,4 +1,4 @@ - #include "routing/turns_sound.hpp" +#include "routing/turns_sound.hpp" #include "platform/location.hpp" @@ -67,7 +67,7 @@ void TurnsSound::GenerateTurnSound(vector const & turns, vector kMaxTurnDistM) return; - string const secondNotification = GenerateTurnText(0 /*distanceUnits is not used because of then is used*/, + string const secondNotification = GenerateTurnText(0 /* distanceUnits is not used because of "Then" is used */, secondTurn.m_turnItem.m_exitNum, true, secondTurn.m_turnItem.m_turn, m_settings.GetLengthUnits()); @@ -102,9 +102,6 @@ string TurnsSound::GenerateFirstTurnSound(TurnItem const & turn, double distance // First turn sound notification. uint32_t const distToPronounce = m_settings.RoundByPresetSoundedDistancesUnits(turnNotificationDistUnits); - - // @TODO(vbykoianko) Check if there's a turn immediately after the current turn. - // If so add an extra item to turnNotifications with "then parameter". m_nextTurnNotificationProgress = PronouncedNotification::First; return GenerateTurnText(distToPronounce, turn.m_exitNum, false, turn.m_turn, m_settings.GetLengthUnits()); @@ -122,8 +119,6 @@ string TurnsSound::GenerateFirstTurnSound(TurnItem const & turn, double distance if (m_nextTurnNotificationProgress == PronouncedNotification::First && distanceToTurnMeters < distanceToPronounceNotificationMeters) { - // @TODO(vbykoianko) Check if there's a turn immediately after the current turn. - // If so add an extra item to info.turnNotifications with "then parameter". m_nextTurnNotificationProgress = PronouncedNotification::Second; return GenerateTurnText(0, turn.m_exitNum, false, turn.m_turn, m_settings.GetLengthUnits()); } From 99871099c366e6668697c3379d366910c9031389 Mon Sep 17 00:00:00 2001 From: Vladimir Byko-Ianko Date: Mon, 5 Oct 2015 17:21:30 +0300 Subject: [PATCH 8/8] Corrections after colleagues comments. --- routing/route.cpp | 13 ++++++------- routing/route.hpp | 10 ++++++++-- routing/turns.cpp | 10 +++++----- routing/turns_sound.cpp | 33 +++++++++++++++++---------------- routing/turns_sound.hpp | 1 + routing/turns_tts_text.cpp | 16 ++++++++-------- 6 files changed, 45 insertions(+), 38 deletions(-) diff --git a/routing/route.cpp b/routing/route.cpp index 5f2fe8d275..f6fa503798 100644 --- a/routing/route.cpp +++ b/routing/route.cpp @@ -148,8 +148,8 @@ Route::TTurns::const_iterator Route::GetCurrentTurn() const }); } -// @TODO After current GPS possition passes the finish of the route the method GetCurrentTurn -// continues returning the last turn of the route. It looks like an issue. +// @TODO After current GPS position passes the finish of the route the method GetCurrentTurn +// continues to return the last turn of the route. It looks like an issue. bool Route::GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const { auto it = GetCurrentTurn(); @@ -188,19 +188,18 @@ bool Route::GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) c return true; } -bool Route::GetNextTurns(vector & turns) +bool Route::GetNextTurns(vector & turns) const { turns.clear(); turns::TurnItemDist currentTurn; if (!GetCurrentTurn(currentTurn.m_distMeters, currentTurn.m_turnItem)) return false; - turns.push_back(move(currentTurn)); + turns.emplace_back(move(currentTurn)); turns::TurnItemDist nextTurn; - if (!GetNextTurn(nextTurn.m_distMeters, nextTurn.m_turnItem)) - return true; - turns.push_back(move(nextTurn)); + if (GetNextTurn(nextTurn.m_distMeters, nextTurn.m_turnItem)) + turns.emplace_back(move(nextTurn)); return true; } diff --git a/routing/route.hpp b/routing/route.hpp index 148929aa2a..e2347f6ebe 100644 --- a/routing/route.hpp +++ b/routing/route.hpp @@ -72,13 +72,19 @@ public: double GetCurrentDistanceToEndMeters() const; double GetMercatorDistanceFromBegin() const; + /// \brief GetCurrentTurn returns information about the nearest turn. + /// \param distanceToTurnMeters is a distance from current position to the nearest turn. + /// \param turn is information about the nearest turn. bool GetCurrentTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const; /// @return true if GetNextTurn() returns a valid result in parameters, false otherwise. - /// \param distanceToTurnMeters is a distance from current possition to the second turn. + /// \param distanceToTurnMeters is a distance from current position to the second turn. /// \param turn is information about the second turn. + /// @return true if its parameters are filled with correct result. /// \note All parameters are filled while a GetNextTurn function call. bool GetNextTurn(double & distanceToTurnMeters, turns::TurnItem & turn) const; - bool GetNextTurns(vector & turns); + /// \brief Extract information about zero, one or two nearest turns depending on current position. + /// @return true if its parameter is filled with correct result. (At least with one element.) + bool GetNextTurns(vector & turns) const; void GetCurrentDirectionPoint(m2::PointD & pt) const; diff --git a/routing/turns.cpp b/routing/turns.cpp index 24f606f51d..98da2a61a0 100644 --- a/routing/turns.cpp +++ b/routing/turns.cpp @@ -72,11 +72,11 @@ string DebugPrint(TurnItem const & turnItem) string DebugPrint(TurnItemDist const & turnItemDist) { - stringstream out; - out << "TurnItemDist [ m_turnItem = " << DebugPrint(turnItemDist.m_turnItem) - << ", m_distMeters = " << turnItemDist.m_distMeters - << " ]" << endl; - return out.str(); + stringstream out; + out << "TurnItemDist [ m_turnItem = " << DebugPrint(turnItemDist.m_turnItem) + << ", m_distMeters = " << turnItemDist.m_distMeters + << " ]" << endl; + return out.str(); } string const GetTurnString(TurnDirection turn) diff --git a/routing/turns_sound.cpp b/routing/turns_sound.cpp index 96354456ac..ff7c521190 100644 --- a/routing/turns_sound.cpp +++ b/routing/turns_sound.cpp @@ -48,32 +48,31 @@ void TurnsSound::GenerateTurnSound(vector const & turns, vector kMaxTurnDistM) return; - string const secondNotification = GenerateTurnText(0 /* distanceUnits is not used because of "Then" is used */, - secondTurn.m_turnItem.m_exitNum, true, - secondTurn.m_turnItem.m_turn, - m_settings.GetLengthUnits()); + string secondNotification = GenerateTurnText(0 /* distanceUnits is not used because of "Then" is used */, + secondTurn.m_turnItem.m_exitNum, true, + secondTurn.m_turnItem.m_turn, + m_settings.GetLengthUnits()); if (secondNotification.empty()) return; - turnNotifications.push_back(move(secondNotification)); + turnNotifications.emplace_back(move(secondNotification)); } string TurnsSound::GenerateFirstTurnSound(TurnItem const & turn, double distanceToTurnMeters) @@ -103,8 +102,8 @@ string TurnsSound::GenerateFirstTurnSound(TurnItem const & turn, double distance uint32_t const distToPronounce = m_settings.RoundByPresetSoundedDistancesUnits(turnNotificationDistUnits); m_nextTurnNotificationProgress = PronouncedNotification::First; - return GenerateTurnText(distToPronounce, turn.m_exitNum, false, turn.m_turn, - m_settings.GetLengthUnits()); + return GenerateTurnText(distToPronounce, turn.m_exitNum, false /* useThenInsteadOfDistance */, + turn.m_turn, m_settings.GetLengthUnits()); } } else @@ -113,16 +112,18 @@ string TurnsSound::GenerateFirstTurnSound(TurnItem const & turn, double distance // It happens if one turn follows shortly behind another one. m_nextTurnNotificationProgress = PronouncedNotification::First; } - return ""; + return string(); } if (m_nextTurnNotificationProgress == PronouncedNotification::First && distanceToTurnMeters < distanceToPronounceNotificationMeters) { m_nextTurnNotificationProgress = PronouncedNotification::Second; - return GenerateTurnText(0, turn.m_exitNum, false, turn.m_turn, m_settings.GetLengthUnits()); + return GenerateTurnText(0 /* distanceUnits */, turn.m_exitNum, + false /* useThenInsteadOfDistance */, + turn.m_turn, m_settings.GetLengthUnits()); } - return ""; + return string(); } void TurnsSound::Enable(bool enable) diff --git a/routing/turns_sound.hpp b/routing/turns_sound.hpp index e6e0eae191..94ccec8b6d 100644 --- a/routing/turns_sound.hpp +++ b/routing/turns_sound.hpp @@ -63,6 +63,7 @@ class TurnsSound string GenerateTurnText(uint32_t distanceUnits, uint8_t exitNum, bool useThenInsteadOfDistance, TurnDirection turnDir, LengthUnits lengthUnits) const; + /// Generates turn sound notification for the nearest to the current position turn. string GenerateFirstTurnSound(TurnItem const & turn, double distanceToTurnMeters); public: TurnsSound() : m_enabled(false), m_speedMetersPerSecond(0.), m_settings(), diff --git a/routing/turns_tts_text.cpp b/routing/turns_tts_text.cpp index 7d8aec4197..1c8b50978e 100644 --- a/routing/turns_tts_text.cpp +++ b/routing/turns_tts_text.cpp @@ -20,7 +20,7 @@ template string DistToTextId(TIter begin, TIter end, uint32_t dist if (distToSound == end) { ASSERT(false, ("notification.m_distanceUnits is not correct.")); - return ""; + return string(); } return distToSound->second; } @@ -51,11 +51,11 @@ string GetTtsText::operator()(Notification const & notification) const if (notification.m_distanceUnits == 0 && !notification.m_useThenInsteadOfDistance) return GetTextById(GetDirectionTextId(notification)); if (notification.m_useThenInsteadOfDistance && notification.m_turnDir == TurnDirection::NoTurn) - return ""; + return string(); string const dirStr = GetTextById(GetDirectionTextId(notification)); if (dirStr.empty()) - return ""; + return string(); string const distStr = GetTextById(GetDistanceTextId(notification)); return distStr + " " + dirStr; @@ -78,7 +78,7 @@ string GetDistanceTextId(Notification const & notification) if (!notification.IsValid()) { ASSERT(false, ()); - return ""; + return string(); } if (notification.m_useThenInsteadOfDistance) @@ -88,7 +88,7 @@ string GetDistanceTextId(Notification const & notification) { case LengthUnits::Undefined: ASSERT(false, ()); - return ""; + return string(); case LengthUnits::Meters: return DistToTextId(GetAllSoundedDistMeters().cbegin(), GetAllSoundedDistMeters().cend(), notification.m_distanceUnits); @@ -97,7 +97,7 @@ string GetDistanceTextId(Notification const & notification) notification.m_distanceUnits); } ASSERT(false, ()); - return ""; + return string(); } string GetDirectionTextId(Notification const & notification) @@ -132,10 +132,10 @@ string GetDirectionTextId(Notification const & notification) case TurnDirection::NoTurn: case TurnDirection::Count: ASSERT(false, ()); - return ""; + return string(); } ASSERT(false, ()); - return ""; + return string(); } } // namespace sound } // namespace turns