2 * Navit, a modular navigation system.
3 * Copyright (C) 2005-2008 Navit Team
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License
7 * version 2 as published by the Free Software Foundation.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the
16 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17 * Boston, MA 02110-1301, USA.
28 #include "navigation.h"
32 #include "transform.h"
34 #include "projection.h"
40 #define _(STRING) gettext(STRING)
58 struct item_hash *hash;
59 struct navigation_itm *first;
60 struct navigation_itm *last;
61 struct navigation_command *cmd_first;
62 struct navigation_command *cmd_last;
63 struct callback_list *callback_speech;
64 struct callback_list *callback;
66 struct item item_last;
68 int turn_around_limit;
71 int announce[route_item_last-route_item_first+1][3];
75 struct navigation_command {
76 struct navigation_itm *itm;
77 struct navigation_command *next;
82 navigation_new(struct attr **attrs)
85 struct navigation *ret=g_new0(struct navigation, 1);
86 ret->hash=item_hash_new();
87 ret->callback=callback_list_new();
88 ret->callback_speech=callback_list_new();
90 ret->distance_last=-2;
91 ret->distance_turn=50;
92 ret->turn_around_limit=3;
94 for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
95 for (i = 0 ; i < 3 ; i++) {
96 ret->announce[j][i]=-1;
104 navigation_set_announce(struct navigation *this_, enum item_type type, int *level)
107 if (type < route_item_first || type > route_item_last) {
108 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
111 for (i = 0 ; i < 3 ; i++)
112 this_->announce[type-route_item_first][i]=level[i];
117 navigation_get_announce_level(struct navigation *this_, enum item_type type, int dist)
121 if (type < route_item_first || type > route_item_last)
123 for (i = 0 ; i < 3 ; i++) {
124 if (dist <= this_->announce[type-route_item_first][i])
130 struct navigation_itm {
145 struct navigation_itm *next;
146 struct navigation_itm *prev;
151 road_angle(struct coord *c1, struct coord *c2, int dir)
153 int ret=transform_get_angle_delta(c1, c2, dir);
154 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
159 round_distance(int dist)
182 dist=(dist+500)/1000;
185 dist=(dist+5000)/10000;
190 get_distance(int dist, enum attr_type type, int is_length)
192 if (type == attr_navigation_long) {
194 return g_strdup_printf(_("%d m"), dist);
196 return g_strdup_printf(_("in %d m"), dist);
200 return g_strdup_printf(_("%d meters"), dist);
202 return g_strdup_printf(_("in %d meters"), dist);
205 int rem=(dist/100)%10;
208 return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
210 return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
214 return g_strdup_printf(ngettext("one kilometer","%d kilometers", dist/1000), dist/1000);
216 return g_strdup_printf(ngettext("in one kilometer","in %d kilometers", dist/1000), dist/1000);
220 navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *end)
222 struct navigation_itm *itm;
223 struct navigation_command *cmd;
224 dbg(2,"enter this_=%p this_->first=%p this_->cmd_first=%p end=%p\n", this_, this_->first, this_->cmd_first, end);
225 if (this_->cmd_first)
226 dbg(2,"this_->cmd_first->itm=%p\n", this_->cmd_first->itm);
227 while (this_->first && this_->first != end) {
229 dbg(3,"destroying %p\n", itm);
230 item_hash_remove(this_->hash, &itm->item);
231 this_->first=itm->next;
233 this_->first->prev=NULL;
234 if (this_->cmd_first && this_->cmd_first->itm == itm->next) {
235 cmd=this_->cmd_first;
236 this_->cmd_first=cmd->next;
239 map_convert_free(itm->name1);
240 map_convert_free(itm->name2);
245 if (! this_->first && end)
246 dbg(0,"end wrong\n");
247 dbg(2,"ret this_->first=%p this_->cmd_first=%p\n",this_->first, this_->cmd_first);
251 navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
253 struct attr length, time, straight;
254 if (! item_attr_get(ritem, attr_length, &length)) {
255 dbg(0,"no length\n");
258 if (! item_attr_get(ritem, attr_time, &time)) {
263 if (item_attr_get(ritem, attr_route_follow_straight, &straight)) {
264 itm->straight = straight.u.num;
269 dbg(1,"length=%d time=%d\n", length.u.num, time.u.num);
270 itm->length=length.u.num;
271 itm->time=time.u.num;
274 static struct navigation_itm *
275 navigation_itm_new(struct navigation *this_, struct item *ritem)
277 struct navigation_itm *ret=g_new0(struct navigation_itm, 1);
280 struct attr street_item,direction;
287 if (! item_attr_get(ritem, attr_street_item, &street_item)) {
288 dbg(0,"no street item\n");
291 if (item_attr_get(ritem, attr_direction, &direction))
292 ret->direction=direction.u.num;
295 sitem=street_item.u.item;
297 item_hash_insert(this_->hash, sitem, ret);
298 mr=map_rect_new(sitem->map, NULL);
299 sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo);
300 if (item_attr_get(sitem, attr_street_name, &attr))
301 ret->name1=map_convert_string(sitem->map,attr.u.str);
302 if (item_attr_get(sitem, attr_street_name_systematic, &attr))
303 ret->name2=map_convert_string(sitem->map,attr.u.str);
304 navigation_itm_update(ret, ritem);
306 while (item_coord_get(ritem, &c[i], 1)) {
307 dbg(1, "coord %d 0x%x 0x%x\n", i, c[i].x ,c[i].y);
316 dbg(1,"count=%d\n", i);
319 ret->angle_start=road_angle(&c[0], &c[1], 0);
320 ret->angle_end=road_angle(&c[i-1], &c[i], 0);
323 dbg(1,"i=%d start %d end %d '%s' '%s'\n", i, ret->angle_start, ret->angle_end, ret->name1, ret->name2);
324 map_rect_destroy(mr);
329 this_->last->next=ret;
330 ret->prev=this_->last;
332 dbg(1,"ret=%p\n", ret);
338 * @brief Calculates distance and time to the destination
340 * This function calculates the distance and the time to the destination of a
341 * navigation. If incr is set, this is only calculated for the first navigation
342 * item, which is a lot faster than re-calculation the whole destination, but works
343 * only if the rest of the navigation already has been calculated.
345 * @param this_ The navigation whose destination / time should be calculated
346 * @param incr Set this to true to only calculate the first item. See description.
349 calculate_dest_distance(struct navigation *this_, int incr)
351 int len=0, time=0, count=0;
352 struct navigation_itm *next,*itm=this_->last;
353 dbg(1, "enter this_=%p, incr=%d\n", this_, incr);
356 dbg(2, "old values: (%p) time=%d lenght=%d\n", itm, itm->dest_length, itm->dest_time);
358 dbg(2, "old values: itm is null\n");
361 dbg(2, "itm values: time=%d lenght=%d\n", itm->length, itm->time);
362 dbg(2, "next values: (%p) time=%d lenght=%d\n", next, next->dest_length, next->dest_time);
363 itm->dest_length=next->dest_length+itm->length;
364 itm->dest_count=next->dest_count+1;
365 itm->dest_time=next->dest_time+itm->time;
366 dbg(2, "new values: time=%d lenght=%d\n", itm->dest_length, itm->dest_time);
372 itm->dest_length=len;
374 itm->dest_count=count++;
377 dbg(1,"len %d time %d\n", len, time);
381 * @brief Checks if two navigation items are on the same street
383 * This function checks if two navigation items are on the same street. It returns
384 * true if either their name or their "systematic name" (e.g. "A6" or "B256") are the
387 * @param old The first item to be checked
388 * @param new The second item to be checked
389 * @return True if both old and new are on the same street
392 is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
394 if (old->name1 && new->name1 && !strcmp(old->name1, new->name1)) {
395 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old->name2, new->name2, old->name1, new->name1);
398 if (old->name2 && new->name2 && !strcmp(old->name2, new->name2)) {
399 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old->name2, new->name2, old->name1, new->name1);
402 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old->name2, new->name2, old->name1, new->name1);
407 * @brief Checks if two navigation items are on the same street
409 * This function checks if two navigation items are on the same street. It returns
410 * true if the first part of their "systematic name" is equal. If the "systematic name" is
411 * for example "A352/E3" (a german highway which at the same time is part of the international
412 * E-road network), it would only search for "A352" in the second item's systematic name.
414 * @param old The first item to be checked
415 * @param new The second item to be checked
416 * @return True if the "systematic name" of both items matches. See description.
419 is_same_street_systematic(struct navigation_itm *old, struct navigation_itm *new)
421 int slashold,slashnew;
422 if (!old->name2 || !new->name2)
424 slashold=strcspn(old->name2, "/");
425 slashnew=strcspn(new->name2, "/");
426 if (slashold != slashnew || strncmp(old->name2, new->name2, slashold))
432 * @brief Checks if navit has to create a maneuver to drive from old to new
434 * This function checks if it has to create a "maneuver" - i.e. guide the user - to drive
435 * from "old" to "new".
437 * @param old The old navigation item, where we're coming from
438 * @param new The new navigation item, where we're going to
439 * @param delta The angle the user has to steer to navigate from old to new
440 * @return True if navit should guide the user, false otherwise
443 maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta)
445 dbg(1,"enter %p %p %p\n",old, new, delta);
446 if (new->item.type == old->item.type || (new->item.type != type_ramp && old->item.type != type_ramp)) {
447 if (is_same_street2(old, new)) {
451 dbg(1, "maneuver_required: old or new is ramp\n");
452 if (old->item.type == type_ramp && (new->item.type == type_highway_city || new->item.type == type_highway_land)) {
453 dbg(1, "no_maneuver_required: old is ramp new is highway\n");
457 if (old->crossings_end == 2) {
458 dbg(1, "maneuver_required: only 2 connections: no\n");
462 *delta=new->angle_start-old->angle_end;
467 dbg(1,"delta=%d-%d=%d\n", new->angle_start, old->angle_end, *delta);
468 if ((new->item.type == type_highway_land || new->item.type == type_highway_city || old->item.type == type_highway_land || old->item.type == type_highway_city) && (!is_same_street_systematic(old, new) || (old->name2 != NULL && new->name2 == NULL))) {
469 dbg(1, "maneuver_required: highway changed name\n");
472 if (*delta < 20 && *delta >-20) {
473 if (! new->straight) { /* We're not entering this item straight, so have a maneuver */
477 dbg(1, "maneuver_required: delta(%d) < 20: no\n", *delta);
480 dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
484 static struct navigation_command *
485 command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
487 struct navigation_command *ret=g_new0(struct navigation_command, 1);
488 dbg(1,"enter this_=%p itm=%p delta=%d\n", this_, itm, delta);
492 this_->cmd_last->next=ret;
495 if (!this_->cmd_first)
496 this_->cmd_first=ret;
501 make_maneuvers(struct navigation *this_)
503 struct navigation_itm *itm, *last=NULL, *last_itm=NULL;
506 this_->cmd_last=NULL;
507 this_->cmd_first=NULL;
510 if (maneuver_required2(last_itm, itm, &delta)) {
511 command_new(this_, itm, delta);
521 contains_suffix(char *name, char *suffix)
525 if (strlen(name) < strlen(suffix))
527 return !strcasecmp(name+strlen(name)-strlen(suffix), suffix);
531 replace_suffix(char *name, char *search, char *replace)
533 int len=strlen(name)-strlen(search);
534 char *ret=g_malloc(len+strlen(replace)+1);
535 strncpy(ret, name, len);
536 strcpy(ret+len, replace);
542 navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *next, char *prefix)
544 char *ret=NULL,*name1,*sep,*name2;
548 if(!itm->name1 && !itm->name2 && itm->item.type == type_ramp) {
549 dbg(1,">> Next is ramp %lx current is %lx \n", itm->item.type, next->item.type);
551 if(next->item.type == type_ramp)
553 if(itm->item.type == type_highway_city || itm->item.type == type_highway_land )
554 return g_strdup_printf("%s%s",prefix,_("exit")); /* %FIXME Can this even be reached? */
556 return g_strdup_printf("%s%s",prefix,_("ramp"));
559 if (!itm->name1 && !itm->name2)
564 for (i = 0 ; i < sizeof(suffixes)/sizeof(suffixes[0]) ; i++) {
565 if (contains_suffix(itm->name1,suffixes[i].fullname)) {
567 name1=g_strdup(itm->name1);
570 if (contains_suffix(itm->name1,suffixes[i].abbrev)) {
572 name1=replace_suffix(itm->name1, suffixes[i].abbrev, suffixes[i].fullname);
585 /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name */
586 ret=g_strdup_printf(_("%sinto the street %s%s%s"),prefix,itm->name1, sep, name2);
589 /* 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 */
590 ret=g_strdup_printf(_("%sinto the %s%s%s|male form"),prefix,name1, sep, name2);
593 /* 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 */
594 ret=g_strdup_printf(_("%sinto the %s%s%s|female form"),prefix,name1, sep, name2);
597 /* 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 */
598 ret=g_strdup_printf(_("%sinto the %s%s%s|neutral form"),prefix,name1, sep, name2);
604 /* TRANSLATORS: gives the name of the next road to turn into (into the E17) */
605 ret=g_strdup_printf(_("into the %s"),itm->name2);
624 show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
626 /* TRANSLATORS: right, as in 'Turn right' */
627 char *dir=_("right"),*strength="";
628 int distance=itm->dest_length-cmd->itm->dest_length;
630 int delta=cmd->delta;
634 /* TRANSLATORS: left, as in 'Turn left' */
639 /* TRANSLATORS: Don't forget the ending space */
640 strength=_("easily ");
641 } else if (delta < 105) {
643 } else if (delta < 165) {
644 /* TRANSLATORS: Don't forget the ending space */
645 strength=_("strongly ");
647 dbg(1,"delta=%d\n", delta);
648 /* TRANSLATORS: Don't forget the ending space */
649 strength=_("unknown ");
651 if (type != attr_navigation_long_exact)
652 distance=round_distance(distance);
653 if (type == attr_navigation_speech) {
654 if (nav->turn_around && nav->turn_around == nav->turn_around_limit)
655 return g_strdup(_("When possible, please turn around"));
656 level=navigation_get_announce_level(nav, itm->item.type, distance);
657 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->item.type);
661 d=get_distance(distance, type, 1);
662 ret=g_strdup_printf(_("Follow the road for the next %s"), d);
666 d=g_strdup(_("soon"));
669 d=get_distance(distance, type, 0);
672 d=g_strdup(_("now"));
675 d=g_strdup(_("error"));
677 if (cmd->itm->next) {
678 int tellstreetname = 0;
679 char *destination = NULL;
681 if(type == attr_navigation_speech) { // In voice mode
682 // In Voice Mode only tell the street name in level 1 or in level 0 if level 1
685 if (level == 1) { // we are close to the intersection
686 cmd->itm->told = 1; // remeber to be checked when we turn
687 tellstreetname = 1; // Ok so we tell the name of the street
691 if(cmd->itm->told == 0) // we are write at the intersection
694 cmd->itm->told = 0; // reset just in case we come to the same street again
702 destination=navigation_item_destination(cmd->itm, itm, " ");
703 /* 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' */
704 ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
707 ret=g_strdup_printf(_("You have reached your destination %s"), d);
713 navigation_call_callbacks(struct navigation *this_, int force_speech)
715 int distance, level = 0;
717 if (!this_->cmd_first)
719 callback_list_call(this_->callback, 1, &p);
720 dbg(1,"force_speech=%d turn_around=%d turn_around_limit=%d\n", force_speech, this_->turn_around, this_->turn_around_limit);
721 distance=round_distance(this_->first->dest_length-this_->cmd_first->itm->dest_length);
722 if (this_->turn_around_limit && this_->turn_around == this_->turn_around_limit) {
723 dbg(1,"distance=%d distance_turn=%d\n", distance, this_->distance_turn);
724 while (distance > this_->distance_turn) {
728 if (this_->distance_turn >= 500)
729 this_->distance_turn*=2;
731 this_->distance_turn=500;
733 } else if (!this_->turn_around_limit || this_->turn_around == -this_->turn_around_limit+1) {
734 this_->distance_turn=50;
735 level=navigation_get_announce_level(this_, this_->first->item.type, distance);
736 if (level < this_->level_last) {
737 dbg(1,"level %d < %d\n", level, this_->level_last);
738 this_->level_last=level;
741 if (!item_is_equal(this_->cmd_first->itm->item, this_->item_last)) {
742 dbg(1,"item different\n");
743 this_->item_last=this_->cmd_first->itm->item;
748 this_->level_last=level;
749 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, this_->first->item.type);
750 callback_list_call(this_->callback_speech, 1, &p);
755 navigation_update(struct navigation *this_, struct route *route)
759 struct item *ritem; /* Holds an item from the route map */
760 struct item *sitem; /* Holds the corresponding item from the actual map */
761 struct attr street_item,street_direction;
762 struct navigation_itm *itm;
767 map=route_get_map(route);
770 mr=map_rect_new(map, NULL);
774 ritem=map_rect_get_item(mr);
776 if (!item_attr_get(ritem, attr_street_item, &street_item)) {
777 ritem=map_rect_get_item(mr);
781 if (!item_attr_get(ritem, attr_street_item, &street_item)) {
782 dbg(0,"no street item\n");
785 if (!item_attr_get(ritem, attr_direction, &street_direction))
786 street_direction.u.num=0;
787 sitem=street_item.u.item;
788 dbg(1,"sitem=%p\n", sitem);
789 itm=item_hash_lookup(this_->hash, sitem);
790 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sitem->id_hi, sitem->id_lo, itm);
791 if (itm && itm->direction != street_direction.u.num) {
792 dbg(2,"wrong direction\n");
795 navigation_destroy_itms_cmds(this_, itm);
798 navigation_itm_update(itm, ritem);
800 dbg(1,"not on track\n");
803 navigation_itm_new(this_, ritem);
804 ritem=map_rect_get_item(mr);
806 itm=navigation_itm_new(this_, NULL);
807 make_maneuvers(this_);
809 calculate_dest_distance(this_, incr);
810 dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
811 if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0)
812 this_->turn_around++;
814 this_->turn_around--;
815 if (this_->turn_around > this_->turn_around_limit)
816 this_->turn_around=this_->turn_around_limit;
817 else if (this_->turn_around < -this_->turn_around_limit+1)
818 this_->turn_around=-this_->turn_around_limit+1;
819 dbg(2,"turn_around=%d\n", this_->turn_around);
820 this_->distance_last=this_->first->dest_length;
822 navigation_call_callbacks(this_, FALSE);
824 navigation_destroy_itms_cmds(this_, NULL);
825 map_rect_destroy(mr);
828 struct route_path_handle *rph;
829 struct route_path_segment *s;
830 struct navigation_itm *itm;
831 struct route_info *pos,*dst;
832 struct street_data *sd;
838 pos=route_get_pos(route);
839 dst=route_get_dst(route);
842 speedlist=route_get_speedlist(route);
843 len=route_info_length(pos, dst, 0);
844 dbg(2,"len pos,dst = %d\n", len);
846 len=route_info_length(pos, NULL, 0);
847 dbg(2,"len pos = %d\n", len);
850 sd=route_info_street(pos);
851 itm=item_hash_lookup(this_->hash, &sd->item);
852 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sd->item.id_hi, sd->item.id_lo, itm);
853 navigation_destroy_itms_cmds(this_, itm);
857 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, -1));
861 itm->time=route_time(speedlist, &sd->item, len);
862 dbg(2,"%p time = %d\n", itm, itm->time);
864 printf("not on track\n");
865 rph=route_path_open(route);
867 while((s=route_path_get_segment(rph))) {
868 itm=navigation_itm_new(this_, route_path_segment_get_item(s),route_path_segment_get_start(s));
869 itm->time=route_path_segment_get_time(s);
870 itm->length=route_path_segment_get_length(s);
872 route_path_close(rph);
875 len=route_info_length(NULL, dst, 0);
876 dbg(1, "end %d\n", len);
877 sd=route_info_street(dst);
878 itm=navigation_itm_new(this_, &sd->item, route_info_point(pos, 2));
880 itm->time=route_time(speedlist, &sd->item, len);
882 itm=navigation_itm_new(this_, NULL, NULL);
883 make_maneuvers(this_);
885 calculate_dest_distance(this_, incr);
886 dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
887 if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0)
888 this_->turn_around=1;
890 this_->turn_around=0;
891 dbg(2,"turn_around=%d\n", this_->turn_around);
892 this_->distance_last=this_->first->dest_length;
894 navigation_call_callbacks(this_, FALSE);
899 navigation_flush(struct navigation *this_)
901 navigation_destroy_itms_cmds(this_, NULL);
906 navigation_destroy(struct navigation *this_)
908 navigation_flush(this_);
909 item_hash_destroy(this_->hash);
910 callback_list_destroy(this_->callback);
911 callback_list_destroy(this_->callback_speech);
916 navigation_register_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
918 if (type == attr_navigation_speech)
919 callback_list_add(this_->callback_speech, cb);
921 callback_list_add(this_->callback, cb);
926 navigation_unregister_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
928 if (type == attr_navigation_speech)
929 callback_list_remove_destroy(this_->callback_speech, cb);
931 callback_list_remove_destroy(this_->callback, cb);
935 navigation_get_map(struct navigation *this_)
938 this_->map=map_new(NULL, (struct attr*[]){
939 &(struct attr){attr_type,{"navigation"}},
940 &(struct attr){attr_navigation,.u.navigation=this_},
941 &(struct attr){attr_data,{""}},
942 &(struct attr){attr_description,{"Navigation"}},
948 struct navigation *navigation;
951 struct map_rect_priv {
952 struct navigation *nav;
953 struct navigation_command *cmd;
954 struct navigation_command *cmd_next;
955 struct navigation_itm *itm;
956 struct navigation_itm *itm_next;
957 struct navigation_itm *cmd_itm;
958 struct navigation_itm *cmd_itm_next;
960 enum attr_type attr_next;
968 navigation_map_item_coord_get(void *priv_data, struct coord *c, int count)
970 struct map_rect_priv *this=priv_data;
971 if (this->ccount || ! count)
979 navigation_map_item_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
981 struct map_rect_priv *this_=priv_data;
982 attr->type=attr_type;
983 struct navigation_command *cmd=this_->cmd;
984 struct navigation_itm *itm=this_->itm;
985 struct navigation_itm *prev=itm->prev;
997 case attr_navigation_short:
998 this_->attr_next=attr_navigation_long;
1000 this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
1004 case attr_navigation_long:
1005 this_->attr_next=attr_navigation_long_exact;
1007 this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
1011 case attr_navigation_long_exact:
1012 this_->attr_next=attr_navigation_speech;
1014 this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
1018 case attr_navigation_speech:
1019 this_->attr_next=attr_length;
1021 this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, this_->cmd, attr_type);
1026 this_->attr_next=attr_time;
1028 attr->u.num=this_->cmd_itm->dest_length-cmd->itm->dest_length;
1033 this_->attr_next=attr_destination_length;
1035 attr->u.num=this_->cmd_itm->dest_time-cmd->itm->dest_time;
1039 case attr_destination_length:
1040 attr->u.num=itm->dest_length;
1041 this_->attr_next=attr_destination_time;
1043 case attr_destination_time:
1044 attr->u.num=itm->dest_time;
1045 this_->attr_next=attr_street_name;
1047 case attr_street_name:
1048 attr->u.str=itm->name1;
1049 this_->attr_next=attr_street_name_systematic;
1051 case attr_street_name_systematic:
1052 attr->u.str=itm->name2;
1053 this_->attr_next=attr_debug;
1056 switch(this_->debug_idx) {
1059 this_->str=attr->u.str=g_strdup_printf("angle:%d - %d", itm->angle_start, itm->angle_end);
1063 this_->str=attr->u.str=g_strdup_printf("item type:%s", item_to_name(itm->item.type));
1068 this_->str=attr->u.str=g_strdup_printf("delta:%d", cmd->delta);
1074 this_->str=attr->u.str=g_strdup_printf("prev street_name:%s", prev->name1);
1080 this_->str=attr->u.str=g_strdup_printf("prev street_name_systematic:%s", prev->name2);
1085 this_->str=attr->u.str=g_strdup_printf("prev angle:%d - %d", prev->angle_start, prev->angle_end);
1090 this_->str=attr->u.str=g_strdup_printf("prev item type:%s", item_to_name(prev->item.type));
1094 this_->attr_next=attr_none;
1098 while (this_->attr_next != attr_none) {
1099 if (navigation_map_item_attr_get(priv_data, this_->attr_next, attr))
1104 attr->type=attr_none;
1109 static struct item_methods navigation_map_item_methods = {
1111 navigation_map_item_coord_get,
1113 navigation_map_item_attr_get,
1118 navigation_map_destroy(struct map_priv *priv)
1124 navigation_map_rect_init(struct map_rect_priv *priv)
1126 priv->cmd_next=priv->nav->cmd_first;
1127 priv->cmd_itm_next=priv->itm_next=priv->nav->first;
1130 static struct map_rect_priv *
1131 navigation_map_rect_new(struct map_priv *priv, struct map_selection *sel)
1133 struct navigation *nav=priv->navigation;
1134 struct map_rect_priv *ret=g_new0(struct map_rect_priv, 1);
1136 navigation_map_rect_init(ret);
1137 ret->item.meth=&navigation_map_item_methods;
1138 ret->item.priv_data=ret;
1143 navigation_map_rect_destroy(struct map_rect_priv *priv)
1148 static struct item *
1149 navigation_map_get_item(struct map_rect_priv *priv)
1151 struct item *ret=&priv->item;
1153 if (!priv->itm_next)
1155 priv->itm=priv->itm_next;
1156 priv->cmd=priv->cmd_next;
1157 priv->cmd_itm=priv->cmd_itm_next;
1158 if (!priv->show_all) {
1161 priv->itm=priv->cmd->itm;
1163 priv->itm_next=priv->itm->next;
1164 ret->type=type_nav_none;
1165 if (priv->cmd->itm == priv->itm) {
1166 priv->cmd_itm_next=priv->cmd->itm;
1167 priv->cmd_next=priv->cmd->next;
1168 delta=priv->cmd->delta;
1172 ret->type=type_nav_left_1;
1173 else if (delta < 105)
1174 ret->type=type_nav_left_2;
1175 else if (delta < 165)
1176 ret->type=type_nav_left_3;
1178 ret->type=type_none;
1181 ret->type=type_nav_right_1;
1182 else if (delta < 105)
1183 ret->type=type_nav_right_2;
1184 else if (delta < 165)
1185 ret->type=type_nav_right_3;
1187 ret->type=type_none;
1192 priv->attr_next=attr_navigation_short;
1194 ret->id_lo=priv->itm->dest_count;
1195 dbg(1,"type=%d\n", ret->type);
1199 static struct item *
1200 navigation_map_get_item_byid(struct map_rect_priv *priv, int id_hi, int id_lo)
1203 navigation_map_rect_init(priv);
1204 while ((ret=navigation_map_get_item(priv))) {
1205 if (ret->id_hi == id_hi && ret->id_lo == id_lo)
1211 static struct map_methods navigation_map_meth = {
1214 navigation_map_destroy,
1215 navigation_map_rect_new,
1216 navigation_map_rect_destroy,
1217 navigation_map_get_item,
1218 navigation_map_get_item_byid,
1224 static struct map_priv *
1225 navigation_map_new(struct map_methods *meth, struct attr **attrs)
1227 struct map_priv *ret;
1228 struct attr *navigation_attr;
1230 navigation_attr=attr_search(attrs, NULL, attr_navigation);
1231 if (! navigation_attr)
1233 ret=g_new0(struct map_priv, 1);
1234 *meth=navigation_map_meth;
1235 ret->navigation=navigation_attr->u.navigation;
1242 navigation_init(void)
1244 plugin_register_map_type("navigation", navigation_map_new);