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;
59 navigation_new(struct mapset *ms)
62 struct navigation *ret=g_new0(struct navigation, 1);
64 ret->hash=item_hash_new();
65 ret->callback=callback_list_new();
66 ret->callback_speech=callback_list_new();
68 ret->distance_last=-2;
69 ret->distance_turn=50;
71 for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
72 for (i = 0 ; i < 3 ; i++) {
73 ret->announce[j][i]=-1;
81 navigation_set_mapset(struct navigation *this_, struct mapset *ms)
87 navigation_set_announce(struct navigation *this_, enum item_type type, int *level)
90 if (type < route_item_first || type > route_item_last) {
91 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
94 for (i = 0 ; i < 3 ; i++)
95 this_->announce[type-route_item_first][i]=level[i];
100 navigation_get_announce_level(struct navigation *this_, enum item_type type, int dist)
104 if (type < route_item_first || type > route_item_last)
106 for (i = 0 ; i < 3 ; i++) {
107 if (dist <= this_->announce[type-route_item_first][i])
113 struct navigation_itm {
124 struct navigation_itm *next;
125 struct navigation_itm *prev;
130 road_angle(struct coord *c1, struct coord *c2, int dir)
132 int ret=transform_get_angle_delta(c1, c2, dir);
133 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
138 round_distance(int dist)
161 dist=(dist+500)/1000;
164 dist=(dist+5000)/10000;
169 get_distance(int dist, enum attr_type type, int is_length)
171 if (type == attr_navigation_long) {
173 return g_strdup_printf(_("%d m"), dist);
175 return g_strdup_printf(_("in %d m"), dist);
179 return g_strdup_printf(_("%d meters"), dist);
181 return g_strdup_printf(_("in %d meters"), dist);
184 int rem=(dist/100)%10;
187 return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
189 return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
193 return g_strdup_printf(ngettext("one kilometer","%d kilometers", dist/1000), dist/1000);
195 return g_strdup_printf(ngettext("in one kilometer","in %d kilometers", dist/1000), dist/1000);
199 navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *end)
201 struct navigation_itm *itm;
202 struct navigation_command *cmd;
203 dbg(2,"enter this_=%p end=%p\n", this_, end);
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) {
212 cmd=this_->cmd_first;
213 this_->cmd_first=cmd->next;
220 if (! this_->first && end)
221 dbg(0,"end wrong\n");
225 static struct navigation_itm *
226 navigation_itm_new(struct navigation *this_, struct item *item, struct coord *start)
228 struct navigation_itm *ret=g_new0(struct navigation_itm, 1);
229 int l,i=0,a1,a2,dir=0;
236 item_hash_insert(this_->hash, item, ret);
237 mr=map_rect_new(item->map, NULL);
238 item=map_rect_get_item_byid(mr, item->id_hi, item->id_lo);
239 if (item_attr_get(item, attr_street_name, &attr))
240 ret->name1=g_strdup(attr.u.str);
241 if (item_attr_get(item, attr_street_name_systematic, &attr))
242 ret->name2=g_strdup(attr.u.str);
244 while (item_coord_get(item, &c[i], 1)) {
245 dbg(1, "coord %d 0x%x 0x%x\n", i, c[i].x ,c[i].y);
254 dbg(1,"count=%d\n", l);
257 if (start->x != c[0].x || start->y != c[0].y)
259 a1=road_angle(&c[0], &c[1], dir);
260 a2=road_angle(&c[l-1], &c[l], dir);
268 dbg(1,"i=%d dir=%d a1 %d a2 %d '%s' '%s'\n", i, dir, a1, a2, ret->name1, ret->name2);
269 map_rect_destroy(mr);
276 this_->last->next=ret;
277 ret->prev=this_->last;
279 dbg(1,"ret=%p\n", ret);
285 calculate_dest_distance(struct navigation *this_, int incr)
288 struct navigation_itm *next,*itm=this_->last;
289 dbg(1, "enter this_=%p, incr=%d\n", this_, incr);
292 dbg(2, "old values: (%p) time=%d lenght=%d\n", itm, itm->dest_length, itm->dest_time);
294 dbg(2, "old values: itm is null\n");
297 dbg(2, "itm values: time=%d lenght=%d\n", itm->length, itm->time);
298 dbg(2, "next values: (%p) time=%d lenght=%d\n", next, next->dest_length, next->dest_time);
299 itm->dest_length=next->dest_length+itm->length;
300 itm->dest_time=next->dest_time+itm->time;
301 dbg(2, "new values: time=%d lenght=%d\n", itm->dest_length, itm->dest_time);
307 itm->dest_length=len;
311 dbg(1,"len %d time %d\n", len, time);
315 is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
317 if (old->name1 && new->name1 && !strcmp(old->name1, new->name1)) {
318 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old->name2, new->name2, old->name1, new->name1);
321 if (old->name2 && new->name2 && !strcmp(old->name2, new->name2)) {
322 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old->name2, new->name2, old->name1, new->name1);
325 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old->name2, new->name2, old->name1, new->name1);
330 maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta)
332 dbg(1,"enter %p %p %p\n",old, new, delta);
333 if (new->item.type != old->item.type && (new->item.type == type_ramp || old->item.type == type_ramp)) {
334 dbg(1, "maneuver_required: old or new is ramp\n");
337 if (is_same_street2(old, new)) {
338 dbg(1, "maneuver_required: is_same_street: no\n");
342 if (old->crossings_end == 2) {
343 dbg(1, "maneuver_required: only 2 connections: no\n");
347 *delta=new->angle_start-old->angle_end;
352 dbg(1,"delta=%d-%d=%d\n", new->angle_start, old->angle_end, *delta);
353 if (*delta < 20 && *delta >-20) {
354 dbg(1, "maneuver_required: delta(%d) < 20: no\n", *delta);
357 dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
361 static struct navigation_command *
362 command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
364 struct navigation_command *ret=g_new0(struct navigation_command, 1);
368 this_->cmd_last->next=ret;
371 if (!this_->cmd_first)
372 this_->cmd_first=ret;
377 make_maneuvers(struct navigation *this_)
379 struct navigation_itm *itm, *last=NULL, *last_itm=NULL;
382 this_->cmd_last=NULL;
383 this_->cmd_first=NULL;
386 if (maneuver_required2(last_itm, itm, &delta)) {
387 command_new(this_, itm, delta);
397 show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
399 char *dir=_("right"),*strength="";
400 int distance=itm->dest_length-cmd->itm->dest_length;
402 int delta=cmd->delta;
410 strength=_("easily ");
411 } else if (delta < 105) {
413 } else if (delta < 165) {
414 strength=_("strongly ");
416 dbg(1,"delta=%d\n", delta);
417 strength=_("unknown ");
419 if (type != attr_navigation_long_exact)
420 distance=round_distance(distance);
421 if (type == attr_navigation_speech) {
422 if (nav->turn_around)
423 return g_strdup(_("When possible, please turn around"));
424 level=navigation_get_announce_level(nav, itm->item.type, distance);
425 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->item.type);
429 d=get_distance(distance, type, 1);
430 ret=g_strdup_printf(_("Follow the road for the next %s"), d);
434 d=g_strdup(_("soon"));
437 d=get_distance(distance, type, 0);
440 d=g_strdup(_("now"));
443 d=g_strdup(_("error"));
445 if (cmd->itm->next) {
446 /* TRANSLATORS: The first argument is strength, the second direction and the third distance */
447 ret=g_strdup_printf(_("Turn %1$s%2$s %3$s"), strength, dir, d);
450 ret=g_strdup_printf(_("You have reached your destination %s"), d);
456 navigation_list_item_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
458 struct navigation_list *this_=priv_data;
459 attr->type=attr_type;
461 case attr_navigation_short:
462 case attr_navigation_long:
463 case attr_navigation_long_exact:
464 case attr_navigation_speech:
465 attr->u.str=show_maneuver(this_->nav, this_->itm, this_->cmd, attr_type);
468 attr->u.num=this_->itm->dest_length-this_->cmd->itm->dest_length;
471 attr->u.num=(this_->itm->dest_time-this_->cmd->itm->dest_time)/10;
473 case attr_destination_length:
474 attr->u.num=this_->itm->dest_length;
476 case attr_destination_time:
477 attr->u.num=this_->itm->dest_time/10;
480 attr->type=attr_none;
485 struct item_methods navigation_list_item_methods = {
489 navigation_list_item_attr_get,
494 struct navigation_list *
495 navigation_list_new(struct navigation *this_)
497 struct navigation_list *ret=g_new0(struct navigation_list, 1);
499 ret->cmd_next=this_->cmd_first;
500 ret->itm_next=this_->first;
501 ret->item.meth=&navigation_list_item_methods;
502 ret->item.priv_data=ret;
507 navigation_list_get_item(struct navigation_list *this_)
509 if (!this_->cmd_next)
511 this_->cmd=this_->cmd_next;
512 this_->itm=this_->itm_next;
514 this_->str=show_maneuver(this_->nav, this_->itm, this_->cmd, mode);
516 this_->itm_next=this_->cmd->itm;
517 this_->cmd_next=this_->cmd->next;
524 navigation_list_destroy(struct navigation_list *this_)
530 navigation_call_callbacks(struct navigation *this_, int force_speech)
532 int distance, level = 0;
534 if (!this_->cmd_first)
536 callback_list_call(this_->callback, 1, &p);
537 distance=round_distance(this_->first->dest_length-this_->cmd_first->itm->dest_length);
538 if (this_->turn_around) {
539 if (distance > this_->distance_turn) {
543 if (this_->distance_turn > 500)
544 this_->distance_turn*=2;
546 this_->distance_turn=500;
549 this_->distance_turn=50;
550 level=navigation_get_announce_level(this_, this_->first->item.type, distance);
551 if (level < this_->level_last) {
552 dbg(0,"level %d < %d\n", level, this_->level_last);
553 this_->level_last=level;
556 if (!item_is_equal(this_->cmd_first->itm->item, this_->item_last)) {
557 dbg(0,"item different\n");
558 this_->item_last=this_->cmd_first->itm->item;
563 this_->level_last=level;
564 dbg(0,"distance=%d level=%d type=0x%x\n", distance, level, this_->first->item.type);
565 callback_list_call(this_->callback_speech, 1, &p);
570 navigation_update(struct navigation *this_, struct route *route)
572 struct route_path_handle *rph;
573 struct route_path_segment *s;
574 struct navigation_itm *itm;
575 struct route_info *pos,*dst;
576 struct street_data *sd;
582 pos=route_get_pos(route);
583 dst=route_get_dst(route);
586 speedlist=route_get_speedlist(route);
587 len=route_info_length(pos, dst, 0);
588 dbg(2,"len pos,dst = %d\n", len);
590 len=route_info_length(pos, NULL, 0);
591 dbg(2,"len pos = %d\n", len);
594 sd=route_info_street(pos);
595 itm=item_hash_lookup(this_->hash, &sd->item);
596 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sd->item.id_hi, sd->item.id_lo, itm);
597 navigation_destroy_itms_cmds(this_, itm);
601 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, -1));
605 itm->time=route_time(speedlist, &sd->item, len);
606 dbg(2,"%p time = %d\n", itm, itm->time);
608 printf("not on track\n");
609 rph=route_path_open(route);
611 while((s=route_path_get_segment(rph))) {
612 itm=navigation_itm_new(this_, route_path_segment_get_item(s),route_path_segment_get_start(s));
613 itm->time=route_path_segment_get_time(s);
614 itm->length=route_path_segment_get_length(s);
616 route_path_close(rph);
619 len=route_info_length(NULL, dst, 0);
620 dbg(1, "end %d\n", len);
621 sd=route_info_street(dst);
622 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, 2));
624 itm->time=route_time(speedlist, &sd->item, len);
626 itm=navigation_itm_new(this_, NULL, NULL);
627 make_maneuvers(this_);
629 calculate_dest_distance(this_, incr);
630 dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
631 if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0)
632 this_->turn_around=1;
634 this_->turn_around=0;
635 dbg(2,"turn_around=%d\n", this_->turn_around);
636 this_->distance_last=this_->first->dest_length;
638 navigation_call_callbacks(this_, FALSE);
642 navigation_destroy(struct navigation *this_)
644 item_hash_destroy(this_->hash);
645 callback_list_destroy(this_->callback);
646 callback_list_destroy(this_->callback_speech);
651 navigation_register_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
653 if (type == attr_navigation_speech)
654 callback_list_add(this_->callback_speech, cb);
656 callback_list_add(this_->callback, cb);
661 navigation_unregister_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
663 if (type == attr_navigation_speech)
664 callback_list_remove_destroy(this_->callback_speech, cb);
666 callback_list_remove_destroy(this_->callback, cb);