forked from organicmaps/organicmaps-tmp
Merge pull request #164 from bykoianko/k-th-exit-from-a-roundabout
[turns][sound] Sound notification about an exact number of roundabout exit.
This commit is contained in:
commit
85bd6d264a
8 changed files with 166 additions and 5 deletions
|
@ -202,7 +202,7 @@ UNIT_TEST(RussiaHugeRoundaboutTurnTest)
|
|||
integration::GetNthTurn(route, 1)
|
||||
.TestValid()
|
||||
.TestDirection(TurnDirection::LeaveRoundAbout)
|
||||
.TestRoundAboutExitNum(0);
|
||||
.TestRoundAboutExitNum(4);
|
||||
}
|
||||
|
||||
UNIT_TEST(BelarusMiskProspNezavisimostiMKADTurnTest)
|
||||
|
|
|
@ -138,7 +138,7 @@ UNIT_TEST(TestFixupTurns)
|
|||
|
||||
FixupTurns(pointsMerc1, turnsDir1);
|
||||
Route::TTurns const expectedTurnDir1 = {{0, TurnDirection::EnterRoundAbout, 2},
|
||||
{2, TurnDirection::LeaveRoundAbout},
|
||||
{2, TurnDirection::LeaveRoundAbout, 2},
|
||||
{3, TurnDirection::ReachedYourDestination}};
|
||||
TEST_EQUAL(turnsDir1, expectedTurnDir1, ());
|
||||
|
||||
|
|
|
@ -394,6 +394,114 @@ UNIT_TEST(TurnsSoundComposedTurnTest)
|
|||
turnSound.GenerateTurnSound(turns6, turnNotifications);
|
||||
TEST_EQUAL(turnNotifications, expectedNotification6, ());
|
||||
}
|
||||
|
||||
UNIT_TEST(TurnsSoundRoundaboutTurnTest)
|
||||
{
|
||||
TurnsSound turnSound;
|
||||
turnSound.Enable(true);
|
||||
turnSound.SetLengthUnits(routing::turns::sound::LengthUnits::Meters);
|
||||
string const engShortJson =
|
||||
"\
|
||||
{\
|
||||
\"enter_the_roundabout\":\"Enter the roundabout.\",\
|
||||
\"leave_the_roundabout\":\"Leave the roundabout.\",\
|
||||
\"take_the_1st_exit\":\"Take the first exit.\",\
|
||||
\"take_the_2nd_exit\":\"Take the second exit.\",\
|
||||
\"take_the_4th_exit\":\"Take the fourth exit.\",\
|
||||
\"in_600_meters\":\"In 600 meters.\",\
|
||||
\"then\":\"Then.\"\
|
||||
}";
|
||||
turnSound.m_getTtsText.ForTestingSetLocaleWithJson(engShortJson);
|
||||
turnSound.m_settings.ForTestingSetNotificationTimeSecond(30);
|
||||
|
||||
turnSound.Reset();
|
||||
turnSound.SetSpeedMetersPerSecond(20.);
|
||||
vector<string> turnNotifications;
|
||||
|
||||
// Starting nearing the first turn.
|
||||
// 1000 meters till the first turn.
|
||||
vector<TurnItemDist> const turns1 = {{{5 /* idx */, TurnDirection::EnterRoundAbout, 2 /* m_exitNum */},
|
||||
1000. /* m_distMeters */},
|
||||
{{10 /* idx */, TurnDirection::LeaveRoundAbout, 2 /* m_exitNum */},
|
||||
2000. /* m_distMeters */}};
|
||||
turnSound.GenerateTurnSound(turns1, turnNotifications);
|
||||
TEST(turnNotifications.empty(), ());
|
||||
|
||||
// 620 meters till the first turn.
|
||||
vector<TurnItemDist> const turns2 = {{{5 /* idx */, TurnDirection::EnterRoundAbout, 2 /* m_exitNum */},
|
||||
620. /* m_distMeters */},
|
||||
{{10 /* idx */, TurnDirection::LeaveRoundAbout, 2 /* m_exitNum */},
|
||||
1620. /* m_distMeters */}};
|
||||
vector<string> const expectedNotification2 = {{"In 600 meters. Enter the roundabout."},
|
||||
{"Then. Take the second exit."}};
|
||||
turnSound.GenerateTurnSound(turns2, turnNotifications);
|
||||
TEST_EQUAL(turnNotifications, expectedNotification2, ());
|
||||
|
||||
// 3 meters till the first turn.
|
||||
vector<TurnItemDist> const turns3 = {{{5 /* idx */, TurnDirection::EnterRoundAbout, 2 /* m_exitNum */},
|
||||
3. /* m_distMeters */},
|
||||
{{10 /* idx */, TurnDirection::LeaveRoundAbout, 2 /* m_exitNum */},
|
||||
1003. /* m_distMeters */}};
|
||||
vector<string> const expectedNotification3 = {{"Enter the roundabout."},
|
||||
{"Then. Take the second exit."}};
|
||||
turnSound.GenerateTurnSound(turns3, turnNotifications);
|
||||
TEST_EQUAL(turnNotifications, expectedNotification3, ());
|
||||
|
||||
// 900 meters till the second turn.
|
||||
vector<TurnItemDist> const turns4 = {{{10 /* idx */, TurnDirection::LeaveRoundAbout, 2 /* m_exitNum */},
|
||||
900. /* m_distMeters */},
|
||||
{{15 /* idx */, TurnDirection::EnterRoundAbout, 1 /* m_exitNum */},
|
||||
1900. /* m_distMeters */}};
|
||||
turnSound.GenerateTurnSound(turns4, turnNotifications);
|
||||
TEST(turnNotifications.empty(), ());
|
||||
|
||||
// 300 meters till the second turn.
|
||||
vector<TurnItemDist> const turns5 = {{{10 /* idx */, TurnDirection::LeaveRoundAbout, 2 /* m_exitNum */},
|
||||
300. /* m_distMeters */},
|
||||
{{15 /* idx */, TurnDirection::EnterRoundAbout, 1 /* m_exitNum */},
|
||||
1300. /* m_distMeters */}};
|
||||
turnSound.GenerateTurnSound(turns5, turnNotifications);
|
||||
TEST(turnNotifications.empty(), ());
|
||||
|
||||
// 3 meters till the second turn.
|
||||
vector<TurnItemDist> const turns6 = {{{10 /* idx */, TurnDirection::LeaveRoundAbout, 2 /* m_exitNum */},
|
||||
3. /* m_distMeters */},
|
||||
{{15 /* idx */, TurnDirection::EnterRoundAbout, 1 /* m_exitNum */},
|
||||
1003. /* m_distMeters */}};
|
||||
vector<string> const expectedNotification6 = {{"Leave the roundabout."}};
|
||||
turnSound.GenerateTurnSound(turns6, turnNotifications);
|
||||
TEST_EQUAL(turnNotifications, expectedNotification6, ());
|
||||
|
||||
// 5 meters till the third turn.
|
||||
vector<TurnItemDist> const turns7 = {{{15 /* idx */, TurnDirection::EnterRoundAbout, 1 /* m_exitNum */},
|
||||
5. /* m_distMeters */},
|
||||
{{20 /* idx */, TurnDirection::LeaveRoundAbout, 1 /* m_exitNum */},
|
||||
1005. /* m_distMeters */}};
|
||||
vector<string> const expectedNotification7 = {{"Enter the roundabout."},
|
||||
{"Then. Take the first exit."}};
|
||||
turnSound.GenerateTurnSound(turns7, turnNotifications); // The first notification fast forwarding.
|
||||
turnSound.GenerateTurnSound(turns7, turnNotifications);
|
||||
TEST_EQUAL(turnNotifications, expectedNotification7, ());
|
||||
|
||||
// 900 meters till the 4th turn.
|
||||
turnSound.Reset();
|
||||
vector<TurnItemDist> const turns8 = {{{25 /* idx */, TurnDirection::EnterRoundAbout, 4 /* m_exitNum */},
|
||||
900. /* m_distMeters */},
|
||||
{{30 /* idx */, TurnDirection::LeaveRoundAbout, 4 /* m_exitNum */},
|
||||
1200. /* m_distMeters */}};
|
||||
turnSound.GenerateTurnSound(turns8, turnNotifications);
|
||||
TEST(turnNotifications.empty(), ());
|
||||
|
||||
// 620 meters till the 4th turn.
|
||||
vector<TurnItemDist> const turns9 = {{{25 /* idx */, TurnDirection::EnterRoundAbout, 4 /* m_exitNum */},
|
||||
620. /* m_distMeters */},
|
||||
{{30 /* idx */, TurnDirection::LeaveRoundAbout, 4 /* m_exitNum */},
|
||||
920. /* m_distMeters */}};
|
||||
vector<string> const expectedNotification9 = {{"In 600 meters. Enter the roundabout."},
|
||||
{"Then. Take the fourth exit."}};
|
||||
turnSound.GenerateTurnSound(turns9, turnNotifications);
|
||||
TEST_EQUAL(turnNotifications, expectedNotification9, ());
|
||||
}
|
||||
} // namespace sound
|
||||
} // namespace turns
|
||||
} // namespace routing
|
||||
|
|
|
@ -579,7 +579,8 @@ void FixupTurns(vector<m2::PointD> const & points, Route::TTurns & turnsDir)
|
|||
}
|
||||
else if (roundabout && t.m_turn == TurnDirection::LeaveRoundAbout)
|
||||
{
|
||||
roundabout->m_exitNum = exitNum + 1;
|
||||
roundabout->m_exitNum = exitNum + 1; // For EnterRoundAbout turn.
|
||||
t.m_exitNum = roundabout->m_exitNum; // For LeaveRoundAbout turn.
|
||||
roundabout = nullptr;
|
||||
exitNum = 0;
|
||||
}
|
||||
|
|
|
@ -29,6 +29,18 @@ uint32_t CalculateDistBeforeMeters(double m_speedMetersPerSecond)
|
|||
static_cast<uint32_t>(m_speedMetersPerSecond * kStartBeforeSeconds);
|
||||
return my::clamp(startBeforeMeters, kMinStartBeforeMeters, kMaxStartBeforeMeters);
|
||||
}
|
||||
|
||||
// Returns true if the closest turn is an entrance to a roundabout and the second is
|
||||
// an exit form a roundabout.
|
||||
// Note. There are some cases when another turn (besides an exit from roundabout)
|
||||
// follows an entrance to a roundabout. It could happend in case of turns inside a roundabout.
|
||||
// Returns false otherwise.
|
||||
bool IsClassicEntranceToRoundabout(routing::turns::TurnItemDist const & firstTurn,
|
||||
routing::turns::TurnItemDist const & secondTurn)
|
||||
{
|
||||
return firstTurn.m_turnItem.m_turn == routing::turns::TurnDirection::EnterRoundAbout
|
||||
&& secondTurn.m_turnItem.m_turn == routing::turns::TurnDirection::LeaveRoundAbout;
|
||||
}
|
||||
} // namespace
|
||||
|
||||
namespace routing
|
||||
|
@ -64,8 +76,11 @@ void TurnsSound::GenerateTurnSound(vector<TurnItemDist> const & turns, vector<st
|
|||
return;
|
||||
TurnItemDist const & secondTurn = turns[1];
|
||||
ASSERT_LESS_OR_EQUAL(firstTurn.m_distMeters, secondTurn.m_distMeters, ());
|
||||
if (secondTurn.m_distMeters - firstTurn.m_distMeters > kMaxTurnDistM)
|
||||
if (secondTurn.m_distMeters - firstTurn.m_distMeters > kMaxTurnDistM
|
||||
&& !IsClassicEntranceToRoundabout(firstTurn, secondTurn))
|
||||
{
|
||||
return;
|
||||
}
|
||||
string secondNotification = GenerateTurnText(0 /* distanceUnits is not used because of "Then" is used */,
|
||||
secondTurn.m_turnItem.m_exitNum, true,
|
||||
secondTurn.m_turnItem.m_turn,
|
||||
|
|
|
@ -37,6 +37,7 @@ class TurnsSound
|
|||
friend void UnitTest_TurnsSoundMetersTwoTurnsTest();
|
||||
friend void UnitTest_TurnsSoundFeetTest();
|
||||
friend void UnitTest_TurnsSoundComposedTurnTest();
|
||||
friend void UnitTest_TurnsSoundRoundaboutTurnTest();
|
||||
|
||||
/// m_enabled == true when tts is turned on.
|
||||
/// Important! Clients (iOS/Android) implies that m_enabled is false by default.
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#include "routing/turns_sound_settings.hpp"
|
||||
#include "routing/turns_tts_text.hpp"
|
||||
|
||||
#include "base/string_utils.hpp"
|
||||
|
||||
#include "std/algorithm.hpp"
|
||||
#include "std/string.hpp"
|
||||
#include "std/utility.hpp"
|
||||
|
@ -100,6 +102,37 @@ string GetDistanceTextId(Notification const & notification)
|
|||
return string();
|
||||
}
|
||||
|
||||
string GetRoundaboutTextId(Notification const & notification)
|
||||
{
|
||||
if (notification.m_turnDir != TurnDirection::LeaveRoundAbout)
|
||||
{
|
||||
ASSERT(false, ());
|
||||
return string();
|
||||
}
|
||||
if (!notification.m_useThenInsteadOfDistance)
|
||||
return "leave_the_roundabout"; // Notification just before leaving a roundabout.
|
||||
|
||||
static const uint8_t kMaxSoundedExit = 11;
|
||||
if (notification.m_exitNum == 0 || notification.m_exitNum > kMaxSoundedExit)
|
||||
return "leave_the_roundabout";
|
||||
|
||||
if (notification.m_exitNum < 4)
|
||||
{
|
||||
switch (notification.m_exitNum)
|
||||
{
|
||||
case 1:
|
||||
return "take_the_1st_exit";
|
||||
case 2:
|
||||
return "take_the_2nd_exit";
|
||||
case 3:
|
||||
return "take_the_3rd_exit";
|
||||
}
|
||||
ASSERT(false, ());
|
||||
return string();
|
||||
}
|
||||
return "take_the_" + strings::to_string(static_cast<int>(notification.m_exitNum)) + "th_exit";
|
||||
}
|
||||
|
||||
string GetDirectionTextId(Notification const & notification)
|
||||
{
|
||||
switch (notification.m_turnDir)
|
||||
|
@ -123,7 +156,7 @@ string GetDirectionTextId(Notification const & notification)
|
|||
case TurnDirection::EnterRoundAbout:
|
||||
return "enter_the_roundabout";
|
||||
case TurnDirection::LeaveRoundAbout:
|
||||
return "leave_the_roundabout";
|
||||
return GetRoundaboutTextId(notification);
|
||||
case TurnDirection::ReachedYourDestination:
|
||||
return "you_have_reached_the_destination";
|
||||
case TurnDirection::StayOnRoundAbout:
|
||||
|
|
|
@ -36,6 +36,9 @@ private:
|
|||
|
||||
/// Generates text message id about the distance of the notification. For example: In 300 meters.
|
||||
string GetDistanceTextId(Notification const & notification);
|
||||
/// Generates text message id for roundabouts.
|
||||
/// For example: leave_the_roundabout or take_the_3rd_exit
|
||||
string GetRoundaboutTextId(Notification const & notification);
|
||||
/// Generates text message id about the direction of the notification. For example: Make a right
|
||||
/// turn.
|
||||
string GetDirectionTextId(Notification const & notification);
|
||||
|
|
Loading…
Add table
Reference in a new issue