9 #include "navigation.h"
13 #include "transform.h"
15 #include "projection.h"
21 #define _(STRING) gettext(STRING)
39 struct item_hash *hash;
40 struct navigation_itm *first;
41 struct navigation_itm *last;
42 struct navigation_command *cmd_first;
43 struct navigation_command *cmd_last;
44 struct callback_list *callback_speech;
45 struct callback_list *callback;
47 struct item item_last;
49 int turn_around_limit;
52 int announce[route_item_last-route_item_first+1][3];
56 struct navigation_command {
57 struct navigation_itm *itm;
58 struct navigation_command *next;
63 navigation_new(struct attr **attrs)
66 struct navigation *ret=g_new0(struct navigation, 1);
67 ret->hash=item_hash_new();
68 ret->callback=callback_list_new();
69 ret->callback_speech=callback_list_new();
71 ret->distance_last=-2;
72 ret->distance_turn=50;
73 ret->turn_around_limit=3;
75 for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
76 for (i = 0 ; i < 3 ; i++) {
77 ret->announce[j][i]=-1;
85 navigation_set_announce(struct navigation *this_, enum item_type type, int *level)
88 if (type < route_item_first || type > route_item_last) {
89 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
92 for (i = 0 ; i < 3 ; i++)
93 this_->announce[type-route_item_first][i]=level[i];
98 navigation_get_announce_level(struct navigation *this_, enum item_type type, int dist)
102 if (type < route_item_first || type > route_item_last)
104 for (i = 0 ; i < 3 ; i++) {
105 if (dist <= this_->announce[type-route_item_first][i])
111 struct navigation_itm {
122 struct navigation_itm *next;
123 struct navigation_itm *prev;
128 road_angle(struct coord *c1, struct coord *c2, int dir)
130 int ret=transform_get_angle_delta(c1, c2, dir);
131 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
136 round_distance(int dist)
159 dist=(dist+500)/1000;
162 dist=(dist+5000)/10000;
167 get_distance(int dist, enum attr_type type, int is_length)
169 if (type == attr_navigation_long) {
171 return g_strdup_printf(_("%d m"), dist);
173 return g_strdup_printf(_("in %d m"), dist);
177 return g_strdup_printf(_("%d meters"), dist);
179 return g_strdup_printf(_("in %d meters"), dist);
182 int rem=(dist/100)%10;
185 return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
187 return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
191 return g_strdup_printf(ngettext("one kilometer","%d kilometers", dist/1000), dist/1000);
193 return g_strdup_printf(ngettext("in one kilometer","in %d kilometers", dist/1000), dist/1000);
197 navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *end)
199 struct navigation_itm *itm;
200 struct navigation_command *cmd;
201 dbg(2,"enter this_=%p this_->first=%p this_->cmd_first=%p end=%p\n", this_, this_->first, this_->cmd_first, end);
202 if (this_->cmd_first)
203 dbg(2,"this_->cmd_first->itm=%p\n", this_->cmd_first->itm);
204 while (this_->first && this_->first != end) {
206 dbg(3,"destroying %p\n", itm);
207 item_hash_remove(this_->hash, &itm->item);
208 this_->first=itm->next;
210 this_->first->prev=NULL;
211 if (this_->cmd_first && this_->cmd_first->itm == itm->next) {
212 cmd=this_->cmd_first;
213 this_->cmd_first=cmd->next;
216 map_convert_free(itm->name1);
217 map_convert_free(itm->name2);
222 if (! this_->first && end)
223 dbg(0,"end wrong\n");
224 dbg(2,"ret this_->first=%p this_->cmd_first=%p\n",this_->first, this_->cmd_first);
228 navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
230 struct attr length, time;
231 if (! item_attr_get(ritem, attr_length, &length)) {
232 dbg(0,"no length\n");
235 if (! item_attr_get(ritem, attr_time, &time)) {
239 dbg(1,"length=%d time=%d\n", length.u.num, time.u.num);
240 itm->length=length.u.num;
241 itm->time=time.u.num;
244 static struct navigation_itm *
245 navigation_itm_new(struct navigation *this_, struct item *ritem)
247 struct navigation_itm *ret=g_new0(struct navigation_itm, 1);
250 struct attr street_item;
257 if (! item_attr_get(ritem, attr_street_item, &street_item)) {
258 dbg(0,"no street item\n");
261 sitem=street_item.u.item;
263 item_hash_insert(this_->hash, sitem, ret);
264 mr=map_rect_new(sitem->map, NULL);
265 sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo);
266 if (item_attr_get(sitem, attr_street_name, &attr))
267 ret->name1=map_convert_string(sitem->map,attr.u.str);
268 if (item_attr_get(sitem, attr_street_name_systematic, &attr))
269 ret->name2=map_convert_string(sitem->map,attr.u.str);
270 navigation_itm_update(ret, ritem);
272 while (item_coord_get(ritem, &c[i], 1)) {
273 dbg(1, "coord %d 0x%x 0x%x\n", i, c[i].x ,c[i].y);
282 dbg(1,"count=%d\n", l);
285 ret->angle_start=road_angle(&c[0], &c[1], 0);
286 ret->angle_end=road_angle(&c[l-1], &c[l], 0);
287 dbg(1,"i=%d start %d end %d '%s' '%s'\n", i, ret->angle_start, ret->angle_end, ret->name1, ret->name2);
288 map_rect_destroy(mr);
293 this_->last->next=ret;
294 ret->prev=this_->last;
296 dbg(1,"ret=%p\n", ret);
302 calculate_dest_distance(struct navigation *this_, int incr)
305 struct navigation_itm *next,*itm=this_->last;
306 dbg(1, "enter this_=%p, incr=%d\n", this_, incr);
309 dbg(2, "old values: (%p) time=%d lenght=%d\n", itm, itm->dest_length, itm->dest_time);
311 dbg(2, "old values: itm is null\n");
314 dbg(2, "itm values: time=%d lenght=%d\n", itm->length, itm->time);
315 dbg(2, "next values: (%p) time=%d lenght=%d\n", next, next->dest_length, next->dest_time);
316 itm->dest_length=next->dest_length+itm->length;
317 itm->dest_time=next->dest_time+itm->time;
318 dbg(2, "new values: time=%d lenght=%d\n", itm->dest_length, itm->dest_time);
324 itm->dest_length=len;
328 dbg(1,"len %d time %d\n", len, time);
332 is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
334 if (old->name1 && new->name1 && !strcmp(old->name1, new->name1)) {
335 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old->name2, new->name2, old->name1, new->name1);
338 if (old->name2 && new->name2 && !strcmp(old->name2, new->name2)) {
339 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old->name2, new->name2, old->name1, new->name1);
342 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old->name2, new->name2, old->name1, new->name1);
347 maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta)
349 dbg(1,"enter %p %p %p\n",old, new, delta);
350 if (new->item.type == old->item.type || (new->item.type != type_ramp && old->item.type != type_ramp)) {
351 if (is_same_street2(old, new)) {
352 dbg(1, "maneuver_required: is_same_street: no\n");
356 dbg(1, "maneuver_required: old or new is ramp\n");
358 if (old->crossings_end == 2) {
359 dbg(1, "maneuver_required: only 2 connections: no\n");
363 *delta=new->angle_start-old->angle_end;
368 dbg(1,"delta=%d-%d=%d\n", new->angle_start, old->angle_end, *delta);
369 if (*delta < 20 && *delta >-20) {
370 dbg(1, "maneuver_required: delta(%d) < 20: no\n", *delta);
373 dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
377 static struct navigation_command *
378 command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
380 struct navigation_command *ret=g_new0(struct navigation_command, 1);
381 dbg(1,"enter this_=%p itm=%p delta=%d\n", this_, itm, delta);
385 this_->cmd_last->next=ret;
388 if (!this_->cmd_first)
389 this_->cmd_first=ret;
394 make_maneuvers(struct navigation *this_)
396 struct navigation_itm *itm, *last=NULL, *last_itm=NULL;
399 this_->cmd_last=NULL;
400 this_->cmd_first=NULL;
403 if (maneuver_required2(last_itm, itm, &delta)) {
404 command_new(this_, itm, delta);
414 contains_suffix(char *name, char *suffix)
418 if (strlen(name) < strlen(suffix))
420 return !strcasecmp(name+strlen(name)-strlen(suffix), suffix);
424 replace_suffix(char *name, char *search, char *replace)
426 int len=strlen(name)-strlen(search);
427 char *ret=g_malloc(len+strlen(replace)+1);
428 strncpy(ret, name, len);
429 strcpy(ret+len, replace);
435 navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *next, char *prefix)
437 char *ret=NULL,*name1,*sep,*name2;
441 if(!itm->name1 && !itm->name2 && itm->item.type == type_ramp) {
442 dbg(1,">> Next is ramp %lx current is %lx \n", itm->item.type, next->item.type);
444 if(next->item.type == type_ramp)
446 if(itm->item.type == type_highway_city || itm->item.type == type_highway_land )
447 return g_strdup_printf("%s%s",prefix,_("exit"));
449 return g_strdup_printf("%s%s",prefix,_("ramp"));
452 if (!itm->name1 && !itm->name2)
457 for (i = 0 ; i < sizeof(suffixes)/sizeof(suffixes[0]) ; i++) {
458 if (contains_suffix(itm->name1,suffixes[i].fullname)) {
460 name1=g_strdup(itm->name1);
463 if (contains_suffix(itm->name1,suffixes[i].abbrev)) {
465 name1=replace_suffix(itm->name1, suffixes[i].abbrev, suffixes[i].fullname);
478 /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name */
479 ret=g_strdup_printf(_("%sinto the street %s%s%s"),prefix,itm->name1, sep, name2);
482 /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name. Male form. The stuff after | doesn't have to be included */
483 ret=g_strdup_printf(_("%sinto the %s%s%s|male form"),prefix,name1, sep, name2);
486 /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name. Female form. The stuff after | doesn't have to be included */
487 ret=g_strdup_printf(_("%sinto the %s%s%s|female form"),prefix,name1, sep, name2);
490 /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name. Neutral form. The stuff after | doesn't have to be included */
491 ret=g_strdup_printf(_("%sinto the %s%s%s|neutral form"),prefix,name1, sep, name2);
497 ret=g_strdup_printf(_("into the %s"),itm->name2);
516 show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
518 char *dir=_("right"),*strength="";
519 int distance=itm->dest_length-cmd->itm->dest_length;
521 int delta=cmd->delta;
529 strength=_("easily ");
530 } else if (delta < 105) {
532 } else if (delta < 165) {
533 strength=_("strongly ");
535 dbg(1,"delta=%d\n", delta);
536 strength=_("unknown ");
538 if (type != attr_navigation_long_exact)
539 distance=round_distance(distance);
540 if (type == attr_navigation_speech) {
541 if (nav->turn_around && nav->turn_around == nav->turn_around_limit)
542 return g_strdup(_("When possible, please turn around"));
543 level=navigation_get_announce_level(nav, itm->item.type, distance);
544 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->item.type);
548 d=get_distance(distance, type, 1);
549 ret=g_strdup_printf(_("Follow the road for the next %s"), d);
553 d=g_strdup(_("soon"));
556 d=get_distance(distance, type, 0);
559 d=g_strdup(_("now"));
562 d=g_strdup(_("error"));
564 if (cmd->itm->next) {
565 int tellstreetname = 0;
566 char *destination = NULL;
568 if(type == attr_navigation_speech) { // In voice mode
569 // In Voice Mode only tell the street name in level 1 or in level 0 if level 1
572 if (level == 1) { // we are close to the intersection
573 cmd->itm->told = 1; // remeber to be checked when we turn
574 tellstreetname = 1; // Ok so we tell the name of the street
578 if(cmd->itm->told == 0) // we are write at the intersection
581 cmd->itm->told = 0; // reset just in case we come to the same street again
589 destination=navigation_item_destination(cmd->itm, itm, " ");
590 /* 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' */
591 ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
594 ret=g_strdup_printf(_("You have reached your destination %s"), d);
600 navigation_call_callbacks(struct navigation *this_, int force_speech)
602 int distance, level = 0;
604 if (!this_->cmd_first)
606 callback_list_call(this_->callback, 1, &p);
607 dbg(1,"force_speech=%d turn_around=%d turn_around_limit=%d\n", force_speech, this_->turn_around, this_->turn_around_limit);
608 distance=round_distance(this_->first->dest_length-this_->cmd_first->itm->dest_length);
609 if (this_->turn_around_limit && this_->turn_around == this_->turn_around_limit) {
610 dbg(1,"distance=%d distance_turn=%d\n", distance, this_->distance_turn);
611 while (distance > this_->distance_turn) {
615 if (this_->distance_turn >= 500)
616 this_->distance_turn*=2;
618 this_->distance_turn=500;
620 } else if (!this_->turn_around_limit || this_->turn_around == -this_->turn_around_limit+1) {
621 this_->distance_turn=50;
622 level=navigation_get_announce_level(this_, this_->first->item.type, distance);
623 if (level < this_->level_last) {
624 dbg(1,"level %d < %d\n", level, this_->level_last);
625 this_->level_last=level;
628 if (!item_is_equal(this_->cmd_first->itm->item, this_->item_last)) {
629 dbg(1,"item different\n");
630 this_->item_last=this_->cmd_first->itm->item;
635 this_->level_last=level;
636 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, this_->first->item.type);
637 callback_list_call(this_->callback_speech, 1, &p);
642 navigation_update(struct navigation *this_, struct route *route)
646 struct item *ritem,*sitem;
647 struct attr street_item;
648 struct navigation_itm *itm;
653 map=route_get_map(route);
656 mr=map_rect_new(map, NULL);
660 ritem=map_rect_get_item(mr);
662 if (item_attr_get(ritem, attr_street_item, &street_item)) {
663 sitem=street_item.u.item;
664 dbg(1,"sitem=%p\n", sitem);
665 itm=item_hash_lookup(this_->hash, sitem);
666 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sitem->id_hi, sitem->id_lo, itm);
667 navigation_destroy_itms_cmds(this_, itm);
670 navigation_itm_update(itm, ritem);
672 dbg(1,"not on track\n");
675 navigation_itm_new(this_, ritem);
676 ritem=map_rect_get_item(mr);
678 itm=navigation_itm_new(this_, NULL);
679 make_maneuvers(this_);
682 dbg(0,"no street_item\n");
683 calculate_dest_distance(this_, incr);
684 dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
685 if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0)
686 this_->turn_around++;
688 this_->turn_around--;
689 if (this_->turn_around > this_->turn_around_limit)
690 this_->turn_around=this_->turn_around_limit;
691 else if (this_->turn_around < -this_->turn_around_limit+1)
692 this_->turn_around=-this_->turn_around_limit+1;
693 dbg(2,"turn_around=%d\n", this_->turn_around);
694 this_->distance_last=this_->first->dest_length;
696 navigation_call_callbacks(this_, FALSE);
698 navigation_destroy_itms_cmds(this_, NULL);
699 map_rect_destroy(mr);
702 struct route_path_handle *rph;
703 struct route_path_segment *s;
704 struct navigation_itm *itm;
705 struct route_info *pos,*dst;
706 struct street_data *sd;
712 pos=route_get_pos(route);
713 dst=route_get_dst(route);
716 speedlist=route_get_speedlist(route);
717 len=route_info_length(pos, dst, 0);
718 dbg(2,"len pos,dst = %d\n", len);
720 len=route_info_length(pos, NULL, 0);
721 dbg(2,"len pos = %d\n", len);
724 sd=route_info_street(pos);
725 itm=item_hash_lookup(this_->hash, &sd->item);
726 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sd->item.id_hi, sd->item.id_lo, itm);
727 navigation_destroy_itms_cmds(this_, itm);
731 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, -1));
735 itm->time=route_time(speedlist, &sd->item, len);
736 dbg(2,"%p time = %d\n", itm, itm->time);
738 printf("not on track\n");
739 rph=route_path_open(route);
741 while((s=route_path_get_segment(rph))) {
742 itm=navigation_itm_new(this_, route_path_segment_get_item(s),route_path_segment_get_start(s));
743 itm->time=route_path_segment_get_time(s);
744 itm->length=route_path_segment_get_length(s);
746 route_path_close(rph);
749 len=route_info_length(NULL, dst, 0);
750 dbg(1, "end %d\n", len);
751 sd=route_info_street(dst);
752 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, 2));
754 itm->time=route_time(speedlist, &sd->item, len);
756 itm=navigation_itm_new(this_, NULL, NULL);
757 make_maneuvers(this_);
759 calculate_dest_distance(this_, incr);
760 dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
761 if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0)
762 this_->turn_around=1;
764 this_->turn_around=0;
765 dbg(2,"turn_around=%d\n", this_->turn_around);
766 this_->distance_last=this_->first->dest_length;
768 navigation_call_callbacks(this_, FALSE);
773 navigation_flush(struct navigation *this_)
775 navigation_destroy_itms_cmds(this_, NULL);
780 navigation_destroy(struct navigation *this_)
782 navigation_flush(this_);
783 item_hash_destroy(this_->hash);
784 callback_list_destroy(this_->callback);
785 callback_list_destroy(this_->callback_speech);
790 navigation_register_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
792 if (type == attr_navigation_speech)
793 callback_list_add(this_->callback_speech, cb);
795 callback_list_add(this_->callback, cb);
800 navigation_unregister_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
802 if (type == attr_navigation_speech)
803 callback_list_remove_destroy(this_->callback_speech, cb);
805 callback_list_remove_destroy(this_->callback, cb);
809 navigation_get_map(struct navigation *this_)
811 struct attr navigation_attr;
812 struct attr data_attr;
813 struct attr *attrs_navigation[]={&navigation_attr, &data_attr, NULL};
814 navigation_attr.type=attr_navigation;
815 navigation_attr.u.navigation=this_;
816 data_attr.type=attr_data;
820 this_->map=map_new("navigation",attrs_navigation);
825 struct navigation *navigation;
828 struct map_rect_priv {
829 struct navigation *nav;
830 struct navigation_command *cmd;
831 struct navigation_command *cmd_next;
832 struct navigation_itm *itm;
833 struct navigation_itm *itm_next;
838 navigation_map_item_coord_get(void *priv_data, struct coord *c, int count)
844 navigation_map_item_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
846 struct map_rect_priv *this_=priv_data;
847 attr->type=attr_type;
849 case attr_navigation_short:
850 case attr_navigation_long:
851 case attr_navigation_long_exact:
852 case attr_navigation_speech:
853 attr->u.str=show_maneuver(this_->nav, this_->itm, this_->cmd, attr_type);
856 attr->u.num=this_->itm->dest_length-this_->cmd->itm->dest_length;
859 attr->u.num=this_->itm->dest_time-this_->cmd->itm->dest_time;
861 case attr_destination_length:
862 attr->u.num=this_->itm->dest_length;
864 case attr_destination_time:
865 attr->u.num=this_->itm->dest_time;
868 attr->type=attr_none;
873 static struct item_methods navigation_map_item_methods = {
875 navigation_map_item_coord_get,
877 navigation_map_item_attr_get,
882 navigation_map_destroy(struct map_priv *priv)
887 static struct map_rect_priv *
888 navigation_map_rect_new(struct map_priv *priv, struct map_selection *sel)
890 struct navigation *nav=priv->navigation;
891 struct map_rect_priv *ret=g_new0(struct map_rect_priv, 1);
893 ret->cmd_next=nav->cmd_first;
894 ret->itm_next=nav->first;
895 ret->item.meth=&navigation_map_item_methods;
896 ret->item.priv_data=ret;
901 navigation_map_rect_destroy(struct map_rect_priv *priv)
907 navigation_map_get_item(struct map_rect_priv *priv)
914 priv->cmd=priv->cmd_next;
915 priv->itm=priv->itm_next;
916 priv->itm_next=priv->cmd->itm;
917 priv->cmd_next=priv->cmd->next;
919 delta=priv->cmd->delta;
920 dbg(1,"delta=%d\n", delta);
924 ret->type=type_nav_left_1;
925 else if (delta < 105)
926 ret->type=type_nav_left_2;
927 else if (delta < 165)
928 ret->type=type_nav_left_3;
933 ret->type=type_nav_right_1;
934 else if (delta < 105)
935 ret->type=type_nav_right_2;
936 else if (delta < 165)
937 ret->type=type_nav_right_3;
941 dbg(1,"type=%d\n", ret->type);
946 navigation_map_get_item_byid(struct map_rect_priv *priv, int id_hi, int id_lo)
952 static struct map_methods navigation_map_meth = {
955 navigation_map_destroy,
956 navigation_map_rect_new,
957 navigation_map_rect_destroy,
958 navigation_map_get_item,
959 navigation_map_get_item_byid,
965 static struct map_priv *
966 navigation_map_new(struct map_methods *meth, struct attr **attrs)
968 struct map_priv *ret;
969 struct attr *navigation_attr;
971 navigation_attr=attr_search(attrs, NULL, attr_navigation);
972 if (! navigation_attr)
974 ret=g_new0(struct map_priv, 1);
975 *meth=navigation_map_meth;
976 ret->navigation=navigation_attr->u.navigation;
983 navigation_init(void)
985 plugin_register_map_type("navigation", navigation_map_new);