summaryrefslogtreecommitdiff
path: root/navit/navigation.c
diff options
context:
space:
mode:
authorRobotaxi <robotaxi@arcor.de>2015-08-13 21:40:59 +0200
committerRobotaxi <robotaxi@arcor.de>2015-08-13 21:40:59 +0200
commit20e32a0b714eef1bc260523c737f2d7bb2068ef2 (patch)
tree2a85d618c7111cd5a79f57f4194766519f9d929e /navit/navigation.c
parent968d85114ed8326ede2f2f8af981c862c25b08af (diff)
downloadnavit-20e32a0b714eef1bc260523c737f2d7bb2068ef2.tar.gz
Concatenation of announcements now working
Diffstat (limited to 'navit/navigation.c')
-rw-r--r--navit/navigation.c300
1 files changed, 159 insertions, 141 deletions
diff --git a/navit/navigation.c b/navit/navigation.c
index 2f5ced438..d00e6b243 100644
--- a/navit/navigation.c
+++ b/navit/navigation.c
@@ -127,6 +127,18 @@ static int sharp_turn_limit = 110;
* Note that, depending on other conditions, even maneuvers whose delta exceeds the threshold may still be announced as (sharp) turns. */
static int u_turn_limit = 165;
+/** Enum that defines the different states in announcing a turn.
+ * These states are dependent on the current distance to the turn;
+ * the distances are configured in navit.xml for every type of highway. */
+enum announcement_level {
+ level_connect = -2,
+ level_error = -1,
+ level_now = 0,
+ level_meters = 1,
+ level_soon = 2,
+ level_follow = 3
+};
+
enum gender {unknown, masculine, feminine, neuter};
struct suffix {
@@ -786,38 +798,39 @@ navigation_set_announce(struct navigation *this_, enum item_type type, int *leve
dbg(lvl_debug,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
return 0;
}
- for (i = 0 ; i < 3 ; i++)
+ for (i = 0 ; i < 3 ; i++)
this_->announce[type-route_item_first][i]=level[i];
return 1;
}
-static int
+static enum announcement_level
navigation_get_announce_level(struct navigation *this_, enum item_type type, int dist)
{
- int i;
+ enum announcement_level level;
if (type < route_item_first || type > route_item_last)
{
dbg(lvl_error," item outside routable range\n");
- return -1;
+ return level_error;
}
- for (i = 0 ; i < 3 ; i++) {
- if (dist <= this_->announce[type-route_item_first][i])
- return i;
+ for (level = level_now ; level < level_follow ; level++) {
+ if (dist <= this_->announce[type-route_item_first][level])
+ return level;
}
- return i;
+ return level;
}
static int is_way_allowed(struct navigation *nav, struct navigation_way *way, int mode);
-static int
+static enum announcement_level
navigation_get_announce_level_cmd(struct navigation *this_, struct navigation_itm *itm, struct navigation_command *cmd, int distance)
{
- int level2,level=navigation_get_announce_level(this_, itm->way.item.type, distance);
+ enum announcement_level level2,level=navigation_get_announce_level(this_, itm->way.item.type, distance);
if (this_->cmd_first->itm->prev) {
level2=navigation_get_announce_level(this_, cmd->itm->prev->way.item.type, distance);
- if (level2 > level)
- level=level2;
+ if (level2 > level) {
+ level = level2;
+ }
}
return level;
}
@@ -3251,50 +3264,60 @@ navigation_cmd_get_exit_announce(struct navigation_command *this_, char *street_
* in..., then turn right"
*/
static char *
-show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type, int connect)
+show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type, enum announcement_level level)
{
int distance=itm->dest_length-cmd->itm->dest_length;
char *d=NULL,*ret=NULL;
char *street_destination_announce=NULL;
- int level;
int skip_roads = 0;
int count_roundabout;
struct navigation_itm *cur;
int tellstreetname = 0;
- char * at = NULL; /* Motorway junction name */
- char * direction = NULL; /* The direction-dependent part of the maneuver */
+ char *at = NULL; /* Motorway junction name */
+ char *direction = NULL; /* The direction-dependent part of the maneuver */
char *destination = NULL;
char *street_destination = NULL;
- char * instruction = NULL;
- char * strength = NULL; /* Strength of the turn */
-
- if (connect)
- level = -2; /* level = -2 means "connect to another maneuver via 'then ...'" */
- else
- level = 1;
+ char *instruction = NULL;
+ char *strength = NULL; /* Strength of turn like 'easily', 'strongly', etc. */
if (type != attr_navigation_long_exact)
distance=round_distance(distance);
- if (type == attr_navigation_speech)
- {
- if (nav->turn_around && nav->turn_around == nav->turn_around_limit)
- {
- navigation_set_turnaround(nav, nav->turn_around_count+1);
- return g_strdup(_("When possible, please turn around"));
+
+ if (type == attr_navigation_speech) {
+ if (nav->turn_around && nav->turn_around == nav->turn_around_limit) {
+ if (level == level_connect) {
+ return g_strdup(""); /* there is no ',then turn around' */
+ } else {
+ navigation_set_turnaround(nav, nav->turn_around_count+1);
+ return g_strdup(_("When possible, please turn around"));
+ }
}
navigation_set_turnaround(nav, 0);
- if (!connect)
- level=navigation_get_announce_level_cmd(nav, itm, cmd, distance-cmd->length);
dbg(lvl_debug,"distance=%d level=%d type=0x%x\n", distance, level, itm->way.item.type);
}
street_destination=select_announced_destinations(cmd);
if (street_destination)
- /* TRANSLATORS: the argument is the destination to follow */
- street_destination_announce=g_strdup_printf(_("towards %s"),street_destination);
+ if (level == level_connect) {
+ /* for the connected announcement suppress the destination, if this is the same as in the first part of the announcement */
+ if (cmd->prev) {
+ char *street_destination_previous = select_announced_destinations(cmd->prev);
+ if (street_destination_previous && strstr(street_destination_previous, street_destination)) { /* doesn't have any new information? */
+ street_destination_announce=g_strdup("");
+ } else {
+ /* TRANSLATORS: the argument is the destination to follow */
+ street_destination_announce=g_strdup_printf(_("towards %s"),street_destination);
+ }
+ g_free(street_destination_previous);
+ } else {
+ street_destination_announce=g_strdup_printf(_("towards %s"),street_destination);
+ }
+ } else {
+ street_destination_announce=g_strdup_printf(_("towards %s"),street_destination);
+ }
else street_destination_announce=g_strdup("");
g_free(street_destination);
@@ -3311,21 +3334,20 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
}
switch (level)
{
- case 3:
+ case level_follow:
d=get_distance_str(nav, distance, type, 1);
return g_strdup_printf(_("Follow the road for the next %s"), d);
- case 2:
+ case level_soon:
return g_strdup(_("Enter the roundabout soon"));
- case 1:
+ case level_meters:
d = get_distance_str(nav, distance, attr_navigation_short, 0);
/* TRANSLATORS: %s is the distance to the roundabout */
ret = g_strdup_printf(_("Enter the roundabout %s"), d);
g_free(d);
return ret;
- case -2:
- /* TRANSLATORS: first arg. is the manieth exit, second arg. is the destination to follow */
- return g_strdup_printf(_("then leave the roundabout at the %1$s %2$s"), get_exit_count_str(count_roundabout),street_destination_announce);
- case 0:
+ case level_connect:
+ return g_strdup(_("then enter the roundabout"));
+ case level_now:
/* TRANSLATORS: first arg. is the manieth exit, second arg. is the destination to follow */
return g_strdup_printf(_("Leave the roundabout at the %1$s %2$s"), get_exit_count_str(count_roundabout),street_destination_announce);
}
@@ -3337,20 +3359,23 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
{
if(type == attr_navigation_speech)
{ /* In voice mode */
- /* In Voice Mode only tell the street name in level 1 or in level 0 if level 1 was skipped */
- if (level == 1)
+ /* In Voice Mode only tell the street name in level_meters or in level_ if level 1 was skipped */
+ if (level == level_meters)
{ /* we are close to the intersection */
cmd->itm->streetname_told = 1; /* remember to be checked when we turn */
tellstreetname = 1; /* Ok, so we tell the name of the street */
}
- if (level == 0)
+ else if (level == level_now)
{
if(cmd->itm->streetname_told == 0) /* we are right at the intersection */
tellstreetname = 1;
else
cmd->itm->streetname_told = 0; /* reset just in case we come to the same street again */
}
-
+ else if (level == level_connect)
+ {
+ tellstreetname = 1;
+ }
}
else
tellstreetname = 1;
@@ -3359,16 +3384,16 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
switch (level)
{
- case 2 :
+ case level_soon :
d=g_strdup(_("soon"));
break;
- case 1 :
+ case level_meters :
d=get_distance_str(nav, distance, attr_navigation_short, 0);
break;
- case 0 :
+ case level_now :
d=g_strdup(_("now"));
break;
- case -2 :
+ case level_connect :
d=g_strdup(_("then"));
break;
default :
@@ -3387,8 +3412,8 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
/* interchange or exit announcement shall be a long distance information only.
But if so, exit_label shall not be announced in case it is a substring
of destination info to avoid redundancy and not let the sentence become too long.
- Otherwise, if there is no additional destination info, just say it at level 1. */
- if ((level == 2) || ((level == 1) && (!street_destination_announce && !destination)) || (type != attr_navigation_speech)) {
+ Otherwise, if there is no additional destination info, just say it at level_meters. */
+ if ((level == level_soon) || ((level == level_meters) && (!street_destination_announce && !destination)) || (type != attr_navigation_speech)) {
exit_announce = navigation_cmd_get_exit_announce(cmd, street_destination_announce);
}
@@ -3397,16 +3422,16 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
case mex_merge_left:
case mex_merge_right:
if (cmd->maneuver->merge_or_exit == mex_merge_right) {
- if (level == -2)
+ if (level == level_connect)
/* TRANSLATORS: the arg. is the phrase 'onto ...'. Right merge, the stuff after | doesn't have to be included. */
- instruction = g_strdup_printf(_("then merge%1$s|right"), d);
+ instruction = g_strdup_printf(_("then merge%1$s|right"), destination);
else
/* TRANSLATORS: the first arg. is distance, the second is the phrase 'onto ...'. Right merge, the stuff after | doesn't have to be included. */
instruction = g_strdup_printf(_("Merge %1$s%2$s|right"), d, destination);
} else {
- if (level == -2)
+ if (level == level_connect)
/* TRANSLATORS: the arg. is the phrase 'onto ...'. Left merge, the stuff after | doesn't have to be included. */
- instruction = g_strdup_printf(_("then merge%1$s|left"), d);
+ instruction = g_strdup_printf(_("then merge%1$s|left"), destination);
else
/* TRANSLATORS: the first arg. is distance, the second is the phrase 'onto ...'. Left merge, the stuff after | doesn't have to be included. */
instruction = g_strdup_printf(_("Merge %1$s%2$s|left"), d, destination);
@@ -3439,7 +3464,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
at = g_strdup("");
switch (cmd->maneuver->type) {
case type_nav_straight :
- if (level == -2)
+ if (level == level_connect)
/* TRANSLATORS: the arg. is where to do the maneuver */
instruction = g_strdup_printf(_("then continue straight%1$s"), at);
else
@@ -3447,7 +3472,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
instruction = g_strdup_printf(_("Continue straight %1$s%2$s%3$s"), d, at, destination);
break;
case type_nav_keep_right :
- if (level == -2)
+ if (level == level_connect)
/* TRANSLATORS: the arg. is where to do the maneuver */
instruction = g_strdup_printf(_("then keep right%1$s"), at);
else
@@ -3455,7 +3480,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
instruction = g_strdup_printf(_("Keep right %1$s%2$s%3$s"), d, at, destination);
break;
case type_nav_keep_left :
- if (level == -2)
+ if (level == level_connect)
/* TRANSLATORS: the arg. is where to do the maneuver */
instruction = g_strdup_printf(_("then keep left%1$s"), at);
else
@@ -3475,16 +3500,21 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
case type_nav_right_3 :
/* TRANSLATORS: "right" as in "turn right" */
direction = g_strdup(_("right"));
- if (level==-2 || level == 0)
- skip_roads = count_possible_turns(nav,cmd->prev ? cmd->prev->itm : nav->first,cmd->itm,90);
+ if (level == level_now)
+ skip_roads = count_possible_turns(nav, cmd->prev ? cmd->prev->itm : nav->first, cmd->itm, 90);
+ else if (level == level_connect)
+ /* Robotaxi: todo - must tidy up skip_roads == -1 issue */
+ skip_roads = count_possible_turns(nav, itm->next ? itm->next : itm, cmd->itm, 90);
break;
case type_nav_left_1 :
case type_nav_left_2 :
case type_nav_left_3 :
/* TRANSLATORS: "left" as in "turn left" */
direction = g_strdup(_("left"));
- if (level==-2 || level == 0)
- skip_roads = count_possible_turns(nav,cmd->prev ? cmd->prev->itm : nav->first,cmd->itm,-90);
+ if (level == level_now)
+ skip_roads = count_possible_turns(nav, cmd->prev ? cmd->prev->itm : nav->first, cmd->itm, -90);
+ else if (level == level_connect)
+ skip_roads = count_possible_turns(nav, itm->next ? itm->next : itm, cmd->itm, -90);
break;
default:
direction = g_strdup("");
@@ -3505,22 +3535,28 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
strength = g_strdup("");
break;
}
- if (skip_roads) {
- if (skip_roads < 6)
- instruction = g_strdup_printf(_("Take the %1$s road to the %2$s"), get_count_str(skip_roads+1), direction);
- /*and preserve skip_roads to signal we already have an instruction*/
- else {
+ /* Robotaxi: todo - must tidy up skip_roads == -1 issue */
+ if (skip_roads > 0) {
+ if (skip_roads < 6) {
+ if (level == level_connect)
+ instruction = g_strdup_printf(_("then take the %1$s road to the %2$s"), get_count_str(skip_roads+1), direction);
+ else
+ instruction = g_strdup_printf(_("Take the %1$s road to the %2$s"), get_count_str(skip_roads+1), direction);
+ /*and preserve skip_roads to signal that we already have an instruction*/
+ } else {
g_free(d);
d=g_strdup_printf(_("after %i roads"),skip_roads);
skip_roads = 0; /*signal an instruction still has to be created*/
}
}
- if (!skip_roads) /* cave: no else - may come from 'if (skip_roads)' above ! */
+ /* cave: no else - may come from 'if (skip_roads)' above ! */
+ if (skip_roads <= 0) {
/* TRANSLATORS: the first arg. is strength, the second is direction, the third is distance, the fourth is destination */
instruction = g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, direction, d, destination);
+ }
break;
case type_nav_turnaround_left:
- if (level == -2)
+ if (level == level_connect)
/* TRANSLATORS: Left U-turn, the stuff after | doesn't have to be included. */
instruction = g_strdup(_("then make a U-turn|left"));
else
@@ -3528,7 +3564,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
instruction = g_strdup_printf(_("Make a U-turn %1$s|left"), d);
break;
case type_nav_turnaround_right:
- if (level == -2)
+ if (level == level_connect)
/* TRANSLATORS: Right U-turn, the stuff after | doesn't have to be included. */
instruction = g_strdup(_("then make a U-turn|right"));
else
@@ -3543,7 +3579,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
* in cases where relevant destination info is available.
* Even if there is no driving command to be announced, in some cases
* there is an overhead roadsign in preparation of an upcoming road-split,
- * and then we can give usefull info to the driver.
+ * and then we can give useful info to the driver.
*
* UNTESTED !
*
@@ -3552,13 +3588,13 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
break;
case type_nav_destination:
/* the old code used to clear the route destination when this was the only
- * instruction left. Was that usefull ?
+ * instruction left. Was that useful ?
* Should be tested with the old code what happens if the driver
* 'overshoots' the destination and the route destination is already cleared.
* I suppose it will now keep guiding the user to destination untill another one
* is set or a 'stop navigation' action is done using the gui.
*/
- if (level == -2)
+ if (level == level_connect)
instruction=g_strdup(_("then you have reached your destination."));
else
/* TRANSLATORS: the arg. is distance */
@@ -3572,28 +3608,24 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
}
switch (level)
{
- case 3:
+ case level_follow:
d=get_distance_str(nav, distance, type, 1);
ret=g_strdup_printf(_("Follow the road for the next %s"), d);
break;
- case 2:
+ case level_soon:
if (at) /* 'at' contains interchange or exit information that shall not be combined with street_destination_announce */
ret= g_strdup_printf(("%1$s %2$s"),instruction,"");
else
ret= g_strdup_printf(("%1$s %2$s"),instruction,street_destination_announce);
break;
- case 1:
- ret= g_strdup_printf(("%1$s %2$s"),instruction,street_destination_announce);
- break;
- case -2:
- ret= g_strdup_printf(("%1$s %2$s"),instruction,street_destination_announce);
- break;
- case 0:
+ case level_meters:
+ case level_connect:
+ case level_now:
ret= g_strdup_printf(("%1$s %2$s"),instruction,street_destination_announce);
break;
default :
ret= g_strdup_printf(("%1$s %2$s"),instruction,street_destination_announce);
- dbg(lvl_error,"unevaluated speech level\n");
+ dbg(lvl_error,"unevaluated announcement level\n");
break;
}
@@ -3632,77 +3664,63 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
static char *
show_next_maneuvers(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
{
- struct navigation_command *cur,*prev;
- int distance=itm->dest_length-cmd->itm->dest_length;
- int level, i, time;
- int speech_time,time2nav;
- char *ret,*old,*buf,*next;
+ int distance = itm->dest_length-cmd->itm->dest_length; // distance from e.g. current GPS position to next announced turn position
+ enum announcement_level level;
+ char *ret,*buf,*next;
+
if (type != attr_navigation_speech) {
- return show_maneuver(nav, itm, cmd, type, 0); /* We accumulate maneuvers only in speech navigation */
+ return show_maneuver(nav, itm, cmd, type, level_meters); /* We only accumulate maneuvers in speech navigation */
}
- level=navigation_get_announce_level(nav, itm->way.item.type, distance-cmd->length);
- if (level > 1) {
- return show_maneuver(nav, itm, cmd, type, 0); /* We accumulate maneuvers only if they are close */
- }
+//////////////////////////////////////
+ level = navigation_get_announce_level_cmd(nav, itm, cmd, distance-cmd->length);
+//////////////////////////////////////
+ //level=navigation_get_announce_level(nav, itm->way.item.type, distance - cmd->length);
- if (cmd->itm->told) {
+ if (level > level_soon) {
+ /* suppress the 'follow the road..' announcement, if the next 'soon' announcement is just a few meters away, so just quit */
+ if ((distance - cmd->length) < (nav->announce[itm->way.item.type - route_item_first][2] + 2 * nav->announce[itm->way.item.type - route_item_first][0])) {
+ /* a few meters away is defined by two times the distance of the 'now'-distance. */
+ return g_strdup("");
+ }
+ }
+ else if ((level == level_soon) && (itm->told == 1)) {
+ /* suppress the 'soon' announcement, if the last announcement already concatenated this, so just quit */
return g_strdup("");
}
-
- ret = show_maneuver(nav, itm, cmd, type, 0);
- time2nav = navigation_time(itm,cmd->itm->prev);
- old = NULL;
-
- cur = cmd->next;
- prev = cmd;
- i = 0;
- while (cur && cur->itm) {
- /* We don't merge more than 3 announcements... */
- if (i > 1) { /* if you change this, please also change the value below, that is used to terminate the loop */
- break;
- }
-
- next = show_maneuver(nav,prev->itm, cur, type, 0);
- if (nav->speech)
- speech_time = speech_estimate_duration(nav->speech,next);
- else
- speech_time = -1;
- g_free(next);
-
- if (speech_time == -1) { /* user didn't set cps */
- speech_time = 30; /* assume 3 seconds */
+ else if ((level == level_meters) && (itm->told == 1)) {
+ /* suppress the 'in xx meters..' announcement, if the 'soon' announcement is just a few meters away, so just quit */
+ if ((distance - cmd->length) < (nav->announce[itm->way.item.type - route_item_first][1] + 2 * nav->announce[itm->way.item.type - route_item_first][0])) {
+ /* a few meters away is defined by two times the distance of the 'now'-distance. */
+ return g_strdup("");
}
+ }
- time = navigation_time(prev->itm,cur->itm->prev);
-
- if (time >= (speech_time + 30)) { /* 3 seconds for understanding what has been said */
- break;
- }
+ ret = show_maneuver(nav, itm, cmd, type, level);
+
+ if (level > level_meters) {
+ return ret; /* We only concatenate maneuvers that are close each other, so quit here */
+ }
- old = ret;
- buf = show_maneuver(nav, prev->itm, cur, type, 1);
- ret = g_strdup_printf("%s, %s", old, buf);
- g_free(buf);
- if (nav->speech && speech_estimate_duration(nav->speech,ret) > time2nav) {
- g_free(ret);
- ret = old;
- i = 2; /* This will terminate the loop */
- } else {
- g_free(old);
- }
+ if (cmd->next && cmd->itm) {
+ // determine the level of the command that comes immediately after that.
+ enum announcement_level nextlevel = navigation_get_announce_level(nav, cmd->itm->way.item.type, cmd->itm->dest_length - cmd->next->itm->dest_length);
- /* If the two maneuvers are *really* close, we shouldn't tell the second one again, because TTS won't be fast enough */
- if (time <= speech_time) {
- cur->itm->told = 1;
+ // If this level starts with 1 or 0 concatenate the following announcement to the current:
+ if (nextlevel <= level_soon) {
+ next = show_maneuver(nav, cmd->itm, cmd->next, type, level_connect);
+ if (*next != '\0') /* is the second announcement not an empty string? */
+ {
+ cmd->itm->told = 1;
+ buf = ret;
+ ret = g_strdup_printf("%s, %s", buf, next); // concatenate both announcements
+ g_free(buf);
+ }
+ g_free(next);
}
-
- prev = cur;
- cur = cur->next;
- i++;
- }
+ }
return ret;
}
@@ -3716,7 +3734,7 @@ navigation_call_callbacks(struct navigation *this_, int force_speech)
return;
callback_list_call(this_->callback, 1, &p);
dbg(lvl_debug,"force_speech=%d turn_around=%d turn_around_limit=%d\n", force_speech, this_->turn_around, this_->turn_around_limit);
- distance=round_distance(this_->first->dest_length-this_->cmd_first->itm->dest_length);
+ distance=this_->first->dest_length-this_->cmd_first->itm->dest_length;
if (this_->turn_around_limit && this_->turn_around == this_->turn_around_limit) {
dbg(lvl_debug,"distance=%d distance_turn=%d\n", distance, this_->distance_turn);
while (distance > this_->distance_turn) {