Fix:maptool:Another name for faroe islands
[navit-package] / navit / navigation.c
index 8f868c7..ce01152 100644 (file)
@@ -21,6 +21,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <math.h>
+#include <ctype.h>
 #include <glib.h>
 #include "debug.h"
 #include "profile.h"
@@ -54,6 +55,7 @@ struct suffix {
 };
 
 struct navigation {
+       struct route *route;
        struct map *map;
        struct item_hash *hash;
        struct navigation_itm *first;
@@ -62,13 +64,15 @@ struct navigation {
        struct navigation_command *cmd_last;
        struct callback_list *callback_speech;
        struct callback_list *callback;
+       struct navit *navit;
        int level_last;
        struct item item_last;
        int turn_around;
        int turn_around_limit;
        int distance_turn;
-       int distance_last;
+       struct callback *route_cb;
        int announce[route_item_last-route_item_first+1][3];
+       int tell_street_name;
 };
 
 
@@ -81,6 +85,8 @@ struct navigation_command {
        int length;
 };
 
+static void navigation_flush(struct navigation *this_);
+
 /**
  * @brief Calculates the delta between two angles
  * @param angle1 The first angle
@@ -99,18 +105,54 @@ angle_delta(int angle1, int angle2)
        return delta;
 }
 
+static int
+angle_median(int angle1, int angle2)
+{
+       int delta=angle_delta(angle1, angle2);
+       int ret=angle1+delta/2;
+       if (ret < 0)
+               ret+=360;
+       if (ret > 360)
+               ret-=360;
+       return ret;
+}
+
+static int
+angle_opposite(int angle)
+{
+       return ((angle+180)%360);
+}
+
+int
+navigation_get_attr(struct navigation *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
+{
+       dbg(0,"enter %s\n", attr_to_name(type));
+       switch (type) {
+       case attr_map:
+               attr->u.map=this_->map;
+               break;
+       default:
+               return 0;       
+       }
+       attr->type=type;
+       return 1;
+}
+
+
 struct navigation *
-navigation_new(struct attr **attrs)
+navigation_new(struct attr *parent, struct attr **attrs)
 {
        int i,j;
+       struct attr * attr;
        struct navigation *ret=g_new0(struct navigation, 1);
        ret->hash=item_hash_new();
        ret->callback=callback_list_new();
        ret->callback_speech=callback_list_new();
        ret->level_last=-2;
-       ret->distance_last=-2;
        ret->distance_turn=50;
        ret->turn_around_limit=3;
+       ret->navit=parent->u.navit;
+       ret->tell_street_name=1;
 
        for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
                for (i = 0 ; i < 3 ; i++) {
@@ -118,6 +160,10 @@ navigation_new(struct attr **attrs)
                }
        }
 
+       if ((attr=attr_search(attrs, NULL, attr_tell_street_name))) {
+               ret->tell_street_name = attr->u.num;
+       }
+
        return ret;     
 }
 
@@ -196,7 +242,7 @@ static char
 {
        switch (n) {
        case 0:
-               return _("zeroth"); // Not shure if this exists, neither if it will ever be needed
+               return _("zeroth"); // Not sure if this exists, neither if it will ever be needed
        case 1:
                return _("first");
        case 2:
@@ -214,6 +260,28 @@ static char
        }
 }
 
+static char
+*get_exit_count_str(int n) 
+{
+       switch (n) {
+       case 0:
+               return _("zeroth exit"); // Not sure if this exists, neither if it will ever be needed
+       case 1:
+               return _("first exit");
+       case 2:
+               return _("second exit");
+       case 3:
+               return _("third exit");
+       case 4:
+               return _("fourth exit");
+       case 5:
+               return _("fifth exit");
+       case 6:
+               return _("sixth exit");
+       default: 
+               return NULL;
+       }
+}
 static int
 round_distance(int dist)
 {
@@ -264,7 +332,7 @@ get_distance(int dist, enum attr_type type, int is_length)
                int rem=(dist/100)%10;
                if (rem) {
                        if (is_length)
-                               return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
+                               return g_strdup_printf(_("%d.%d kilometers"), dist/1000, rem);
                        else
                                return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
                }
@@ -607,7 +675,7 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
        if (ritem) {
                ret->streetname_told=0;
                if (! item_attr_get(ritem, attr_street_item, &street_item)) {
-                       dbg(0,"no street item\n");
+                       dbg(1, "no street item\n");
                        return NULL;
                }
                if (item_attr_get(ritem, attr_direction, &direction))
@@ -619,7 +687,8 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
                ret->item=*sitem;
                item_hash_insert(this_->hash, sitem, ret);
                mr=map_rect_new(sitem->map, NULL);
-               sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo);
+               if (! (sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo)))
+                       return NULL;
                if (item_attr_get(sitem, attr_street_name, &attr))
                        ret->name1=map_convert_string(sitem->map,attr.u.str);
                if (item_attr_get(sitem, attr_street_name_systematic, &attr))
@@ -944,9 +1013,8 @@ maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *
        if (!new->ways) {
                /* No announcement necessary */
                r="no: Only one possibility";
-       } else if (!new->ways->next && new->ways->item.type == type_ramp) {
+       } else if (!new->ways->next && new->ways->item.type == type_ramp && !is_way_allowed(new->ways)) {
                /* If the other way is only a ramp and it is one-way in the wrong direction, no announcement necessary */
-               /* TODO: check for one way in wrong direction */
                r="no: Only ramp";
        }
        if (! r) {
@@ -1110,24 +1178,27 @@ command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
        dbg(1,"enter this_=%p itm=%p delta=%d\n", this_, itm, delta);
        ret->delta=delta;
        ret->itm=itm;
-       if (itm && itm->prev && !(itm->flags & AF_ROUNDABOUT) && (itm->prev->flags & AF_ROUNDABOUT)) {
+       if (itm && itm->prev && itm->ways && itm->prev->ways && !(itm->flags & AF_ROUNDABOUT) && (itm->prev->flags & AF_ROUNDABOUT)) {
                int len=0;
-               int angle;
+               int angle=0;
+               int entry_angle;
                struct navigation_itm *itm2=itm->prev;
+               int exit_angle=angle_median(itm->prev->angle_end, itm->ways->angle2);
+               dbg(1,"exit %d median from %d,%d\n", exit_angle,itm->prev->angle_end, itm->ways->angle2);
                while (itm2 && (itm2->flags & AF_ROUNDABOUT)) {
                        len+=itm2->length;
                        angle=itm2->angle_end;
                        itm2=itm2->prev;
                }
-               if (itm2) 
-                       ret->roundabout_delta=angle_delta(itm2->angle_end, itm->angle_start);
-               else {
-                       if (delta > 0) 
-                               angle-=90;
-                       else
-                               angle+=90;
-                       ret->roundabout_delta=angle_delta(angle % 360, itm->angle_start);
+               if (itm2 && itm2->next && itm2->next->ways) {
+                       itm2=itm2->next;
+                       entry_angle=angle_median(angle_opposite(itm2->angle_start), itm2->ways->angle2);
+                       dbg(1,"entry %d median from %d(%d),%d\n", entry_angle,angle_opposite(itm2->angle_start), itm2->angle_start, itm2->ways->angle2);
+               } else {
+                       entry_angle=angle_opposite(angle);
                }
+               dbg(0,"entry %d exit %d\n", entry_angle, exit_angle);
+               ret->roundabout_delta=angle_delta(entry_angle, exit_angle);
                ret->length=len;
                
        }
@@ -1180,6 +1251,9 @@ replace_suffix(char *name, char *search, char *replace)
        char *ret=g_malloc(len+strlen(replace)+1);
        strncpy(ret, name, len);
        strcpy(ret+len, replace);
+       if (isupper(name[len])) {
+               ret[len]=toupper(ret[len]);
+       }
 
        return ret;
 }
@@ -1250,7 +1324,7 @@ navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *n
                /* TRANSLATORS: gives the name of the next road to turn into (into the E17) */
                ret=g_strdup_printf(_("%sinto the %s"),prefix,itm->name2);
        name1=ret;
-       while (*name1) {
+       while (name1 && *name1) {
                switch (*name1) {
                case '|':
                        *name1='\0';
@@ -1271,7 +1345,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
        /* TRANSLATORS: right, as in 'Turn right' */
        char *dir=_("right"),*strength="";
        int distance=itm->dest_length-cmd->itm->dest_length;
-       char *d,*ret;
+       char *d,*ret=NULL;
        int delta=cmd->delta;
        int level;
        int strength_needed;
@@ -1288,9 +1362,9 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
 
        w = itm->next->ways;
        strength_needed = 0;
-       if ((itm->next->angle_start - itm->angle_end) < 0) {
+       if (angle_delta(itm->next->angle_start,itm->angle_end) < 0) {
                while (w) {
-                       if (w->angle2-itm->next->angle_start < 0) {
+                       if (angle_delta(w->angle2,itm->angle_end) < 0) {
                                strength_needed = 1;
                                break;
                        }
@@ -1298,7 +1372,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                }
        } else {
                while (w) {
-                       if (w->angle2-itm->next->angle_start > 0) {
+                       if (angle_delta(w->angle2,itm->angle_end) > 0) {
                                strength_needed = 1;
                                break;
                        }
@@ -1321,6 +1395,9 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                } else if (delta < 165) {
                        /* TRANSLATORS: Don't forget the ending space */
                        strength=_("strongly ");
+               } else if (delta < 180) {
+                       /* TRANSLATORS: Don't forget the ending space */
+                       strength=_("really strongly ");
                } else {
                        dbg(1,"delta=%d\n", delta);
                        /* TRANSLATORS: Don't forget the ending space */
@@ -1344,6 +1421,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                        return g_strdup(_("Enter the roundabout soon"));
                case 1:
                        d = get_distance(distance, type, 1);
+                       /* TRANSLATORS: %s is the distance to the roundabout */
                        ret = g_strdup_printf(_("In %s, enter the roundabout"), d);
                        g_free(d);
                        return ret;
@@ -1359,10 +1437,10 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                        }
                        switch (level) {
                        case 0:
-                               ret = g_strdup_printf(_("Leave the roundabout at the %s exit"), get_count_str(count_roundabout));
+                               ret = g_strdup_printf(_("Leave the roundabout at the %s"), get_exit_count_str(count_roundabout));
                                break;
                        case -2:
-                               ret = g_strdup_printf(_("then leave the roundabout at the %s exit"), get_count_str(count_roundabout));
+                               ret = g_strdup_printf(_("then leave the roundabout at the %s"), get_exit_count_str(count_roundabout));
                                break;
                        }
                        return ret;
@@ -1407,7 +1485,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                        }
 
                } else {
-                       d = g_strdup_printf("");
+                       d = g_strdup("");
                }
                break;
        default:
@@ -1415,7 +1493,7 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
        }
        if (cmd->itm->next) {
                int tellstreetname = 0;
-               char *destination = NULL; 
+               char *destination = NULL;
  
                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
@@ -1437,8 +1515,9 @@ show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigat
                else
                     tellstreetname = 1;
 
-               if(tellstreetname) 
+               if(nav->tell_street_name && tellstreetname)
                        destination=navigation_item_destination(cmd->itm, itm, " ");
+
                if (level != -2) {
                        /* TRANSLATORS: The first argument is strength, the second direction, the third distance and the fourth destination Example: 'Turn 'slightly' 'left' in '100 m' 'onto baker street' */
                        ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
@@ -1471,8 +1550,9 @@ show_next_maneuvers(struct navigation *nav, struct navigation_itm *itm, struct n
 {
        struct navigation_command *cur,*prev;
        int distance=itm->dest_length-cmd->itm->dest_length;
-       int l0_dist,level,dist,i,time;
-       char *ret,*old,*buf;
+       int level, dist, i, time;
+       int speech_time,time2nav;
+       char *ret,*old,*buf,*next;
 
        if (type != attr_navigation_speech) {
                return show_maneuver(nav, itm, cmd, type, 0); // We accumulate maneuvers only in speech navigation
@@ -1485,10 +1565,11 @@ show_next_maneuvers(struct navigation *nav, struct navigation_itm *itm, struct n
        }
 
        if (cmd->itm->told) {
-               return "";
+               return g_strdup("");
        }
 
        ret = show_maneuver(nav, itm, cmd, type, 0);
+       time2nav = navigation_time(itm,cmd->itm->prev);
        old = NULL;
 
        cur = cmd->next;
@@ -1496,14 +1577,22 @@ show_next_maneuvers(struct navigation *nav, struct navigation_itm *itm, struct n
        i = 0;
        while (cur && cur->itm) {
                // We don't merge more than 3 announcements...
-               if (i > 1) {
+               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);
+               speech_time = navit_speech_estimate(nav->navit,next);
+               g_free(next);
+
+               if (speech_time == -1) { // user didn't set cps
+                       speech_time = 30; // assume 3 seconds
+               }
 
                dist = prev->itm->dest_length - cur->itm->dest_length;
                time = navigation_time(prev->itm,cur->itm->prev);
 
-               if (time > 50) { // For now, we statically use 5 seconds...
+               if (time >= (speech_time + 30)) { // 3 seconds for understanding what has been said
                        break;
                }
 
@@ -1511,10 +1600,16 @@ show_next_maneuvers(struct navigation *nav, struct navigation_itm *itm, struct n
                buf = show_maneuver(nav, prev->itm, cur, type, 1);
                ret = g_strdup_printf("%s, %s", old, buf);
                g_free(buf);
-               g_free(old);
+               if (navit_speech_estimate(nav->navit,ret) > time2nav) {
+                       g_free(ret);
+                       ret = old;
+                       i = 2; // This will terminate the loop
+               } else {
+                       g_free(old);
+               }
 
                // If the two maneuvers are *really* close, we shouldn't tell the second one again, because TTS won't be fast enough
-               if (time <= 30) {
+               if (time <= speech_time) {
                        cur->itm->told = 1;
                }
 
@@ -1574,8 +1669,8 @@ navigation_call_callbacks(struct navigation *this_, int force_speech)
        }
 }
 
-void
-navigation_update(struct navigation *this_, struct route *route)
+static void
+navigation_update(struct navigation *this_, struct route *route, struct attr *attr)
 {
        struct map *map;
        struct map_rect *mr;
@@ -1583,11 +1678,19 @@ navigation_update(struct navigation *this_, struct route *route)
        struct item *sitem;                     /* Holds the corresponding item from the actual map */
        struct attr street_item,street_direction;
        struct navigation_itm *itm;
-       int incr=0,first=1;
+       int mode=0, incr=0, first=1;
+       if (attr->type != attr_route_status)
+               return;
 
-       if (! route)
+       dbg(1,"enter %d\n", mode);
+       if (attr->u.num == route_status_no_destination || attr->u.num == route_status_not_found || attr->u.num == route_status_path_done_new) 
+               navigation_flush(this_);
+       if (attr->u.num != route_status_path_done_new && attr->u.num != route_status_path_done_incremental)
+               return;
+               
+       if (! this_->route)
                return;
-       map=route_get_map(route);
+       map=route_get_map(this_->route);
        if (! map)
                return;
        mr=map_rect_new(map, NULL);
@@ -1595,6 +1698,12 @@ navigation_update(struct navigation *this_, struct route *route)
                return;
        dbg(1,"enter\n");
        while ((ritem=map_rect_get_item(mr))) {
+               if (ritem->type == type_route_start && this_->turn_around > -this_->turn_around_limit+1)
+                       this_->turn_around--;
+               if (ritem->type == type_route_start_reverse && this_->turn_around < this_->turn_around_limit)
+                       this_->turn_around++;
+               if (ritem->type != type_street_route)
+                       continue;
                if (first && item_attr_get(ritem, attr_street_item, &street_item)) {
                        first=0;
                        if (!item_attr_get(ritem, attr_direction, &street_direction))
@@ -1616,32 +1725,22 @@ navigation_update(struct navigation *this_, struct route *route)
                }
                navigation_itm_new(this_, ritem);
        }
+       dbg(2,"turn_around=%d\n", this_->turn_around);
        if (first) 
                navigation_destroy_itms_cmds(this_, NULL);
        else {
                if (! ritem) {
                        navigation_itm_new(this_, NULL);
-                       make_maneuvers(this_,route);
+                       make_maneuvers(this_,this_->route);
                }
                calculate_dest_distance(this_, incr);
-               dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
-               if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0) 
-                       this_->turn_around++;
-               else
-                       this_->turn_around--;
-               if (this_->turn_around > this_->turn_around_limit)
-                       this_->turn_around=this_->turn_around_limit;
-               else if (this_->turn_around < -this_->turn_around_limit+1)
-                       this_->turn_around=-this_->turn_around_limit+1;
-               dbg(2,"turn_around=%d\n", this_->turn_around);
-               this_->distance_last=this_->first->dest_length;
                profile(0,"end");
                navigation_call_callbacks(this_, FALSE);
        }
        map_rect_destroy(mr);
 }
 
-void
+static void
 navigation_flush(struct navigation *this_)
 {
        navigation_destroy_itms_cmds(this_, NULL);
@@ -1945,7 +2044,7 @@ navigation_map_get_item(struct map_rect_priv *priv)
                        ret->type=type_nav_destination;
                else {
                        if (priv->itm && priv->itm->prev && !(priv->itm->flags & AF_ROUNDABOUT) && (priv->itm->prev->flags & AF_ROUNDABOUT)) {
-                               
+                       
                                switch (((180+22)-priv->cmd->roundabout_delta)/45) {
                                case 0:
                                case 1:
@@ -2048,6 +2147,16 @@ navigation_map_new(struct map_methods *meth, struct attr **attrs)
        return ret;
 }
 
+void
+navigation_set_route(struct navigation *this_, struct route *route)
+{
+       struct attr callback;
+       this_->route=route;
+       this_->route_cb=callback_new_attr_1(callback_cast(navigation_update), attr_route_status, this_);
+       callback.type=attr_callback;
+       callback.u.callback=this_->route_cb;
+       route_add_attr(route, &callback);
+}
 
 void
 navigation_init(void)