9 #include "navigation.h"
13 #include "transform.h"
15 #include "projection.h"
20 #define _(STRING) gettext(STRING)
24 struct item_hash *hash;
25 struct navigation_itm *first;
26 struct navigation_itm *last;
27 struct navigation_command *cmd_first;
28 struct navigation_command *cmd_last;
29 struct callback_list *callback_speech;
30 struct callback_list *callback;
32 struct item item_last;
36 int announce[route_item_last-route_item_first+1][3];
40 struct navigation_command {
41 struct navigation_itm *itm;
42 struct navigation_command *next;
46 struct navigation_list {
47 struct navigation *nav;
48 struct navigation_command *cmd;
49 struct navigation_command *cmd_next;
50 struct navigation_itm *itm;
51 struct navigation_itm *itm_next;
67 navigation_new(struct mapset *ms)
70 struct navigation *ret=g_new0(struct navigation, 1);
72 ret->hash=item_hash_new();
73 ret->callback=callback_list_new();
74 ret->callback_speech=callback_list_new();
76 ret->distance_last=-2;
77 ret->distance_turn=50;
79 for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
80 for (i = 0 ; i < 3 ; i++) {
81 ret->announce[j][i]=-1;
89 navigation_set_mapset(struct navigation *this_, struct mapset *ms)
95 navigation_set_announce(struct navigation *this_, enum item_type type, int *level)
98 if (type < route_item_first || type > route_item_last) {
99 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
102 for (i = 0 ; i < 3 ; i++)
103 this_->announce[type-route_item_first][i]=level[i];
108 navigation_get_announce_level(struct navigation *this_, enum item_type type, int dist)
112 if (type < route_item_first || type > route_item_last)
114 for (i = 0 ; i < 3 ; i++) {
115 if (dist <= this_->announce[type-route_item_first][i])
121 struct navigation_itm {
132 struct navigation_itm *next;
133 struct navigation_itm *prev;
138 road_angle(struct coord *c1, struct coord *c2, int dir)
140 int ret=transform_get_angle_delta(c1, c2, dir);
141 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
146 round_distance(int dist)
169 dist=(dist+500)/1000;
172 dist=(dist+5000)/10000;
177 get_distance(int dist, enum attr_type type, int is_length)
179 if (type == attr_navigation_long) {
181 return g_strdup_printf(_("%d m"), dist);
183 return g_strdup_printf(_("in %d m"), dist);
187 return g_strdup_printf(_("%d meters"), dist);
189 return g_strdup_printf(_("in %d meters"), dist);
192 int rem=(dist/100)%10;
195 return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
197 return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
203 return g_strdup_printf(_("one kilometer"));
205 return g_strdup_printf(_("in one kilometer"));
208 return g_strdup_printf(_("two kilometers"));
210 return g_strdup_printf(_("in two kilometers"));
213 return g_strdup_printf(_("three kilometers"));
215 return g_strdup_printf(_("in three kilometers"));
218 return g_strdup_printf(_("four kilometers"));
220 return g_strdup_printf(_("in four kilometers"));
223 return g_strdup_printf(_("%d kilometers"), dist/1000);
225 return g_strdup_printf(_("in %d kilometers"), dist/1000);
230 navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *end)
232 struct navigation_itm *itm;
233 struct navigation_command *cmd;
234 dbg(2,"enter this_=%p end=%p\n", this_, end);
235 while (this_->first && this_->first != end) {
237 dbg(3,"destroying %p\n", itm);
238 item_hash_remove(this_->hash, &itm->item);
239 this_->first=itm->next;
241 this_->first->prev=NULL;
242 if (this_->cmd_first->itm == itm) {
243 cmd=this_->cmd_first;
244 this_->cmd_first=cmd->next;
251 if (! this_->first && end)
252 dbg(0,"end wrong\n");
256 static struct navigation_itm *
257 navigation_itm_new(struct navigation *this_, struct item *item, struct coord *start)
259 struct navigation_itm *ret=g_new0(struct navigation_itm, 1);
260 int l,i=0,a1,a2,dir=0;
267 item_hash_insert(this_->hash, item, ret);
268 mr=map_rect_new(item->map, NULL);
269 item=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
270 if (item_attr_get(item, attr_street_name, &attr))
271 ret->name1=g_strdup(attr.u.str);
272 if (item_attr_get(item, attr_street_name_systematic, &attr))
273 ret->name2=g_strdup(attr.u.str);
275 while (item_coord_get(item, &c[i], 1)) {
276 dbg(1, "coord %d 0x%x 0x%x\n", i, c[i].x ,c[i].y);
285 dbg(1,"count=%d\n", l);
288 if (start->x != c[0].x || start->y != c[0].y)
290 a1=road_angle(&c[0], &c[1], dir);
291 a2=road_angle(&c[l-1], &c[l], dir);
299 dbg(1,"i=%d a1 %d a2 %d '%s' '%s'\n", i, a1, a2, ret->name1, ret->name2);
300 map_rect_destroy(mr);
307 this_->last->next=ret;
308 ret->prev=this_->last;
310 dbg(1,"ret=%p\n", ret);
316 calculate_dest_distance(struct navigation *this_, int incr)
319 struct navigation_itm *next,*itm=this_->last;
320 dbg(1, "enter this_=%p, incr=%d\n", this_, incr);
323 dbg(2, "old values: (%p) time=%d lenght=%d\n", itm, itm->dest_length, itm->dest_time);
325 dbg(2, "old values: itm is null\n");
328 dbg(2, "itm values: time=%d lenght=%d\n", itm->length, itm->time);
329 dbg(2, "next values: (%p) time=%d lenght=%d\n", next, next->dest_length, next->dest_time);
330 itm->dest_length=next->dest_length+itm->length;
331 itm->dest_time=next->dest_time+itm->time;
332 dbg(2, "new values: time=%d lenght=%d\n", itm->dest_length, itm->dest_time);
338 itm->dest_length=len;
342 dbg(1,"len %d time %d\n", len, time);
346 is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
348 if (old->name1 && new->name1 && !strcmp(old->name1, new->name1)) {
349 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old->name2, new->name2, old->name1, new->name1);
352 if (old->name2 && new->name2 && !strcmp(old->name2, new->name2)) {
353 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old->name2, new->name2, old->name1, new->name1);
356 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old->name2, new->name2, old->name1, new->name1);
361 maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta)
363 dbg(1,"enter %p %p %p\n",old, new, delta);
364 if (new->item.type == type_ramp && old && (old->item.type == type_highway_land || old->item.type == type_highway_city)) {
365 dbg(1, "maneuver_required: new is ramp from highway: yes\n");
368 if (is_same_street2(old, new)) {
369 dbg(1, "maneuver_required: is_same_street: no\n");
373 if (old->crossings_end == 2) {
374 dbg(1, "maneuver_required: only 2 connections: no\n");
378 *delta=new->angle_start-old->angle_end;
383 if (*delta < 20 && *delta >-20) {
384 dbg(1, "maneuver_required: delta(%d) < 20: no\n", *delta);
387 dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
391 static struct navigation_command *
392 command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
394 struct navigation_command *ret=g_new0(struct navigation_command, 1);
398 this_->cmd_last->next=ret;
401 if (!this_->cmd_first)
402 this_->cmd_first=ret;
407 make_maneuvers(struct navigation *this_)
409 struct navigation_itm *itm, *last=NULL, *last_itm=NULL;
412 this_->cmd_last=NULL;
413 this_->cmd_first=NULL;
416 if (maneuver_required2(last_itm, itm, &delta)) {
417 command_new(this_, itm, delta);
427 show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
429 char *dir=_("right"),*strength="";
430 int distance=itm->dest_length-cmd->itm->dest_length;
432 int delta=cmd->delta;
434 char *arg[3],*str[3];
441 strength=_("easily ");
442 } else if (delta < 105) {
444 } else if (delta < 165) {
445 strength=_("strongly ");
447 dbg(1,"delta=%d\n", delta);
448 strength=_("unknown ");
450 if (type != attr_navigation_long_exact)
451 distance=round_distance(distance);
452 if (type == attr_navigation_speech) {
453 if (nav->turn_around)
454 return g_strdup(_("When possible, please turn around"));
455 level=navigation_get_announce_level(nav, itm->item.type, distance);
456 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->item.type);
460 d=get_distance(distance, type, 1);
461 ret=g_strdup_printf(_("Follow the road for the next %s"), d);
465 d=g_strdup(_("soon"));
468 d=get_distance(distance, type, 0);
471 d=g_strdup(_("now"));
474 d=g_strdup(_("error"));
476 if (cmd->itm->next) {
477 for (i = 0 ; i < 3 ; i++)
479 pos[0]=atoi(_("strength_pos"));
481 pos[1]=atoi(_("direction_pos"));
483 pos[2]=atoi(_("distance_pos"));
486 for (i = 0 ; i < 3 ; i++) {
487 if (pos[i] > 0 && pos[i] < 4) {
488 arg[pos[i]-1]=str[i];
493 ret=g_strdup_printf(_("Turn %s%s %s"), arg[0], arg[1], arg[2]);
496 ret=g_strdup_printf(_("You have reached your destination %s"), d);
502 navigation_list_item_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
504 struct navigation_list *this_=priv_data;
506 case attr_navigation_short:
507 case attr_navigation_long:
508 case attr_navigation_long_exact:
509 case attr_navigation_speech:
510 attr->u.str=show_maneuver(this_->nav, this_->itm, this_->cmd, attr_type);
517 struct item_methods navigation_list_item_methods = {
521 navigation_list_item_attr_get,
526 struct navigation_list *
527 navigation_list_new(struct navigation *this_)
529 struct navigation_list *ret=g_new0(struct navigation_list, 1);
531 ret->cmd_next=this_->cmd_first;
532 ret->itm_next=this_->first;
533 ret->item.meth=&navigation_list_item_methods;
534 ret->item.priv_data=ret;
539 navigation_list_get_item(struct navigation_list *this_)
541 if (!this_->cmd_next)
543 this_->cmd=this_->cmd_next;
544 this_->itm=this_->itm_next;
546 this_->str=show_maneuver(this_->nav, this_->itm, this_->cmd, mode);
548 this_->itm_next=this_->cmd->itm;
549 this_->cmd_next=this_->cmd->next;
556 navigation_list_destroy(struct navigation_list *this_)
562 navigation_call_callbacks(struct navigation *this_, int force_speech)
566 callback_list_call(this_->callback, 1, &p);
567 distance=round_distance(this_->first->dest_length-this_->cmd_first->itm->dest_length);
568 if (this_->turn_around) {
569 if (distance > this_->distance_turn) {
573 if (this_->distance_turn > 500)
574 this_->distance_turn*=2;
576 this_->distance_turn=500;
579 this_->distance_turn=50;
580 level=navigation_get_announce_level(this_, this_->first->item.type, distance);
581 if (level < this_->level_last) {
582 dbg(0,"level %d < %d\n", level, this_->level_last);
583 this_->level_last=level;
586 if (!item_is_equal(this_->cmd_first->itm->item, this_->item_last)) {
587 dbg(0,"item different\n");
588 this_->item_last=this_->cmd_first->itm->item;
593 this_->level_last=level;
594 dbg(0,"distance=%d level=%d type=0x%x\n", distance, level, this_->first->item.type);
595 callback_list_call(this_->callback_speech, 1, &p);
600 navigation_update(struct navigation *this_, struct route *route)
602 struct route_path_handle *rph;
603 struct route_path_segment *s;
604 struct navigation_itm *itm;
605 struct route_info *pos,*dst;
606 struct street_data *sd;
612 pos=route_get_pos(route);
613 dst=route_get_dst(route);
616 speedlist=route_get_speedlist(route);
617 len=route_info_length(pos, dst, 0);
618 dbg(2,"len pos,dst = %d\n", len);
620 len=route_info_length(pos, NULL, 0);
621 dbg(2,"len pos = %d\n", len);
624 sd=route_info_street(pos);
625 itm=item_hash_lookup(this_->hash, &sd->item);
626 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sd->item.id_hi, sd->item.id_lo, itm);
627 navigation_destroy_itms_cmds(this_, itm);
631 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, -1));
635 itm->time=route_time(speedlist, &sd->item, len);
636 dbg(2,"%p time = %d\n", itm, itm->time);
638 printf("not on track\n");
639 rph=route_path_open(route);
640 while((s=route_path_get_segment(rph))) {
641 itm=navigation_itm_new(this_, route_path_segment_get_item(s),route_path_segment_get_start(s));
642 itm->time=route_path_segment_get_time(s);
643 itm->length=route_path_segment_get_length(s);
646 len=route_info_length(NULL, dst, 0);
647 dbg(1, "end %d\n", len);
648 sd=route_info_street(dst);
649 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, 2));
651 itm->time=route_time(speedlist, &sd->item, len);
653 itm=navigation_itm_new(this_, NULL, NULL);
654 route_path_close(rph);
655 make_maneuvers(this_);
657 calculate_dest_distance(this_, incr);
658 dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
659 if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0)
660 this_->turn_around=1;
662 this_->turn_around=0;
663 dbg(2,"turn_around=%d\n", this_->turn_around);
664 this_->distance_last=this_->first->dest_length;
666 navigation_call_callbacks(this_, FALSE);
670 navigation_destroy(struct navigation *this_)
672 item_hash_destroy(this_->hash);
673 callback_list_destroy(this_->callback);
674 callback_list_destroy(this_->callback_speech);
679 navigation_register_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
681 if (type == attr_navigation_speech)
682 callback_list_add(this_->callback_speech, cb);
684 callback_list_add(this_->callback, cb);
689 navigation_unregister_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
691 if (type == attr_navigation_speech)
692 callback_list_remove_destroy(this_->callback_speech, cb);
694 callback_list_remove_destroy(this_->callback, cb);