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.
27 #include "navigation.h"
31 #include "transform.h"
33 #include "projection.h"
38 #include "navit_nls.h"
56 struct item_hash *hash;
57 struct navigation_itm *first;
58 struct navigation_itm *last;
59 struct navigation_command *cmd_first;
60 struct navigation_command *cmd_last;
61 struct callback_list *callback_speech;
62 struct callback_list *callback;
64 struct item item_last;
66 int turn_around_limit;
69 int announce[route_item_last-route_item_first+1][3];
73 struct navigation_command {
74 struct navigation_itm *itm;
75 struct navigation_command *next;
80 * @brief Calculates the delta between two angles
81 * @param angle1 The first angle
82 * @param angle2 The second angle
83 * @return The difference between the angles: -179..-1=angle2 is left of angle1,0=same,1..179=angle2 is right of angle1,180=angle1 is opposite of angle2
87 angle_delta(int angle1, int angle2)
89 int delta=angle2-angle1;
98 navigation_new(struct attr **attrs)
101 struct navigation *ret=g_new0(struct navigation, 1);
102 ret->hash=item_hash_new();
103 ret->callback=callback_list_new();
104 ret->callback_speech=callback_list_new();
106 ret->distance_last=-2;
107 ret->distance_turn=50;
108 ret->turn_around_limit=3;
110 for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
111 for (i = 0 ; i < 3 ; i++) {
112 ret->announce[j][i]=-1;
120 navigation_set_announce(struct navigation *this_, enum item_type type, int *level)
123 if (type < route_item_first || type > route_item_last) {
124 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
127 for (i = 0 ; i < 3 ; i++)
128 this_->announce[type-route_item_first][i]=level[i];
133 navigation_get_announce_level(struct navigation *this_, enum item_type type, int dist)
137 if (type < route_item_first || type > route_item_last)
139 for (i = 0 ; i < 3 ; i++) {
140 if (dist <= this_->announce[type-route_item_first][i])
147 * @brief Holds a way that one could possibly drive from a navigation item
149 struct navigation_way {
150 struct navigation_way *next; /**< Pointer to a linked-list of all navigation_ways from this navigation item */
151 short dir; /**< The direction -1 or 1 of the way */
152 short angle2; /**< The angle one has to steer to drive from the old item to this street */
153 int flags; /**< The flags of the way */
154 struct item item; /**< The item of the way */
157 struct navigation_itm {
164 struct coord start,end;
171 struct navigation_itm *next;
172 struct navigation_itm *prev;
173 struct navigation_way *ways; /**< Pointer to all ways one could drive from here */
178 road_angle(struct coord *c1, struct coord *c2, int dir)
180 int ret=transform_get_angle_delta(c1, c2, dir);
181 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
186 round_distance(int dist)
209 dist=(dist+500)/1000;
212 dist=(dist+5000)/10000;
217 get_distance(int dist, enum attr_type type, int is_length)
219 if (type == attr_navigation_long) {
221 return g_strdup_printf(_("%d m"), dist);
223 return g_strdup_printf(_("in %d m"), dist);
227 return g_strdup_printf(_("%d meters"), dist);
229 return g_strdup_printf(_("in %d meters"), dist);
232 int rem=(dist/100)%10;
235 return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
237 return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
241 return g_strdup_printf(ngettext("one kilometer","%d kilometers", dist/1000), dist/1000);
243 return g_strdup_printf(ngettext("in one kilometer","in %d kilometers", dist/1000), dist/1000);
248 * @brief This calculates the angle with which an item starts or ends
250 * This function can be used to get the angle an item (from a route graph map)
251 * starts or ends with. Note that the angle will point towards the inner of
254 * This is meant to be used with items from a route graph map
255 * With other items this will probably not be optimal...
257 * @param w The way which should be calculated
260 calculate_angle(struct navigation_way *w)
262 struct coord cbuf[2];
263 struct item *ritem; // the "real" item
269 mr = map_rect_new(w->item.map, NULL);
273 ritem = map_rect_get_item_byid(mr, w->item.id_hi, w->item.id_lo);
275 dbg(1,"Item from segment not found on map!\n");
276 map_rect_destroy(mr);
280 if (ritem->type < type_line || ritem->type >= type_area) {
281 map_rect_destroy(mr);
284 if (item_attr_get(ritem, attr_flags, &attr))
290 if (item_coord_get(ritem, cbuf, 2) != 2) {
291 dbg(1,"Using calculate_angle() with a less-than-two-coords-item?\n");
292 map_rect_destroy(mr);
296 while (item_coord_get(ritem, &c, 1)) {
302 if (item_coord_get(ritem, cbuf, 2) != 2) {
303 dbg(1,"Using calculate_angle() with a less-than-two-coords-item?\n");
304 map_rect_destroy(mr);
312 map_rect_destroy(mr);
314 w->angle2=road_angle(&cbuf[1],&cbuf[0],0);
318 * @brief Clears the ways one can drive from itm
320 * @param itm The item that should have its ways cleared
323 navigation_itm_ways_clear(struct navigation_itm *itm)
325 struct navigation_way *c,*n;
338 * @brief Updates the ways one can drive from itm
340 * This updates the list of possible ways to drive to from itm. The item "itm" is on
341 * and the next navigation item are excluded.
343 * @param itm The item that should be updated
344 * @param graph_map The route graph's map that these items are on
347 navigation_itm_ways_update(struct navigation_itm *itm, struct map *graph_map)
349 struct map_selection coord_sel;
350 struct map_rect *g_rect; // Contains a map rectangle from the route graph's map
351 struct item *i,*sitem;
352 struct attr sitem_attr,direction_attr;
353 struct navigation_way *w,*l;
355 navigation_itm_ways_clear(itm);
357 // These values cause the code in route.c to get us only the route graph point and connected segments
358 coord_sel.next = NULL;
359 coord_sel.u.c_rect.lu = itm->start;
360 coord_sel.u.c_rect.rl = itm->start;
361 // the selection's order is ignored
363 g_rect = map_rect_new(graph_map, &coord_sel);
365 i = map_rect_get_item(g_rect);
366 if (!i || i->type != type_rg_point) { // probably offroad?
373 i = map_rect_get_item(g_rect);
379 if (i->type != type_rg_segment) {
383 if (!item_attr_get(i,attr_street_item,&sitem_attr)) {
384 dbg(1, "Got no street item for route graph item in entering_straight()\n");
388 if (!item_attr_get(i,attr_direction,&direction_attr)) {
392 sitem = sitem_attr.u.item;
393 if (item_is_equal(itm->item,*sitem) || ((itm->prev) && item_is_equal(itm->prev->item,*sitem))) {
398 w = g_new(struct navigation_way, 1);
399 w->dir = direction_attr.u.num;
405 map_rect_destroy(g_rect);
411 navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *end)
413 struct navigation_itm *itm;
414 struct navigation_command *cmd;
415 dbg(2,"enter this_=%p this_->first=%p this_->cmd_first=%p end=%p\n", this_, this_->first, this_->cmd_first, end);
416 if (this_->cmd_first)
417 dbg(2,"this_->cmd_first->itm=%p\n", this_->cmd_first->itm);
418 while (this_->first && this_->first != end) {
420 dbg(3,"destroying %p\n", itm);
421 item_hash_remove(this_->hash, &itm->item);
422 this_->first=itm->next;
424 this_->first->prev=NULL;
425 if (this_->cmd_first && this_->cmd_first->itm == itm->next) {
426 cmd=this_->cmd_first;
427 this_->cmd_first=cmd->next;
430 map_convert_free(itm->name1);
431 map_convert_free(itm->name2);
432 navigation_itm_ways_clear(itm);
437 if (! this_->first && end)
438 dbg(0,"end wrong\n");
439 dbg(2,"ret this_->first=%p this_->cmd_first=%p\n",this_->first, this_->cmd_first);
443 navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
445 struct attr length, time;
446 if (! item_attr_get(ritem, attr_length, &length)) {
447 dbg(0,"no length\n");
450 if (! item_attr_get(ritem, attr_time, &time)) {
455 dbg(1,"length=%d time=%d\n", length.u.num, time.u.num);
456 itm->length=length.u.num;
457 itm->time=time.u.num;
460 static struct navigation_itm *
461 navigation_itm_new(struct navigation *this_, struct item *ritem)
463 struct navigation_itm *ret=g_new0(struct navigation_itm, 1);
466 struct map *graph_map = NULL;
467 struct attr street_item,direction,route_attr;
474 if (! item_attr_get(ritem, attr_street_item, &street_item)) {
475 dbg(0,"no street item\n");
478 if (item_attr_get(ritem, attr_direction, &direction))
479 ret->direction=direction.u.num;
483 item_attr_get(ritem, attr_route, &route_attr);
484 graph_map = route_get_graph_map(route_attr.u.route);
486 sitem=street_item.u.item;
488 item_hash_insert(this_->hash, sitem, ret);
489 mr=map_rect_new(sitem->map, NULL);
490 sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo);
491 if (item_attr_get(sitem, attr_street_name, &attr))
492 ret->name1=map_convert_string(sitem->map,attr.u.str);
493 if (item_attr_get(sitem, attr_street_name_systematic, &attr))
494 ret->name2=map_convert_string(sitem->map,attr.u.str);
495 navigation_itm_update(ret, ritem);
497 while (item_coord_get(ritem, &c[i], 1)) {
498 dbg(1, "coord %d 0x%x 0x%x\n", i, c[i].x ,c[i].y);
507 dbg(1,"count=%d\n", i);
510 ret->angle_start=road_angle(&c[0], &c[1], 0);
511 ret->angle_end=road_angle(&c[i-1], &c[i], 0);
515 dbg(1,"i=%d start %d end %d '%s' '%s'\n", i, ret->angle_start, ret->angle_end, ret->name1, ret->name2);
516 map_rect_destroy(mr);
519 ret->start=ret->end=this_->last->end;
524 this_->last->next=ret;
525 ret->prev=this_->last;
527 navigation_itm_ways_update(ret,graph_map);
530 dbg(1,"ret=%p\n", ret);
536 * @brief Calculates distance and time to the destination
538 * This function calculates the distance and the time to the destination of a
539 * navigation. If incr is set, this is only calculated for the first navigation
540 * item, which is a lot faster than re-calculation the whole destination, but works
541 * only if the rest of the navigation already has been calculated.
543 * @param this_ The navigation whose destination / time should be calculated
544 * @param incr Set this to true to only calculate the first item. See description.
547 calculate_dest_distance(struct navigation *this_, int incr)
549 int len=0, time=0, count=0;
550 struct navigation_itm *next,*itm=this_->last;
551 dbg(1, "enter this_=%p, incr=%d\n", this_, incr);
554 dbg(2, "old values: (%p) time=%d lenght=%d\n", itm, itm->dest_length, itm->dest_time);
556 dbg(2, "old values: itm is null\n");
559 dbg(2, "itm values: time=%d lenght=%d\n", itm->length, itm->time);
560 dbg(2, "next values: (%p) time=%d lenght=%d\n", next, next->dest_length, next->dest_time);
561 itm->dest_length=next->dest_length+itm->length;
562 itm->dest_count=next->dest_count+1;
563 itm->dest_time=next->dest_time+itm->time;
564 dbg(2, "new values: time=%d lenght=%d\n", itm->dest_length, itm->dest_time);
570 itm->dest_length=len;
572 itm->dest_count=count++;
575 dbg(1,"len %d time %d\n", len, time);
579 * @brief Checks if two navigation items are on the same street
581 * This function checks if two navigation items are on the same street. It returns
582 * true if either their name or their "systematic name" (e.g. "A6" or "B256") are the
585 * @param old The first item to be checked
586 * @param new The second item to be checked
587 * @return True if both old and new are on the same street
590 is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
592 if (old->name1 && new->name1 && !strcmp(old->name1, new->name1)) {
593 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old->name2, new->name2, old->name1, new->name1);
596 if (old->name2 && new->name2 && !strcmp(old->name2, new->name2)) {
597 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old->name2, new->name2, old->name1, new->name1);
600 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old->name2, new->name2, old->name1, new->name1);
605 * @brief Checks if two navigation items are on the same street
607 * This function checks if two navigation items are on the same street. It returns
608 * true if the first part of their "systematic name" is equal. If the "systematic name" is
609 * for example "A352/E3" (a german highway which at the same time is part of the international
610 * E-road network), it would only search for "A352" in the second item's systematic name.
612 * @param old The first item to be checked
613 * @param new The second item to be checked
614 * @return True if the "systematic name" of both items matches. See description.
617 is_same_street_systematic(struct navigation_itm *old, struct navigation_itm *new)
619 int slashold,slashnew;
620 if (!old->name2 || !new->name2)
622 slashold=strcspn(old->name2, "/");
623 slashnew=strcspn(new->name2, "/");
624 if (slashold != slashnew || strncmp(old->name2, new->name2, slashold))
631 * @brief Check if there are multiple possibilities to drive from old
633 * This function checks, if there are multiple streets connected to the exit of "old".
634 * Sometimes it happens that an item on a map is just segmented, without any other streets
635 * being connected there, and it is not useful if navit creates a maneuver there.
637 * @param new The navigation item we're driving to
638 * @return True if there are multiple streets
641 check_multiple_streets(struct navigation_itm *new)
651 * @brief Check if the new item is entered "straight"
653 * This function checks if the new item is entered "straight" from the old item, i.e. if there
654 * is no other street one could take from the old item on with less steering.
656 * @param new The navigation item we're driving to
657 * @param diff The absolute angle one needs to steer to drive to this item
658 * @return True if the new item is entered "straight"
661 entering_straight(struct navigation_itm *new, int diff)
664 struct navigation_way *w;
667 dbg(1,"diff=%d\n", diff);
669 curr_diff=abs(angle_delta(new->prev->angle_end, w->angle2));
670 dbg(1,"curr_diff=%d\n", curr_diff);
671 if (curr_diff < diff) {
680 * @brief Checks if navit has to create a maneuver to drive from old to new
682 * This function checks if it has to create a "maneuver" - i.e. guide the user - to drive
683 * from "old" to "new".
685 * @param old The old navigation item, where we're coming from
686 * @param new The new navigation item, where we're going to
687 * @param delta The angle the user has to steer to navigate from old to new
688 * @param reason A text string explaining how the return value resulted
689 * @return True if navit should guide the user, false otherwise
692 maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta, char **reason)
694 int straight_limit=20,ext_straight_limit=45;
696 dbg(1,"enter %p %p %p\n",old, new, delta);
697 *delta=angle_delta(old->angle_end, new->angle_start);
699 if (new->item.type == old->item.type || (new->item.type != type_ramp && old->item.type != type_ramp)) {
700 if (is_same_street2(old, new)) {
701 if (! entering_straight(new, abs(*delta))) {
702 dbg(1, "maneuver_required: Not driving straight: yes\n");
704 *reason="yes: Not driving straight";
708 dbg(1, "maneuver_required: Staying on the same street: no\n");
710 *reason="no: Staying on same street";
714 dbg(1, "maneuver_required: old or new is ramp\n");
716 if (old->item.type == type_ramp && (new->item.type == type_highway_city || new->item.type == type_highway_land)) {
717 dbg(1, "no_maneuver_required: old is ramp new is highway\n");
719 *reason="no: old is ramp new is highway";
724 if (old->crossings_end == 2) {
725 dbg(1, "maneuver_required: only 2 connections: no\n");
729 dbg(1,"delta=%d-%d=%d\n", new->angle_start, old->angle_end, *delta);
730 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))) {
731 dbg(1, "maneuver_required: highway changed name\n");
733 *reason="yes: highway changed name";
736 if (abs(*delta) < straight_limit) {
737 if (! entering_straight(new,abs(*delta))) {
739 *reason="yes: not straight";
740 dbg(1, "maneuver_required: not driving straight: yes\n");
744 dbg(1, "maneuver_required: delta(%d) < %d: no\n", *delta, straight_limit);
746 *reason="no: delta < limit";
749 if (abs(*delta) < ext_straight_limit) {
750 if (entering_straight(new,abs(*delta)*2)) {
752 *reason="no: delta < ext_limit";
757 if (! check_multiple_streets(new)) {
758 dbg(1, "maneuver_required: only one possibility: no\n");
760 *reason="no: only one possibility";
764 dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
766 *reason="yes: delta >= limit";
770 static struct navigation_command *
771 command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
773 struct navigation_command *ret=g_new0(struct navigation_command, 1);
774 dbg(1,"enter this_=%p itm=%p delta=%d\n", this_, itm, delta);
778 this_->cmd_last->next=ret;
781 if (!this_->cmd_first)
782 this_->cmd_first=ret;
787 make_maneuvers(struct navigation *this_, struct route *route)
789 struct navigation_itm *itm, *last=NULL, *last_itm=NULL;
792 this_->cmd_last=NULL;
793 this_->cmd_first=NULL;
796 if (maneuver_required2(last_itm, itm,&delta,NULL)) {
797 command_new(this_, itm, delta);
807 contains_suffix(char *name, char *suffix)
811 if (strlen(name) < strlen(suffix))
813 return !strcasecmp(name+strlen(name)-strlen(suffix), suffix);
817 replace_suffix(char *name, char *search, char *replace)
819 int len=strlen(name)-strlen(search);
820 char *ret=g_malloc(len+strlen(replace)+1);
821 strncpy(ret, name, len);
822 strcpy(ret+len, replace);
828 navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *next, char *prefix)
830 char *ret=NULL,*name1,*sep,*name2;
834 if(!itm->name1 && !itm->name2 && itm->item.type == type_ramp) {
835 dbg(1,">> Next is ramp %lx current is %lx \n", itm->item.type, next->item.type);
837 if(next->item.type == type_ramp)
839 if(itm->item.type == type_highway_city || itm->item.type == type_highway_land )
840 return g_strdup_printf("%s%s",prefix,_("exit")); /* %FIXME Can this even be reached? */
842 return g_strdup_printf("%s%s",prefix,_("ramp"));
845 if (!itm->name1 && !itm->name2)
850 for (i = 0 ; i < sizeof(suffixes)/sizeof(suffixes[0]) ; i++) {
851 if (contains_suffix(itm->name1,suffixes[i].fullname)) {
853 name1=g_strdup(itm->name1);
856 if (contains_suffix(itm->name1,suffixes[i].abbrev)) {
858 name1=replace_suffix(itm->name1, suffixes[i].abbrev, suffixes[i].fullname);
871 /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name */
872 ret=g_strdup_printf(_("%sinto the street %s%s%s"),prefix,itm->name1, sep, name2);
875 /* 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 */
876 ret=g_strdup_printf(_("%sinto the %s%s%s|male form"),prefix,name1, sep, name2);
879 /* 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 */
880 ret=g_strdup_printf(_("%sinto the %s%s%s|female form"),prefix,name1, sep, name2);
883 /* 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 */
884 ret=g_strdup_printf(_("%sinto the %s%s%s|neutral form"),prefix,name1, sep, name2);
890 /* TRANSLATORS: gives the name of the next road to turn into (into the E17) */
891 ret=g_strdup_printf(_("into the %s"),itm->name2);
909 show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
911 /* TRANSLATORS: right, as in 'Turn right' */
912 char *dir=_("right"),*strength="";
913 int distance=itm->dest_length-cmd->itm->dest_length;
915 int delta=cmd->delta;
918 struct navigation_way *w;
922 if ((itm->next->angle_start - itm->angle_end) < 0) {
924 if (w->angle2-itm->next->angle_start < 0) {
932 if (w->angle2-itm->next->angle_start > 0) {
942 /* TRANSLATORS: left, as in 'Turn left' */
947 if (strength_needed) {
949 /* TRANSLATORS: Don't forget the ending space */
950 strength=_("easily ");
951 } else if (delta < 105) {
953 } else if (delta < 165) {
954 /* TRANSLATORS: Don't forget the ending space */
955 strength=_("strongly ");
957 dbg(1,"delta=%d\n", delta);
958 /* TRANSLATORS: Don't forget the ending space */
959 strength=_("unknown ");
962 if (type != attr_navigation_long_exact)
963 distance=round_distance(distance);
964 if (type == attr_navigation_speech) {
965 if (nav->turn_around && nav->turn_around == nav->turn_around_limit)
966 return g_strdup(_("When possible, please turn around"));
967 level=navigation_get_announce_level(nav, itm->item.type, distance);
968 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->item.type);
972 d=get_distance(distance, type, 1);
973 ret=g_strdup_printf(_("Follow the road for the next %s"), d);
977 d=g_strdup(_("soon"));
980 d=get_distance(distance, type, 0);
983 d=g_strdup(_("now"));
986 d=g_strdup(_("error"));
988 if (cmd->itm->next) {
989 int tellstreetname = 0;
990 char *destination = NULL;
992 if(type == attr_navigation_speech) { // In voice mode
993 // In Voice Mode only tell the street name in level 1 or in level 0 if level 1
996 if (level == 1) { // we are close to the intersection
997 cmd->itm->told = 1; // remeber to be checked when we turn
998 tellstreetname = 1; // Ok so we tell the name of the street
1002 if(cmd->itm->told == 0) // we are right at the intersection
1005 cmd->itm->told = 0; // reset just in case we come to the same street again
1013 destination=navigation_item_destination(cmd->itm, itm, " ");
1014 /* 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' */
1015 ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
1016 g_free(destination);
1018 ret=g_strdup_printf(_("You have reached your destination %s"), d);
1024 navigation_call_callbacks(struct navigation *this_, int force_speech)
1026 int distance, level = 0;
1028 if (!this_->cmd_first)
1030 callback_list_call(this_->callback, 1, &p);
1031 dbg(1,"force_speech=%d turn_around=%d turn_around_limit=%d\n", force_speech, this_->turn_around, this_->turn_around_limit);
1032 distance=round_distance(this_->first->dest_length-this_->cmd_first->itm->dest_length);
1033 if (this_->turn_around_limit && this_->turn_around == this_->turn_around_limit) {
1034 dbg(1,"distance=%d distance_turn=%d\n", distance, this_->distance_turn);
1035 while (distance > this_->distance_turn) {
1036 this_->level_last=4;
1039 if (this_->distance_turn >= 500)
1040 this_->distance_turn*=2;
1042 this_->distance_turn=500;
1044 } else if (!this_->turn_around_limit || this_->turn_around == -this_->turn_around_limit+1) {
1045 this_->distance_turn=50;
1046 level=navigation_get_announce_level(this_, this_->first->item.type, distance);
1047 if (level < this_->level_last) {
1048 dbg(1,"level %d < %d\n", level, this_->level_last);
1049 this_->level_last=level;
1052 if (!item_is_equal(this_->cmd_first->itm->item, this_->item_last)) {
1053 dbg(1,"item different\n");
1054 this_->item_last=this_->cmd_first->itm->item;
1059 this_->level_last=level;
1060 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, this_->first->item.type);
1061 callback_list_call(this_->callback_speech, 1, &p);
1066 navigation_update(struct navigation *this_, struct route *route)
1069 struct map_rect *mr;
1070 struct item *ritem; /* Holds an item from the route map */
1071 struct item *sitem; /* Holds the corresponding item from the actual map */
1072 struct attr street_item,street_direction;
1073 struct navigation_itm *itm;
1078 map=route_get_map(route);
1081 mr=map_rect_new(map, NULL);
1085 while ((ritem=map_rect_get_item(mr))) {
1086 if (first && item_attr_get(ritem, attr_street_item, &street_item)) {
1088 if (!item_attr_get(ritem, attr_direction, &street_direction))
1089 street_direction.u.num=0;
1090 sitem=street_item.u.item;
1091 dbg(1,"sitem=%p\n", sitem);
1092 itm=item_hash_lookup(this_->hash, sitem);
1093 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sitem->id_hi, sitem->id_lo, itm);
1094 if (itm && itm->direction != street_direction.u.num) {
1095 dbg(2,"wrong direction\n");
1098 navigation_destroy_itms_cmds(this_, itm);
1100 navigation_itm_update(itm, ritem);
1103 dbg(1,"not on track\n");
1105 navigation_itm_new(this_, ritem);
1108 navigation_destroy_itms_cmds(this_, NULL);
1111 navigation_itm_new(this_, NULL);
1112 make_maneuvers(this_,route);
1114 calculate_dest_distance(this_, incr);
1115 dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
1116 if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0)
1117 this_->turn_around++;
1119 this_->turn_around--;
1120 if (this_->turn_around > this_->turn_around_limit)
1121 this_->turn_around=this_->turn_around_limit;
1122 else if (this_->turn_around < -this_->turn_around_limit+1)
1123 this_->turn_around=-this_->turn_around_limit+1;
1124 dbg(2,"turn_around=%d\n", this_->turn_around);
1125 this_->distance_last=this_->first->dest_length;
1127 navigation_call_callbacks(this_, FALSE);
1129 map_rect_destroy(mr);
1133 navigation_flush(struct navigation *this_)
1135 navigation_destroy_itms_cmds(this_, NULL);
1140 navigation_destroy(struct navigation *this_)
1142 navigation_flush(this_);
1143 item_hash_destroy(this_->hash);
1144 callback_list_destroy(this_->callback);
1145 callback_list_destroy(this_->callback_speech);
1150 navigation_register_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
1152 if (type == attr_navigation_speech)
1153 callback_list_add(this_->callback_speech, cb);
1155 callback_list_add(this_->callback, cb);
1160 navigation_unregister_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
1162 if (type == attr_navigation_speech)
1163 callback_list_remove_destroy(this_->callback_speech, cb);
1165 callback_list_remove_destroy(this_->callback, cb);
1169 navigation_get_map(struct navigation *this_)
1172 this_->map=map_new(NULL, (struct attr*[]){
1173 &(struct attr){attr_type,{"navigation"}},
1174 &(struct attr){attr_navigation,.u.navigation=this_},
1175 &(struct attr){attr_data,{""}},
1176 &(struct attr){attr_description,{"Navigation"}},
1182 struct navigation *navigation;
1185 struct map_rect_priv {
1186 struct navigation *nav;
1187 struct navigation_command *cmd;
1188 struct navigation_command *cmd_next;
1189 struct navigation_itm *itm;
1190 struct navigation_itm *itm_next;
1191 struct navigation_itm *cmd_itm;
1192 struct navigation_itm *cmd_itm_next;
1194 enum attr_type attr_next;
1197 struct navigation_way *ways;
1203 navigation_map_item_coord_get(void *priv_data, struct coord *c, int count)
1205 struct map_rect_priv *this=priv_data;
1206 if (this->ccount || ! count)
1208 *c=this->itm->start;
1214 navigation_map_item_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
1216 struct map_rect_priv *this_=priv_data;
1217 attr->type=attr_type;
1218 struct navigation_command *cmd=this_->cmd;
1219 struct navigation_itm *itm=this_->itm;
1220 struct navigation_itm *prev=itm->prev;
1228 if (cmd->itm != itm)
1232 case attr_navigation_short:
1233 this_->attr_next=attr_navigation_long;
1235 this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
1239 case attr_navigation_long:
1240 this_->attr_next=attr_navigation_long_exact;
1242 this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
1246 case attr_navigation_long_exact:
1247 this_->attr_next=attr_navigation_speech;
1249 this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
1253 case attr_navigation_speech:
1254 this_->attr_next=attr_length;
1256 this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, this_->cmd, attr_type);
1261 this_->attr_next=attr_time;
1263 attr->u.num=this_->cmd_itm->dest_length-cmd->itm->dest_length;
1268 this_->attr_next=attr_destination_length;
1270 attr->u.num=this_->cmd_itm->dest_time-cmd->itm->dest_time;
1274 case attr_destination_length:
1275 attr->u.num=itm->dest_length;
1276 this_->attr_next=attr_destination_time;
1278 case attr_destination_time:
1279 attr->u.num=itm->dest_time;
1280 this_->attr_next=attr_street_name;
1282 case attr_street_name:
1283 attr->u.str=itm->name1;
1284 this_->attr_next=attr_street_name_systematic;
1287 case attr_street_name_systematic:
1288 attr->u.str=itm->name2;
1289 this_->attr_next=attr_debug;
1293 switch(this_->debug_idx) {
1296 this_->str=attr->u.str=g_strdup_printf("angle:%d (- %d)", itm->angle_start, itm->angle_end);
1300 this_->str=attr->u.str=g_strdup_printf("item type:%s", item_to_name(itm->item.type));
1305 this_->str=attr->u.str=g_strdup_printf("delta:%d", cmd->delta);
1311 this_->str=attr->u.str=g_strdup_printf("prev street_name:%s", prev->name1);
1317 this_->str=attr->u.str=g_strdup_printf("prev street_name_systematic:%s", prev->name2);
1323 this_->str=attr->u.str=g_strdup_printf("prev angle:(%d -) %d", prev->angle_start, prev->angle_end);
1328 this_->ways=itm->ways;
1330 this_->str=attr->u.str=g_strdup_printf("prev item type:%s", item_to_name(prev->item.type));
1335 this_->str=attr->u.str=g_strdup_printf("other item angle:%d delta:%d flags:%d dir:%d type:%s id:(0x%x,0x%x)", this_->ways->angle2, angle_delta(prev->angle_end, this_->ways->angle2), this_->ways->flags, this_->ways->dir, item_to_name(this_->ways->item.type), this_->ways->item.id_hi, this_->ways->item.id_lo);
1336 this_->ways=this_->ways->next;
1345 maneuver_required2(prev, itm, &delta, &reason);
1346 this_->str=attr->u.str=g_strdup_printf("reason:%s",reason);
1351 this_->attr_next=attr_none;
1355 while (this_->attr_next != attr_none) {
1356 if (navigation_map_item_attr_get(priv_data, this_->attr_next, attr))
1361 attr->type=attr_none;
1366 static struct item_methods navigation_map_item_methods = {
1368 navigation_map_item_coord_get,
1370 navigation_map_item_attr_get,
1375 navigation_map_destroy(struct map_priv *priv)
1381 navigation_map_rect_init(struct map_rect_priv *priv)
1383 priv->cmd_next=priv->nav->cmd_first;
1384 priv->cmd_itm_next=priv->itm_next=priv->nav->first;
1387 static struct map_rect_priv *
1388 navigation_map_rect_new(struct map_priv *priv, struct map_selection *sel)
1390 struct navigation *nav=priv->navigation;
1391 struct map_rect_priv *ret=g_new0(struct map_rect_priv, 1);
1393 navigation_map_rect_init(ret);
1394 ret->item.meth=&navigation_map_item_methods;
1395 ret->item.priv_data=ret;
1403 navigation_map_rect_destroy(struct map_rect_priv *priv)
1408 static struct item *
1409 navigation_map_get_item(struct map_rect_priv *priv)
1411 struct item *ret=&priv->item;
1413 if (!priv->itm_next)
1415 priv->itm=priv->itm_next;
1416 priv->cmd=priv->cmd_next;
1417 priv->cmd_itm=priv->cmd_itm_next;
1420 if (!priv->show_all && priv->itm->prev != NULL)
1421 priv->itm=priv->cmd->itm;
1422 priv->itm_next=priv->itm->next;
1423 if (priv->itm->prev)
1424 ret->type=type_nav_none;
1426 ret->type=type_nav_position;
1427 if (priv->cmd->itm == priv->itm) {
1428 priv->cmd_itm_next=priv->cmd->itm;
1429 priv->cmd_next=priv->cmd->next;
1430 if (priv->cmd_itm_next && !priv->cmd_itm_next->next)
1431 ret->type=type_nav_destination;
1433 delta=priv->cmd->delta;
1437 ret->type=type_nav_left_1;
1438 else if (delta < 105)
1439 ret->type=type_nav_left_2;
1440 else if (delta < 165)
1441 ret->type=type_nav_left_3;
1443 ret->type=type_none;
1446 ret->type=type_nav_right_1;
1447 else if (delta < 105)
1448 ret->type=type_nav_right_2;
1449 else if (delta < 165)
1450 ret->type=type_nav_right_3;
1452 ret->type=type_none;
1458 priv->attr_next=attr_navigation_short;
1460 ret->id_lo=priv->itm->dest_count;
1461 dbg(1,"type=%d\n", ret->type);
1465 static struct item *
1466 navigation_map_get_item_byid(struct map_rect_priv *priv, int id_hi, int id_lo)
1469 navigation_map_rect_init(priv);
1470 while ((ret=navigation_map_get_item(priv))) {
1471 if (ret->id_hi == id_hi && ret->id_lo == id_lo)
1477 static struct map_methods navigation_map_meth = {
1480 navigation_map_destroy,
1481 navigation_map_rect_new,
1482 navigation_map_rect_destroy,
1483 navigation_map_get_item,
1484 navigation_map_get_item_byid,
1490 static struct map_priv *
1491 navigation_map_new(struct map_methods *meth, struct attr **attrs)
1493 struct map_priv *ret;
1494 struct attr *navigation_attr;
1496 navigation_attr=attr_search(attrs, NULL, attr_navigation);
1497 if (! navigation_attr)
1499 ret=g_new0(struct map_priv, 1);
1500 *meth=navigation_map_meth;
1501 ret->navigation=navigation_attr->u.navigation;
1508 navigation_init(void)
1510 plugin_register_map_type("navigation", navigation_map_new);