diff options
author | Robotaxi <robotaxi@arcor.de> | 2015-08-13 21:40:59 +0200 |
---|---|---|
committer | Robotaxi <robotaxi@arcor.de> | 2015-08-13 21:40:59 +0200 |
commit | 20e32a0b714eef1bc260523c737f2d7bb2068ef2 (patch) | |
tree | 2a85d618c7111cd5a79f57f4194766519f9d929e /navit/navigation.c | |
parent | 968d85114ed8326ede2f2f8af981c862c25b08af (diff) | |
download | navit-20e32a0b714eef1bc260523c737f2d7bb2068ef2.tar.gz |
Concatenation of announcements now working
Diffstat (limited to 'navit/navigation.c')
-rw-r--r-- | navit/navigation.c | 300 |
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) { |