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"
39 #include "vehicleprofile.h"
41 #include "navit_nls.h"
45 static int roundabout_extra_length=50;
65 struct item_hash *hash;
66 struct vehicleprofile *vehicleprofile;
67 struct navigation_itm *first;
68 struct navigation_itm *last;
69 struct navigation_command *cmd_first;
70 struct navigation_command *cmd_last;
71 struct callback_list *callback_speech;
72 struct callback_list *callback;
74 struct speech *speech;
76 struct item item_last;
78 int turn_around_limit;
80 struct callback *route_cb;
81 int announce[route_item_last-route_item_first+1][3];
87 int distances[]={1,2,3,4,5,10,25,50,75,100,150,200,250,300,400,500,750,-1};
90 struct navigation_command {
91 struct navigation_itm *itm;
92 struct navigation_command *next;
93 struct navigation_command *prev;
99 static void navigation_flush(struct navigation *this_);
102 * @brief Calculates the delta between two angles
103 * @param angle1 The first angle
104 * @param angle2 The second angle
105 * @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
109 angle_delta(int angle1, int angle2)
111 int delta=angle2-angle1;
120 angle_median(int angle1, int angle2)
122 int delta=angle_delta(angle1, angle2);
123 int ret=angle1+delta/2;
132 angle_opposite(int angle)
134 return ((angle+180)%360);
138 navigation_get_attr(struct navigation *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
142 dbg(1,"enter %s\n", attr_to_name(type));
145 attr->u.map=this_->map;
149 case attr_navigation_speech:
150 mr=map_rect_new(this_->map, NULL);
151 while ((item=map_rect_get_item(mr))) {
152 if (item->type != type_nav_none && item->type != type_nav_position) {
153 if (type == attr_item_type)
154 attr->u.item_type=item->type;
156 if (!item_attr_get(item, type, attr))
162 map_rect_destroy(mr);
174 navigation_set_attr(struct navigation *this_, struct attr *attr)
176 switch (attr->type) {
178 this_->speech=attr->u.speech;
187 navigation_new(struct attr *parent, struct attr **attrs)
191 struct navigation *ret=g_new0(struct navigation, 1);
192 ret->hash=item_hash_new();
193 ret->callback=callback_list_new();
194 ret->callback_speech=callback_list_new();
196 ret->distance_turn=50;
197 ret->turn_around_limit=3;
198 ret->navit=parent->u.navit;
199 ret->tell_street_name=1;
201 for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
202 for (i = 0 ; i < 3 ; i++) {
203 ret->announce[j][i]=-1;
207 if ((attr=attr_search(attrs, NULL, attr_tell_street_name))) {
208 ret->tell_street_name = attr->u.num;
210 if ((attr=attr_search(attrs, NULL, attr_delay))) {
211 ret->delay = attr->u.num;
218 navigation_set_announce(struct navigation *this_, enum item_type type, int *level)
221 if (type < route_item_first || type > route_item_last) {
222 dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
225 for (i = 0 ; i < 3 ; i++)
226 this_->announce[type-route_item_first][i]=level[i];
231 navigation_get_announce_level(struct navigation *this_, enum item_type type, int dist)
235 if (type < route_item_first || type > route_item_last)
237 for (i = 0 ; i < 3 ; i++) {
238 if (dist <= this_->announce[type-route_item_first][i])
246 * @brief Holds a way that one could possibly drive from a navigation item
248 struct navigation_way {
249 struct navigation_way *next; /**< Pointer to a linked-list of all navigation_ways from this navigation item */
250 short dir; /**< The direction -1 or 1 of the way */
251 short angle2; /**< The angle one has to steer to drive from the old item to this street */
252 int flags; /**< The flags of the way */
253 struct item item; /**< The item of the way */
258 struct navigation_itm {
259 struct navigation_way way;
261 struct coord start,end;
267 int told; /**< Indicates if this item's announcement has been told earlier and should not be told again*/
268 int streetname_told; /**< Indicates if this item's streetname has been told in speech navigation*/
270 struct navigation_itm *next;
271 struct navigation_itm *prev;
274 static int is_way_allowed(struct navigation *nav, struct navigation_way *way, int mode);
277 navigation_get_announce_level_cmd(struct navigation *this_, struct navigation_itm *itm, struct navigation_command *cmd, int distance)
279 int level2,level=navigation_get_announce_level(this_, itm->way.item.type, distance);
280 if (this_->cmd_first->itm->prev) {
281 level2=navigation_get_announce_level(this_, cmd->itm->prev->way.item.type, distance);
290 road_angle(struct coord *c1, struct coord *c2, int dir)
292 int ret=transform_get_angle_delta(c1, c2, dir);
293 dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
298 *get_count_str(int n)
302 /* TRANSLATORS: the following counts refer to streets */
303 return _("zeroth"); // Not sure if this exists, neither if it will ever be needed
322 *get_exit_count_str(int n)
326 /* TRANSLATORS: the following counts refer to roundabout exits */
327 return _("zeroth exit"); // Not sure if this exists, neither if it will ever be needed
329 return _("first exit");
331 return _("second exit");
333 return _("third exit");
335 return _("fourth exit");
337 return _("fifth exit");
339 return _("sixth exit");
345 round_distance(int dist)
368 dist=(dist+500)/1000;
371 dist=(dist+5000)/10000;
376 round_for_vocabulary(int vocabulary, int dist, int factor)
378 if (!(vocabulary & 256)) {
380 dist=(dist+factor/2)/factor;
383 if (!(vocabulary & 255)) {
385 while (distances[i] > 0) {
386 if (!i || abs(distances[i]-dist) <= d) {
387 d=abs(distances[i]-dist);
390 if (distances[i] > dist)
394 dbg(0,"converted %d to %d with factor %d\n",dist,distances[m],factor);
401 vocabulary_last(int vocabulary)
404 if (vocabulary == 65535)
406 while (distances[i] > 0)
408 return distances[i-1];
412 get_distance(struct navigation *nav, int dist, enum attr_type type, int is_length)
414 int imperial=0,vocabulary=65535;
417 if (type == attr_navigation_long) {
419 return g_strdup_printf(_("%d m"), dist);
421 return g_strdup_printf(_("in %d m"), dist);
423 if (navit_get_attr(nav->navit, attr_imperial, &attr, NULL))
425 if (nav->speech && speech_get_attr(nav->speech, attr_vocabulary_distances, &attr, NULL))
426 vocabulary=attr.u.num;
428 if (dist*FEET_PER_METER < vocabulary_last(vocabulary)) {
429 dist=round_for_vocabulary(vocabulary, dist*FEET_PER_METER, 1);
431 return g_strdup_printf(_("%d feet"), dist);
433 return g_strdup_printf(_("in %d feet"), dist);
436 if (dist < vocabulary_last(vocabulary)) {
437 dist=round_for_vocabulary(vocabulary, dist, 1);
439 return g_strdup_printf(_("%d meters"), dist);
441 return g_strdup_printf(_("in %d meters"), dist);
445 dist=round_for_vocabulary(vocabulary, dist*FEET_PER_METER*1000/FEET_PER_MILE, 1000);
447 dist=round_for_vocabulary(vocabulary, dist, 1000);
449 int rem=(dist/100)%10;
453 return g_strdup_printf(_("%d.%d miles"), dist/1000, rem);
455 return g_strdup_printf(_("in %d.%d miles"), dist/1000, rem);
458 return g_strdup_printf(_("%d.%d kilometers"), dist/1000, rem);
460 return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
466 return g_strdup_printf(ngettext("one mile","%d miles", dist/1000), dist/1000);
468 return g_strdup_printf(ngettext("in one mile","in %d miles", dist/1000), dist/1000);
471 return g_strdup_printf(ngettext("one kilometer","%d kilometers", dist/1000), dist/1000);
473 return g_strdup_printf(ngettext("in one kilometer","in %d kilometers", dist/1000), dist/1000);
479 * @brief This calculates the angle with which an item starts or ends
481 * This function can be used to get the angle an item (from a route graph map)
482 * starts or ends with. Note that the angle will point towards the inner of
485 * This is meant to be used with items from a route graph map
486 * With other items this will probably not be optimal...
488 * @param w The way which should be calculated
491 calculate_angle(struct navigation_way *w)
493 struct coord cbuf[2];
494 struct item *ritem; // the "real" item
500 mr = map_rect_new(w->item.map, NULL);
504 ritem = map_rect_get_item_byid(mr, w->item.id_hi, w->item.id_lo);
506 dbg(1,"Item from segment not found on map!\n");
507 map_rect_destroy(mr);
511 if (ritem->type < type_line || ritem->type >= type_area) {
512 map_rect_destroy(mr);
515 if (item_attr_get(ritem, attr_flags, &attr))
519 if (item_attr_get(ritem, attr_street_name, &attr))
520 w->name1=map_convert_string(ritem->map,attr.u.str);
523 if (item_attr_get(ritem, attr_street_name_systematic, &attr))
524 w->name2=map_convert_string(ritem->map,attr.u.str);
529 if (item_coord_get(ritem, cbuf, 2) != 2) {
530 dbg(1,"Using calculate_angle() with a less-than-two-coords-item?\n");
531 map_rect_destroy(mr);
535 while (item_coord_get(ritem, &c, 1)) {
541 if (item_coord_get(ritem, cbuf, 2) != 2) {
542 dbg(1,"Using calculate_angle() with a less-than-two-coords-item?\n");
543 map_rect_destroy(mr);
551 map_rect_destroy(mr);
553 w->angle2=road_angle(&cbuf[1],&cbuf[0],0);
557 * @brief Returns the time (in seconds) one will drive between two navigation items
559 * This function returns the time needed to drive between two items, including both of them,
562 * @param from The first item
563 * @param to The last item
564 * @return The travel time in seconds, or -1 on error
567 navigation_time(struct navigation_itm *from, struct navigation_itm *to)
569 struct navigation_itm *cur;
591 * @brief Clears the ways one can drive from itm
593 * @param itm The item that should have its ways cleared
596 navigation_itm_ways_clear(struct navigation_itm *itm)
598 struct navigation_way *c,*n;
603 map_convert_free(c->name1);
604 map_convert_free(c->name2);
609 itm->way.next = NULL;
613 * @brief Updates the ways one can drive from itm
615 * This updates the list of possible ways to drive to from itm. The item "itm" is on
616 * and the next navigation item are excluded.
618 * @param itm The item that should be updated
619 * @param graph_map The route graph's map that these items are on
622 navigation_itm_ways_update(struct navigation_itm *itm, struct map *graph_map)
624 struct map_selection coord_sel;
625 struct map_rect *g_rect; // Contains a map rectangle from the route graph's map
626 struct item *i,*sitem;
627 struct attr sitem_attr,direction_attr;
628 struct navigation_way *w,*l;
630 navigation_itm_ways_clear(itm);
632 // These values cause the code in route.c to get us only the route graph point and connected segments
633 coord_sel.next = NULL;
634 coord_sel.u.c_rect.lu = itm->start;
635 coord_sel.u.c_rect.rl = itm->start;
636 // the selection's order is ignored
638 g_rect = map_rect_new(graph_map, &coord_sel);
640 i = map_rect_get_item(g_rect);
641 if (!i || i->type != type_rg_point) { // probably offroad?
648 i = map_rect_get_item(g_rect);
654 if (i->type != type_rg_segment) {
658 if (!item_attr_get(i,attr_street_item,&sitem_attr)) {
659 dbg(1, "Got no street item for route graph item in entering_straight()\n");
663 if (!item_attr_get(i,attr_direction,&direction_attr)) {
667 sitem = sitem_attr.u.item;
668 if (sitem->type == type_street_turn_restriction_no || sitem->type == type_street_turn_restriction_only)
671 if (item_is_equal(itm->way.item,*sitem) || ((itm->prev) && item_is_equal(itm->prev->way.item,*sitem))) {
676 w = g_new(struct navigation_way, 1);
677 w->dir = direction_attr.u.num;
683 map_rect_destroy(g_rect);
689 navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *end)
691 struct navigation_itm *itm;
692 struct navigation_command *cmd;
693 dbg(2,"enter this_=%p this_->first=%p this_->cmd_first=%p end=%p\n", this_, this_->first, this_->cmd_first, end);
694 if (this_->cmd_first)
695 dbg(2,"this_->cmd_first->itm=%p\n", this_->cmd_first->itm);
696 while (this_->first && this_->first != end) {
698 dbg(3,"destroying %p\n", itm);
699 item_hash_remove(this_->hash, &itm->way.item);
700 this_->first=itm->next;
702 this_->first->prev=NULL;
703 if (this_->cmd_first && this_->cmd_first->itm == itm->next) {
704 cmd=this_->cmd_first;
705 this_->cmd_first=cmd->next;
707 cmd->next->prev = NULL;
711 map_convert_free(itm->way.name1);
712 map_convert_free(itm->way.name2);
713 navigation_itm_ways_clear(itm);
718 if (! this_->first && end)
719 dbg(0,"end wrong\n");
720 dbg(2,"ret this_->first=%p this_->cmd_first=%p\n",this_->first, this_->cmd_first);
724 navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
726 struct attr length, time, speed;
728 if (! item_attr_get(ritem, attr_length, &length)) {
729 dbg(0,"no length\n");
732 if (! item_attr_get(ritem, attr_time, &time)) {
736 if (! item_attr_get(ritem, attr_speed, &speed)) {
741 dbg(1,"length=%d time=%d speed=%d\n", length.u.num, time.u.num, speed.u.num);
742 itm->length=length.u.num;
743 itm->time=time.u.num;
744 itm->speed=speed.u.num;
748 * @brief This check if an item is part of a roundabout
750 * @param itm The item to be checked
751 * @return True if the item is part of a roundabout
754 check_roundabout(struct navigation_itm *itm, struct map *graph_map)
756 struct map_selection coord_sel;
757 struct map_rect *g_rect; // Contains a map rectangle from the route graph's map
758 struct item *i,*sitem;
759 struct attr sitem_attr,flags_attr;
761 // These values cause the code in route.c to get us only the route graph point and connected segments
762 coord_sel.next = NULL;
763 coord_sel.u.c_rect.lu = itm->start;
764 coord_sel.u.c_rect.rl = itm->start;
765 // the selection's order is ignored
767 g_rect = map_rect_new(graph_map, &coord_sel);
769 i = map_rect_get_item(g_rect);
770 if (!i || i->type != type_rg_point) { // probably offroad?
771 map_rect_destroy(g_rect);
776 i = map_rect_get_item(g_rect);
782 if (i->type != type_rg_segment) {
786 if (!item_attr_get(i,attr_street_item,&sitem_attr)) {
790 sitem = sitem_attr.u.item;
791 if (item_is_equal(itm->way.item,*sitem)) {
792 if (item_attr_get(i,attr_flags,&flags_attr) && (flags_attr.u.num & AF_ROUNDABOUT)) {
793 map_rect_destroy(g_rect);
799 map_rect_destroy(g_rect);
803 static struct navigation_itm *
804 navigation_itm_new(struct navigation *this_, struct item *ritem)
806 struct navigation_itm *ret=g_new0(struct navigation_itm, 1);
809 struct map *graph_map = NULL;
810 struct attr street_item,direction,route_attr;
816 ret->streetname_told=0;
817 if (! item_attr_get(ritem, attr_street_item, &street_item)) {
818 dbg(1, "no street item\n");
823 if (item_attr_get(ritem, attr_direction, &direction))
824 ret->way.dir=direction.u.num;
828 sitem=street_item.u.item;
829 ret->way.item=*sitem;
830 item_hash_insert(this_->hash, sitem, ret);
831 mr=map_rect_new(sitem->map, NULL);
832 if (! (sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo)))
834 if (item_attr_get(sitem, attr_street_name, &attr))
835 ret->way.name1=map_convert_string(sitem->map,attr.u.str);
836 if (item_attr_get(sitem, attr_street_name_systematic, &attr))
837 ret->way.name2=map_convert_string(sitem->map,attr.u.str);
838 navigation_itm_update(ret, ritem);
840 while (item_coord_get(ritem, &c[i], 1)) {
841 dbg(1, "coord %d 0x%x 0x%x\n", i, c[i].x ,c[i].y);
850 dbg(1,"count=%d\n", i);
853 ret->way.angle2=road_angle(&c[0], &c[1], 0);
854 ret->angle_end=road_angle(&c[i-1], &c[i], 0);
859 item_attr_get(ritem, attr_route, &route_attr);
860 graph_map = route_get_graph_map(route_attr.u.route);
861 if (check_roundabout(ret, graph_map)) {
862 ret->way.flags |= AF_ROUNDABOUT;
865 dbg(1,"i=%d start %d end %d '%s' '%s'\n", i, ret->way.angle2, ret->angle_end, ret->way.name1, ret->way.name2);
866 map_rect_destroy(mr);
869 ret->start=ret->end=this_->last->end;
874 this_->last->next=ret;
875 ret->prev=this_->last;
877 navigation_itm_ways_update(ret,graph_map);
880 dbg(1,"ret=%p\n", ret);
886 * @brief Counts how many times a driver could turn right/left
888 * This function counts how many times the driver theoretically could
889 * turn right/left between two navigation items, not counting the final
892 * @param from The navigation item which should form the start
893 * @param to The navigation item which should form the end
894 * @param direction Set to < 0 to count turns to the left >= 0 for turns to the right
895 * @return The number of possibilities to turn or -1 on error
898 count_possible_turns(struct navigation *nav, struct navigation_itm *from, struct navigation_itm *to, int direction)
901 struct navigation_itm *curr;
902 struct navigation_way *w;
906 while (curr && (curr != to)) {
910 if (is_way_allowed(nav, w, 4)) {
912 if (angle_delta(curr->prev->angle_end, w->angle2) < 0) {
917 if (angle_delta(curr->prev->angle_end, w->angle2) > 0) {
928 if (!curr) { // from does not lead to to?
936 * @brief Calculates distance and time to the destination
938 * This function calculates the distance and the time to the destination of a
939 * navigation. If incr is set, this is only calculated for the first navigation
940 * item, which is a lot faster than re-calculation the whole destination, but works
941 * only if the rest of the navigation already has been calculated.
943 * @param this_ The navigation whose destination / time should be calculated
944 * @param incr Set this to true to only calculate the first item. See description.
947 calculate_dest_distance(struct navigation *this_, int incr)
949 int len=0, time=0, count=0;
950 struct navigation_itm *next,*itm=this_->last;
951 dbg(1, "enter this_=%p, incr=%d\n", this_, incr);
954 dbg(2, "old values: (%p) time=%d lenght=%d\n", itm, itm->dest_length, itm->dest_time);
956 dbg(2, "old values: itm is null\n");
960 dbg(2, "itm values: time=%d lenght=%d\n", itm->length, itm->time);
961 dbg(2, "next values: (%p) time=%d lenght=%d\n", next, next->dest_length, next->dest_time);
962 itm->dest_length=next->dest_length+itm->length;
963 itm->dest_count=next->dest_count+1;
964 itm->dest_time=next->dest_time+itm->time;
965 dbg(2, "new values: time=%d lenght=%d\n", itm->dest_length, itm->dest_time);
971 itm->dest_length=len;
973 itm->dest_count=count++;
976 dbg(1,"len %d time %d\n", len, time);
980 * @brief Checks if two navigation items are on the same street
982 * This function checks if two navigation items are on the same street. It returns
983 * true if either their name or their "systematic name" (e.g. "A6" or "B256") are the
986 * @param old The first item to be checked
987 * @param new The second item to be checked
988 * @return True if both old and new are on the same street
991 is_same_street2(char *old_name1, char *old_name2, char *new_name1, char *new_name2)
993 if (old_name1 && new_name1 && !strcmp(old_name1, new_name1)) {
994 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (1.)\n", old_name2, new_name2, old_name1, new_name1);
997 if (old_name2 && new_name2 && !strcmp(old_name2, new_name2)) {
998 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' yes (2.)\n", old_name2, new_name2, old_name1, new_name1);
1001 dbg(1,"is_same_street: '%s' '%s' vs '%s' '%s' no\n", old_name2, new_name2, old_name1, new_name1);
1007 * @brief Checks if two navigation items are on the same street
1009 * This function checks if two navigation items are on the same street. It returns
1010 * true if the first part of their "systematic name" is equal. If the "systematic name" is
1011 * for example "A352/E3" (a german highway which at the same time is part of the international
1012 * E-road network), it would only search for "A352" in the second item's systematic name.
1014 * @param old The first item to be checked
1015 * @param new The second item to be checked
1016 * @return True if the "systematic name" of both items matches. See description.
1019 is_same_street_systematic(struct navigation_itm *old, struct navigation_itm *new)
1021 int slashold,slashnew;
1022 if (!old->name2 || !new->name2)
1024 slashold=strcspn(old->name2, "/");
1025 slashnew=strcspn(new->name2, "/");
1026 if (slashold != slashnew || strncmp(old->name2, new->name2, slashold))
1033 * @brief Check if there are multiple possibilities to drive from old
1035 * This function checks, if there are multiple streets connected to the exit of "old".
1036 * Sometimes it happens that an item on a map is just segmented, without any other streets
1037 * being connected there, and it is not useful if navit creates a maneuver there.
1039 * @param new The navigation item we're driving to
1040 * @return True if there are multiple streets
1043 maneuver_multiple_streets(struct navigation_itm *new)
1045 if (new->way.next) {
1054 * @brief Check if the new item is entered "straight"
1056 * This function checks if the new item is entered "straight" from the old item, i.e. if there
1057 * is no other street one could take from the old item on with less steering.
1059 * @param new The navigation item we're driving to
1060 * @param diff The absolute angle one needs to steer to drive to this item
1061 * @return True if the new item is entered "straight"
1064 maneuver_straight(struct navigation_itm *new, int diff)
1067 struct navigation_way *w;
1070 dbg(1,"diff=%d\n", diff);
1072 curr_diff=abs(angle_delta(new->prev->angle_end, w->angle2));
1073 dbg(1,"curr_diff=%d\n", curr_diff);
1074 if (curr_diff < diff) {
1083 static int maneuver_category(enum item_type type)
1088 case type_street_1_city:
1090 case type_street_2_city:
1092 case type_street_3_city:
1094 case type_street_4_city:
1096 case type_highway_city:
1098 case type_street_1_land:
1100 case type_street_2_land:
1102 case type_street_3_land:
1104 case type_street_4_land:
1106 case type_street_n_lanes:
1108 case type_highway_land:
1112 case type_roundabout:
1124 is_way_allowed(struct navigation *nav, struct navigation_way *way, int mode)
1126 if (!nav->vehicleprofile)
1128 return !way->flags || ((way->flags & (way->dir >= 0 ? nav->vehicleprofile->flags_forward_mask : nav->vehicleprofile->flags_reverse_mask)) == nav->vehicleprofile->flags);
1132 * @brief Checks if navit has to create a maneuver to drive from old to new
1134 * This function checks if it has to create a "maneuver" - i.e. guide the user - to drive
1135 * from "old" to "new".
1137 * @param old The old navigation item, where we're coming from
1138 * @param new The new navigation item, where we're going to
1139 * @param delta The angle the user has to steer to navigate from old to new
1140 * @param reason A text string explaining how the return value resulted
1141 * @return True if navit should guide the user, false otherwise
1144 maneuver_required2(struct navigation *nav, struct navigation_itm *old, struct navigation_itm *new, int *delta, char **reason)
1146 int ret=0,d,dw,dlim;
1148 struct navigation_way *w;
1149 int cat,ncat,wcat,maxcat,left=-180,right=180,is_unambigous=0,is_same_street;
1151 dbg(1,"enter %p %p %p\n",old, new, delta);
1152 d=angle_delta(old->angle_end, new->way.angle2);
1153 if (!new->way.next) {
1154 /* No announcement necessary */
1155 r="no: Only one possibility";
1156 } else if (!new->way.next->next && new->way.next->item.type == type_ramp && !is_way_allowed(nav,new->way.next,1)) {
1157 /* If the other way is only a ramp and it is one-way in the wrong direction, no announcement necessary */
1161 if ((old->way.flags & AF_ROUNDABOUT) && ! (new->way.flags & AF_ROUNDABOUT)) {
1162 r="yes: leaving roundabout";
1164 } else if (!(old->way.flags & AF_ROUNDABOUT) && (new->way.flags & AF_ROUNDABOUT)) {
1165 r="no: entering roundabout";
1166 } else if ((old->way.flags & AF_ROUNDABOUT) && (new->way.flags & AF_ROUNDABOUT))
1167 r="no: staying in roundabout";
1169 if (!r && abs(d) > 75) {
1170 /* always make an announcement if you have to make a sharp turn */
1171 r="yes: delta over 75";
1174 cat=maneuver_category(old->way.item.type);
1175 ncat=maneuver_category(new->way.item.type);
1177 /* Check whether the street keeps its name */
1178 is_same_street=is_same_street2(old->way.name1, old->way.name2, new->way.name1, new->way.name2);
1182 dw=angle_delta(old->angle_end, w->angle2);
1190 wcat=maneuver_category(w->item.type);
1191 /* If any other street has the same name but isn't a highway (a highway might split up temporarily), then
1192 we can't use the same name criterium */
1193 if (is_same_street && is_same_street2(old->way.name1, old->way.name2, w->name1, w->name2) && (cat != 7 || wcat != 7) && is_way_allowed(nav,w,2))
1195 /* Even if the ramp has the same name, announce it */
1196 if (new->way.item.type == type_ramp && old->way.item.type != type_ramp)
1198 /* Mark if the street has a higher or the same category */
1203 /* get the delta limit for checking for other streets. It is lower if the street has no other
1204 streets of the same or higher category */
1209 /* if the street is really straight, the others might be closer to straight */
1212 if ((maxcat == ncat && maxcat == cat) || (ncat == 0 && cat == 0))
1213 dlim=abs(d)*620/256;
1214 else if (maxcat < ncat && maxcat < cat)
1215 dlim=abs(d)*128/256;
1216 if (left < -dlim && right > dlim)
1218 if (!is_same_street && is_unambigous < 1) {
1220 r="yes: not same street or ambigous";
1222 r="no: same street and unambigous";
1224 r=g_strdup_printf("yes: d %d left %d right %d dlim=%d cat old:%d new:%d max:%d unambigous=%d same_street=%d", d, left, right, dlim, cat, ncat, maxcat, is_unambigous, is_same_street);
1234 if (new->item.type == old->item.type || (new->item.type != type_ramp && old->item.type != type_ramp)) {
1235 if (is_same_street2(old, new)) {
1236 if (! entering_straight(new, abs(*delta))) {
1237 dbg(1, "maneuver_required: Not driving straight: yes\n");
1239 *reason="yes: Not driving straight";
1243 if (check_multiple_streets(new)) {
1244 if (entering_straight(new,abs(*delta)*2)) {
1246 *reason="no: delta < ext_limit for same name";
1250 *reason="yes: delta > ext_limit for same name";
1253 dbg(1, "maneuver_required: Staying on the same street: no\n");
1255 *reason="no: Staying on same street";
1260 dbg(1, "maneuver_required: old or new is ramp\n");
1262 if (old->item.type == type_ramp && (new->item.type == type_highway_city || new->item.type == type_highway_land)) {
1263 dbg(1, "no_maneuver_required: old is ramp new is highway\n");
1265 *reason="no: old is ramp new is highway";
1270 if (old->crossings_end == 2) {
1271 dbg(1, "maneuver_required: only 2 connections: no\n");
1275 dbg(1,"delta=%d-%d=%d\n", new->way.angle2, old->angle_end, *delta);
1276 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))) {
1277 dbg(1, "maneuver_required: highway changed name\n");
1279 *reason="yes: highway changed name";
1282 if (abs(*delta) < straight_limit) {
1283 if (! entering_straight(new,abs(*delta))) {
1285 *reason="yes: not straight";
1286 dbg(1, "maneuver_required: not driving straight: yes\n");
1290 dbg(1, "maneuver_required: delta(%d) < %d: no\n", *delta, straight_limit);
1292 *reason="no: delta < limit";
1295 if (abs(*delta) < ext_straight_limit) {
1296 if (entering_straight(new,abs(*delta)*2)) {
1298 *reason="no: delta < ext_limit";
1303 if (! check_multiple_streets(new)) {
1304 dbg(1, "maneuver_required: only one possibility: no\n");
1306 *reason="no: only one possibility";
1310 dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
1312 *reason="yes: delta >= limit";
1317 static struct navigation_command *
1318 command_new(struct navigation *this_, struct navigation_itm *itm, int delta)
1320 struct navigation_command *ret=g_new0(struct navigation_command, 1);
1321 dbg(1,"enter this_=%p itm=%p delta=%d\n", this_, itm, delta);
1324 if (itm && itm->prev && itm->way.next && itm->prev->way.next && !(itm->way.flags & AF_ROUNDABOUT) && (itm->prev->way.flags & AF_ROUNDABOUT)) {
1328 struct navigation_itm *itm2=itm->prev;
1329 int exit_angle=angle_median(itm->prev->angle_end, itm->way.next->angle2);
1330 dbg(1,"exit %d median from %d,%d\n", exit_angle,itm->prev->angle_end, itm->way.next->angle2);
1331 while (itm2 && (itm2->way.flags & AF_ROUNDABOUT)) {
1333 angle=itm2->angle_end;
1336 if (itm2 && itm2->next && itm2->next->way.next) {
1338 entry_angle=angle_median(angle_opposite(itm2->way.angle2), itm2->way.next->angle2);
1339 dbg(1,"entry %d median from %d(%d),%d\n", entry_angle,angle_opposite(itm2->way.angle2), itm2->way.angle2, itm2->way.next->angle2);
1341 entry_angle=angle_opposite(angle);
1343 dbg(0,"entry %d exit %d\n", entry_angle, exit_angle);
1344 ret->roundabout_delta=angle_delta(entry_angle, exit_angle);
1345 ret->length=len+roundabout_extra_length;
1347 if (this_->cmd_last) {
1348 this_->cmd_last->next=ret;
1349 ret->prev = this_->cmd_last;
1351 this_->cmd_last=ret;
1353 if (!this_->cmd_first)
1354 this_->cmd_first=ret;
1359 make_maneuvers(struct navigation *this_, struct route *route)
1361 struct navigation_itm *itm, *last=NULL, *last_itm=NULL;
1364 this_->cmd_last=NULL;
1365 this_->cmd_first=NULL;
1368 if (maneuver_required2(this_, last_itm, itm,&delta,NULL)) {
1369 command_new(this_, itm, delta);
1376 command_new(this_, last_itm, 0);
1380 contains_suffix(char *name, char *suffix)
1384 if (strlen(name) < strlen(suffix))
1386 return !g_strcasecmp(name+strlen(name)-strlen(suffix), suffix);
1390 replace_suffix(char *name, char *search, char *replace)
1392 int len=strlen(name)-strlen(search);
1393 char *ret=g_malloc(len+strlen(replace)+1);
1394 strncpy(ret, name, len);
1395 strcpy(ret+len, replace);
1396 if (isupper(name[len])) {
1397 ret[len]=toupper(ret[len]);
1404 navigation_item_destination(struct navigation *nav, struct navigation_itm *itm, struct navigation_itm *next, char *prefix)
1406 char *ret=NULL,*name1,*sep,*name2;
1409 int vocabulary1=65535;
1410 int vocabulary2=65535;
1415 if (nav->speech && speech_get_attr(nav->speech, attr_vocabulary_name, &attr, NULL))
1416 vocabulary1=attr.u.num;
1417 if (nav->speech && speech_get_attr(nav->speech, attr_vocabulary_name_systematic, &attr, NULL))
1418 vocabulary2=attr.u.num;
1425 if(!n1 && !n2 && itm->way.item.type == type_ramp && vocabulary2) {
1426 dbg(1,">> Next is ramp %lx current is %lx \n", itm->way.item.type, next->way.item.type);
1428 if(next->way.item.type == type_ramp)
1430 if(itm->way.item.type == type_highway_city || itm->way.item.type == type_highway_land )
1431 return g_strdup_printf("%s%s",prefix,_("exit")); /* %FIXME Can this even be reached? */
1433 return g_strdup_printf("%s%s",prefix,_("into the ramp"));
1441 for (i = 0 ; i < sizeof(suffixes)/sizeof(suffixes[0]) ; i++) {
1442 if (contains_suffix(n1,suffixes[i].fullname)) {
1443 sex=suffixes[i].sex;
1447 if (contains_suffix(n1,suffixes[i].abbrev)) {
1448 sex=suffixes[i].sex;
1449 name1=replace_suffix(n1, suffixes[i].abbrev, suffixes[i].fullname);
1462 /* TRANSLATORS: Arguments: 1: Prefix (Space if required) 2: Street Name 3: Separator (Space if required), 4: Systematic Street Name */
1463 ret=g_strdup_printf(_("%sinto the street %s%s%s"),prefix,n1, sep, name2);
1466 /* 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 */
1467 ret=g_strdup_printf(_("%sinto the %s%s%s|male form"),prefix,name1, sep, name2);
1470 /* 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 */
1471 ret=g_strdup_printf(_("%sinto the %s%s%s|female form"),prefix,name1, sep, name2);
1474 /* 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 */
1475 ret=g_strdup_printf(_("%sinto the %s%s%s|neutral form"),prefix,name1, sep, name2);
1481 /* TRANSLATORS: gives the name of the next road to turn into (into the E17) */
1482 ret=g_strdup_printf(_("%sinto the %s"),prefix,n2);
1484 while (name1 && *name1) {
1500 show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type, int connect)
1502 /* TRANSLATORS: right, as in 'Turn right' */
1503 char *dir=_("right"),*strength="";
1504 int distance=itm->dest_length-cmd->itm->dest_length;
1506 int delta=cmd->delta;
1508 int strength_needed;
1510 int count_roundabout;
1511 struct navigation_itm *cur;
1512 struct navigation_way *w;
1515 level = -2; // level = -2 means "connect to another maneuver via 'then ...'"
1520 w = itm->next->way.next;
1521 strength_needed = 0;
1522 if (angle_delta(itm->next->way.angle2,itm->angle_end) < 0) {
1524 if (angle_delta(w->angle2,itm->angle_end) < 0) {
1525 strength_needed = 1;
1532 if (angle_delta(w->angle2,itm->angle_end) > 0) {
1533 strength_needed = 1;
1541 /* TRANSLATORS: left, as in 'Turn left' */
1546 if (strength_needed) {
1548 /* TRANSLATORS: Don't forget the ending space */
1549 strength=_("easily ");
1550 } else if (delta < 105) {
1552 } else if (delta < 165) {
1553 /* TRANSLATORS: Don't forget the ending space */
1554 strength=_("strongly ");
1555 } else if (delta < 180) {
1556 /* TRANSLATORS: Don't forget the ending space */
1557 strength=_("really strongly ");
1559 dbg(1,"delta=%d\n", delta);
1560 /* TRANSLATORS: Don't forget the ending space */
1561 strength=_("unknown ");
1564 if (type != attr_navigation_long_exact)
1565 distance=round_distance(distance);
1566 if (type == attr_navigation_speech) {
1567 if (nav->turn_around && nav->turn_around == nav->turn_around_limit)
1568 return g_strdup(_("When possible, please turn around"));
1570 level=navigation_get_announce_level_cmd(nav, itm, cmd, distance-cmd->length);
1572 dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->way.item.type);
1575 if (cmd->itm->prev->way.flags & AF_ROUNDABOUT) {
1576 cur = cmd->itm->prev;
1577 count_roundabout = 0;
1578 while (cur && (cur->way.flags & AF_ROUNDABOUT)) {
1579 if (cur->next->way.next && is_way_allowed(nav,cur->next->way.next,3)) { // If the next segment has no exit or the exit isn't allowed, don't count it
1586 return g_strdup(_("Enter the roundabout soon"));
1588 d = get_distance(nav, distance, type, 0);
1589 /* TRANSLATORS: %s is the distance to the roundabout */
1590 ret = g_strdup_printf(_("Enter the roundabout %s"), d);
1594 return g_strdup_printf(_("then leave the roundabout at the %s"), get_exit_count_str(count_roundabout));
1596 return g_strdup_printf(_("Leave the roundabout at the %s"), get_exit_count_str(count_roundabout));
1602 d=get_distance(nav, distance, type, 1);
1603 ret=g_strdup_printf(_("Follow the road for the next %s"), d);
1607 d=g_strdup(_("soon"));
1610 d=get_distance(nav, distance, attr_navigation_short, 0);
1613 skip_roads = count_possible_turns(nav,cmd->prev?cmd->prev->itm:nav->first,cmd->itm,cmd->delta);
1614 if (skip_roads > 0) {
1615 if (get_count_str(skip_roads+1)) {
1616 /* TRANSLATORS: First argument is the how manieth street to take, second the direction */
1617 ret = g_strdup_printf(_("Take the %1$s road to the %2$s"), get_count_str(skip_roads+1), dir);
1620 d = g_strdup_printf(_("after %i roads"), skip_roads);
1623 d=g_strdup(_("now"));
1627 skip_roads = count_possible_turns(nav,cmd->prev->itm,cmd->itm,cmd->delta);
1628 if (skip_roads > 0) {
1629 /* TRANSLATORS: First argument is the how manieth street to take, second the direction */
1630 if (get_count_str(skip_roads+1)) {
1631 ret = g_strdup_printf(_("then take the %1$s road to the %2$s"), get_count_str(skip_roads+1), dir);
1634 d = g_strdup_printf(_("after %i roads"), skip_roads);
1642 d=g_strdup(_("error"));
1644 if (cmd->itm->next) {
1645 int tellstreetname = 0;
1646 char *destination = NULL;
1648 if(type == attr_navigation_speech) { // In voice mode
1649 // In Voice Mode only tell the street name in level 1 or in level 0 if level 1
1652 if (level == 1) { // we are close to the intersection
1653 cmd->itm->streetname_told = 1; // remeber to be checked when we turn
1654 tellstreetname = 1; // Ok so we tell the name of the street
1658 if(cmd->itm->streetname_told == 0) // we are right at the intersection
1661 cmd->itm->streetname_told = 0; // reset just in case we come to the same street again
1668 if(nav->tell_street_name && tellstreetname)
1669 destination=navigation_item_destination(nav, cmd->itm, itm, " ");
1672 /* 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' */
1673 ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
1675 /* TRANSLATORS: First argument is strength, second direction, third how many roads to skip, fourth destination */
1676 ret=g_strdup_printf(_("then turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
1678 g_free(destination);
1681 ret=g_strdup_printf(_("You have reached your destination %s"), d);
1683 ret=g_strdup(_("then you have reached your destination."));
1691 * @brief Creates announcements for maneuvers, plus maneuvers immediately following the next maneuver
1693 * This function does create an announcement for the current maneuver and for maneuvers
1694 * immediately following that maneuver, if these are too close and we're in speech navigation.
1696 * @return An announcement that should be made
1699 show_next_maneuvers(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
1701 struct navigation_command *cur,*prev;
1702 int distance=itm->dest_length-cmd->itm->dest_length;
1703 int level, dist, i, time;
1704 int speech_time,time2nav;
1705 char *ret,*old,*buf,*next;
1707 if (type != attr_navigation_speech) {
1708 return show_maneuver(nav, itm, cmd, type, 0); // We accumulate maneuvers only in speech navigation
1711 level=navigation_get_announce_level(nav, itm->way.item.type, distance-cmd->length);
1714 return show_maneuver(nav, itm, cmd, type, 0); // We accumulate maneuvers only if they are close
1717 if (cmd->itm->told) {
1718 return g_strdup("");
1721 ret = show_maneuver(nav, itm, cmd, type, 0);
1722 time2nav = navigation_time(itm,cmd->itm->prev);
1728 while (cur && cur->itm) {
1729 // We don't merge more than 3 announcements...
1730 if (i > 1) { // if you change this, please also change the value below, that is used to terminate the loop
1734 next = show_maneuver(nav,prev->itm, cur, type, 0);
1736 speech_time = speech_estimate_duration(nav->speech,next);
1741 if (speech_time == -1) { // user didn't set cps
1742 speech_time = 30; // assume 3 seconds
1745 dist = prev->itm->dest_length - cur->itm->dest_length;
1746 time = navigation_time(prev->itm,cur->itm->prev);
1748 if (time >= (speech_time + 30)) { // 3 seconds for understanding what has been said
1753 buf = show_maneuver(nav, prev->itm, cur, type, 1);
1754 ret = g_strdup_printf("%s, %s", old, buf);
1756 if (nav->speech && speech_estimate_duration(nav->speech,ret) > time2nav) {
1759 i = 2; // This will terminate the loop
1764 // If the two maneuvers are *really* close, we shouldn't tell the second one again, because TTS won't be fast enough
1765 if (time <= speech_time) {
1778 navigation_call_callbacks(struct navigation *this_, int force_speech)
1780 int distance, level = 0;
1782 if (!this_->cmd_first)
1784 callback_list_call(this_->callback, 1, &p);
1785 dbg(1,"force_speech=%d turn_around=%d turn_around_limit=%d\n", force_speech, this_->turn_around, this_->turn_around_limit);
1786 distance=round_distance(this_->first->dest_length-this_->cmd_first->itm->dest_length);
1787 if (this_->turn_around_limit && this_->turn_around == this_->turn_around_limit) {
1788 dbg(1,"distance=%d distance_turn=%d\n", distance, this_->distance_turn);
1789 while (distance > this_->distance_turn) {
1790 this_->level_last=4;
1793 if (this_->distance_turn >= 500)
1794 this_->distance_turn*=2;
1796 this_->distance_turn=500;
1798 } else if (!this_->turn_around_limit || this_->turn_around == -this_->turn_around_limit+1) {
1799 this_->distance_turn=50;
1800 distance-=this_->cmd_first->length;
1801 level=navigation_get_announce_level_cmd(this_, this_->first, this_->cmd_first, distance);
1802 if (level < this_->level_last) {
1803 /* only tell if the level is valid for more than 3 seconds */
1804 int speed_distance=this_->first->speed*30/36;
1805 if (distance < speed_distance || navigation_get_announce_level_cmd(this_, this_->first, this_->cmd_first, distance-speed_distance) == level) {
1806 dbg(1,"distance %d speed_distance %d\n",distance,speed_distance);
1807 dbg(1,"level %d < %d\n", level, this_->level_last);
1808 this_->level_last=level;
1812 if (!item_is_equal(this_->cmd_first->itm->way.item, this_->item_last)) {
1813 this_->item_last=this_->cmd_first->itm->way.item;
1815 this_->curr_delay=this_->delay;
1819 if (this_->curr_delay) {
1820 this_->curr_delay--;
1821 if (!this_->curr_delay)
1827 this_->level_last=level;
1828 this_->curr_delay=0;
1829 dbg(1,"force_speech=%d distance=%d level=%d type=0x%x\n", force_speech, distance, level, this_->first->way.item.type);
1830 callback_list_call(this_->callback_speech, 1, &p);
1835 navigation_update(struct navigation *this_, struct route *route, struct attr *attr)
1838 struct map_rect *mr;
1839 struct item *ritem; /* Holds an item from the route map */
1840 struct item *sitem; /* Holds the corresponding item from the actual map */
1841 struct attr street_item,street_direction;
1842 struct navigation_itm *itm;
1843 struct attr vehicleprofile;
1844 int mode=0, incr=0, first=1;
1845 if (attr->type != attr_route_status)
1848 dbg(1,"enter %d\n", mode);
1849 if (attr->u.num == route_status_no_destination || attr->u.num == route_status_not_found || attr->u.num == route_status_path_done_new)
1850 navigation_flush(this_);
1851 if (attr->u.num != route_status_path_done_new && attr->u.num != route_status_path_done_incremental)
1856 map=route_get_map(this_->route);
1859 mr=map_rect_new(map, NULL);
1862 if (route_get_attr(route, attr_vehicleprofile, &vehicleprofile, NULL))
1863 this_->vehicleprofile=vehicleprofile.u.vehicleprofile;
1865 this_->vehicleprofile=NULL;
1867 while ((ritem=map_rect_get_item(mr))) {
1868 if (ritem->type == type_route_start && this_->turn_around > -this_->turn_around_limit+1)
1869 this_->turn_around--;
1870 if (ritem->type == type_route_start_reverse && this_->turn_around < this_->turn_around_limit)
1871 this_->turn_around++;
1872 if (ritem->type != type_street_route)
1874 if (first && item_attr_get(ritem, attr_street_item, &street_item)) {
1876 if (!item_attr_get(ritem, attr_direction, &street_direction))
1877 street_direction.u.num=0;
1878 sitem=street_item.u.item;
1879 dbg(1,"sitem=%p\n", sitem);
1880 itm=item_hash_lookup(this_->hash, sitem);
1881 dbg(2,"itm for item with id (0x%x,0x%x) is %p\n", sitem->id_hi, sitem->id_lo, itm);
1882 if (itm && itm->way.dir != street_direction.u.num) {
1883 dbg(2,"wrong direction\n");
1886 navigation_destroy_itms_cmds(this_, itm);
1888 navigation_itm_update(itm, ritem);
1891 dbg(1,"not on track\n");
1893 navigation_itm_new(this_, ritem);
1895 dbg(2,"turn_around=%d\n", this_->turn_around);
1897 navigation_destroy_itms_cmds(this_, NULL);
1900 navigation_itm_new(this_, NULL);
1901 make_maneuvers(this_,this_->route);
1903 calculate_dest_distance(this_, incr);
1905 navigation_call_callbacks(this_, FALSE);
1907 map_rect_destroy(mr);
1911 navigation_flush(struct navigation *this_)
1913 navigation_destroy_itms_cmds(this_, NULL);
1918 navigation_destroy(struct navigation *this_)
1920 navigation_flush(this_);
1921 item_hash_destroy(this_->hash);
1922 callback_list_destroy(this_->callback);
1923 callback_list_destroy(this_->callback_speech);
1928 navigation_register_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
1930 if (type == attr_navigation_speech)
1931 callback_list_add(this_->callback_speech, cb);
1933 callback_list_add(this_->callback, cb);
1938 navigation_unregister_callback(struct navigation *this_, enum attr_type type, struct callback *cb)
1940 if (type == attr_navigation_speech)
1941 callback_list_remove(this_->callback_speech, cb);
1943 callback_list_remove(this_->callback, cb);
1947 navigation_get_map(struct navigation *this_)
1949 struct attr *attrs[5];
1950 struct attr type,navigation,data,description;
1951 type.type=attr_type;
1952 type.u.str="navigation";
1953 navigation.type=attr_navigation;
1954 navigation.u.navigation=this_;
1955 data.type=attr_data;
1957 description.type=attr_description;
1958 description.u.str="Navigation";
1961 attrs[1]=&navigation;
1963 attrs[3]=&description;
1966 this_->map=map_new(NULL, attrs);
1971 struct navigation *navigation;
1974 struct map_rect_priv {
1975 struct navigation *nav;
1976 struct navigation_command *cmd;
1977 struct navigation_command *cmd_next;
1978 struct navigation_itm *itm;
1979 struct navigation_itm *itm_next;
1980 struct navigation_itm *cmd_itm;
1981 struct navigation_itm *cmd_itm_next;
1983 enum attr_type attr_next;
1986 struct navigation_way *ways;
1992 navigation_map_item_coord_get(void *priv_data, struct coord *c, int count)
1994 struct map_rect_priv *this=priv_data;
1995 if (this->ccount || ! count)
1997 *c=this->itm->start;
2003 navigation_map_item_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
2005 struct map_rect_priv *this_=priv_data;
2006 struct navigation_command *cmd=this_->cmd;
2007 struct navigation_itm *itm=this_->itm;
2008 struct navigation_itm *prev=itm->prev;
2009 attr->type=attr_type;
2017 if (cmd->itm != itm)
2023 int distance=this_->cmd_itm->dest_length-cmd->itm->dest_length;
2024 distance=round_distance(distance);
2025 attr->u.num=navigation_get_announce_level(this_->nav, this_->cmd_itm->way.item.type, distance-cmd->length);
2029 case attr_navigation_short:
2030 this_->attr_next=attr_navigation_long;
2032 this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
2036 case attr_navigation_long:
2037 this_->attr_next=attr_navigation_long_exact;
2039 this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
2043 case attr_navigation_long_exact:
2044 this_->attr_next=attr_navigation_speech;
2046 this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
2050 case attr_navigation_speech:
2051 this_->attr_next=attr_length;
2053 this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, this_->cmd, attr_type);
2058 this_->attr_next=attr_time;
2060 attr->u.num=this_->cmd_itm->dest_length-cmd->itm->dest_length;
2065 this_->attr_next=attr_destination_length;
2067 attr->u.num=this_->cmd_itm->dest_time-cmd->itm->dest_time;
2071 case attr_destination_length:
2072 attr->u.num=itm->dest_length;
2073 this_->attr_next=attr_destination_time;
2075 case attr_destination_time:
2076 attr->u.num=itm->dest_time;
2077 this_->attr_next=attr_street_name;
2079 case attr_street_name:
2080 attr->u.str=itm->way.name1;
2081 this_->attr_next=attr_street_name_systematic;
2085 case attr_street_name_systematic:
2086 attr->u.str=itm->way.name2;
2087 this_->attr_next=attr_debug;
2092 switch(this_->debug_idx) {
2095 this_->str=attr->u.str=g_strdup_printf("angle:%d (- %d)", itm->way.angle2, itm->angle_end);
2099 this_->str=attr->u.str=g_strdup_printf("item type:%s", item_to_name(itm->way.item.type));
2104 this_->str=attr->u.str=g_strdup_printf("delta:%d", cmd->delta);
2110 this_->str=attr->u.str=g_strdup_printf("prev street_name:%s", prev->way.name1);
2116 this_->str=attr->u.str=g_strdup_printf("prev street_name_systematic:%s", prev->way.name2);
2122 this_->str=attr->u.str=g_strdup_printf("prev angle:(%d -) %d", prev->way.angle2, prev->angle_end);
2127 this_->ways=itm->way.next;
2129 this_->str=attr->u.str=g_strdup_printf("prev item type:%s", item_to_name(prev->way.item.type));
2133 if (this_->ways && prev) {
2134 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);
2135 this_->ways=this_->ways->next;
2144 maneuver_required2(this_->nav, prev, itm, &delta, &reason);
2145 this_->str=attr->u.str=g_strdup_printf("reason:%s",reason);
2150 this_->attr_next=attr_none;
2154 while (this_->attr_next != attr_none) {
2155 if (navigation_map_item_attr_get(priv_data, this_->attr_next, attr))
2160 attr->type=attr_none;
2165 static struct item_methods navigation_map_item_methods = {
2167 navigation_map_item_coord_get,
2169 navigation_map_item_attr_get,
2174 navigation_map_destroy(struct map_priv *priv)
2180 navigation_map_rect_init(struct map_rect_priv *priv)
2182 priv->cmd_next=priv->nav->cmd_first;
2183 priv->cmd_itm_next=priv->itm_next=priv->nav->first;
2186 static struct map_rect_priv *
2187 navigation_map_rect_new(struct map_priv *priv, struct map_selection *sel)
2189 struct navigation *nav=priv->navigation;
2190 struct map_rect_priv *ret=g_new0(struct map_rect_priv, 1);
2192 navigation_map_rect_init(ret);
2193 ret->item.meth=&navigation_map_item_methods;
2194 ret->item.priv_data=ret;
2202 navigation_map_rect_destroy(struct map_rect_priv *priv)
2207 static struct item *
2208 navigation_map_get_item(struct map_rect_priv *priv)
2210 struct item *ret=&priv->item;
2212 if (!priv->itm_next)
2214 priv->itm=priv->itm_next;
2215 priv->cmd=priv->cmd_next;
2216 priv->cmd_itm=priv->cmd_itm_next;
2219 if (!priv->show_all && priv->itm->prev != NULL)
2220 priv->itm=priv->cmd->itm;
2221 priv->itm_next=priv->itm->next;
2222 if (priv->itm->prev)
2223 ret->type=type_nav_none;
2225 ret->type=type_nav_position;
2226 if (priv->cmd->itm == priv->itm) {
2227 priv->cmd_itm_next=priv->cmd->itm;
2228 priv->cmd_next=priv->cmd->next;
2229 if (priv->cmd_itm_next && !priv->cmd_itm_next->next)
2230 ret->type=type_nav_destination;
2232 if (priv->itm && priv->itm->prev && !(priv->itm->way.flags & AF_ROUNDABOUT) && (priv->itm->prev->way.flags & AF_ROUNDABOUT)) {
2233 enum item_type r=type_none,l=type_none;
2234 switch (((180+22)-priv->cmd->roundabout_delta)/45) {
2237 r=type_nav_roundabout_r1;
2238 l=type_nav_roundabout_l7;
2241 r=type_nav_roundabout_r2;
2242 l=type_nav_roundabout_l6;
2245 r=type_nav_roundabout_r3;
2246 l=type_nav_roundabout_l5;
2249 r=type_nav_roundabout_r4;
2250 l=type_nav_roundabout_l4;
2253 r=type_nav_roundabout_r5;
2254 l=type_nav_roundabout_l3;
2257 r=type_nav_roundabout_r6;
2258 l=type_nav_roundabout_l2;
2261 r=type_nav_roundabout_r7;
2262 l=type_nav_roundabout_l1;
2265 r=type_nav_roundabout_r8;
2266 l=type_nav_roundabout_l8;
2269 dbg(1,"delta %d\n",priv->cmd->delta);
2270 if (priv->cmd->delta < 0)
2275 delta=priv->cmd->delta;
2279 ret->type=type_nav_left_1;
2280 else if (delta < 105)
2281 ret->type=type_nav_left_2;
2282 else if (delta < 165)
2283 ret->type=type_nav_left_3;
2285 ret->type=type_none;
2288 ret->type=type_nav_right_1;
2289 else if (delta < 105)
2290 ret->type=type_nav_right_2;
2291 else if (delta < 165)
2292 ret->type=type_nav_right_3;
2294 ret->type=type_none;
2301 priv->attr_next=attr_navigation_short;
2303 ret->id_lo=priv->itm->dest_count;
2304 dbg(1,"type=%d\n", ret->type);
2308 static struct item *
2309 navigation_map_get_item_byid(struct map_rect_priv *priv, int id_hi, int id_lo)
2312 navigation_map_rect_init(priv);
2313 while ((ret=navigation_map_get_item(priv))) {
2314 if (ret->id_hi == id_hi && ret->id_lo == id_lo)
2320 static struct map_methods navigation_map_meth = {
2323 navigation_map_destroy,
2324 navigation_map_rect_new,
2325 navigation_map_rect_destroy,
2326 navigation_map_get_item,
2327 navigation_map_get_item_byid,
2333 static struct map_priv *
2334 navigation_map_new(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl)
2336 struct map_priv *ret;
2337 struct attr *navigation_attr;
2339 navigation_attr=attr_search(attrs, NULL, attr_navigation);
2340 if (! navigation_attr)
2342 ret=g_new0(struct map_priv, 1);
2343 *meth=navigation_map_meth;
2344 ret->navigation=navigation_attr->u.navigation;
2350 navigation_set_route(struct navigation *this_, struct route *route)
2352 struct attr callback;
2353 if (!this_->route_cb)
2354 this_->route_cb=callback_new_attr_1(callback_cast(navigation_update), attr_route_status, this_);
2355 callback.type=attr_callback;
2356 callback.u.callback=this_->route_cb;
2358 route_remove_attr(this_->route, &callback);
2361 struct attr route_status;
2362 route_add_attr(this_->route, &callback);
2363 if (route_get_attr(this_->route, attr_route_status, &route_status, NULL))
2364 navigation_update(this_, this_->route, &route_status);
2369 navigation_init(void)
2371 plugin_register_map_type("navigation", navigation_map_new);