#include <stdlib.h>
#include <string.h>
#include <math.h>
+#include <ctype.h>
#include <glib.h>
#include "debug.h"
#include "profile.h"
};
struct navigation {
+ struct route *route;
struct map *map;
struct item_hash *hash;
struct navigation_itm *first;
struct navigation_command *cmd_last;
struct callback_list *callback_speech;
struct callback_list *callback;
+ struct navit *navit;
int level_last;
struct item item_last;
int turn_around;
int turn_around_limit;
int distance_turn;
- int distance_last;
+ struct callback *route_cb;
int announce[route_item_last-route_item_first+1][3];
+ int tell_street_name;
};
struct navigation_command {
struct navigation_itm *itm;
struct navigation_command *next;
+ struct navigation_command *prev;
int delta;
+ int roundabout_delta;
+ int length;
};
+static void navigation_flush(struct navigation *this_);
+
/**
* @brief Calculates the delta between two angles
* @param angle1 The first angle
return delta;
}
+static int
+angle_median(int angle1, int angle2)
+{
+ int delta=angle_delta(angle1, angle2);
+ int ret=angle1+delta/2;
+ if (ret < 0)
+ ret+=360;
+ if (ret > 360)
+ ret-=360;
+ return ret;
+}
+
+static int
+angle_opposite(int angle)
+{
+ return ((angle+180)%360);
+}
+
+int
+navigation_get_attr(struct navigation *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
+{
+ dbg(0,"enter %s\n", attr_to_name(type));
+ switch (type) {
+ case attr_map:
+ attr->u.map=this_->map;
+ break;
+ default:
+ return 0;
+ }
+ attr->type=type;
+ return 1;
+}
+
+
struct navigation *
-navigation_new(struct attr **attrs)
+navigation_new(struct attr *parent, struct attr **attrs)
{
int i,j;
+ struct attr * attr;
struct navigation *ret=g_new0(struct navigation, 1);
ret->hash=item_hash_new();
ret->callback=callback_list_new();
ret->callback_speech=callback_list_new();
ret->level_last=-2;
- ret->distance_last=-2;
ret->distance_turn=50;
ret->turn_around_limit=3;
+ ret->navit=parent->u.navit;
+ ret->tell_street_name=1;
for (j = 0 ; j <= route_item_last-route_item_first ; j++) {
for (i = 0 ; i < 3 ; i++) {
}
}
+ if ((attr=attr_search(attrs, NULL, attr_tell_street_name))) {
+ ret->tell_street_name = attr->u.num;
+ }
+
return ret;
}
int length;
int dest_time;
int dest_length;
- int told;
+ int told; /**< Indicates if this item's announcement has been told earlier and should not be told again*/
+ int streetname_told; /**< Indicates if this item's streetname has been told in speech navigation*/
int dest_count;
int flags;
struct navigation_itm *next;
{
switch (n) {
case 0:
- return _("zeroth"); // Not shure if this exists, neither if it will ever be needed
+ return _("zeroth"); // Not sure if this exists, neither if it will ever be needed
case 1:
return _("first");
case 2:
}
}
+static char
+*get_exit_count_str(int n)
+{
+ switch (n) {
+ case 0:
+ return _("zeroth exit"); // Not sure if this exists, neither if it will ever be needed
+ case 1:
+ return _("first exit");
+ case 2:
+ return _("second exit");
+ case 3:
+ return _("third exit");
+ case 4:
+ return _("fourth exit");
+ case 5:
+ return _("fifth exit");
+ case 6:
+ return _("sixth exit");
+ default:
+ return NULL;
+ }
+}
static int
round_distance(int dist)
{
int rem=(dist/100)%10;
if (rem) {
if (is_length)
- return g_strdup_printf(_("%d.%d kilometer"), dist/1000, rem);
+ return g_strdup_printf(_("%d.%d kilometers"), dist/1000, rem);
else
return g_strdup_printf(_("in %d.%d kilometers"), dist/1000, rem);
}
}
/**
+ * @brief Returns the time (in seconds) one will drive between two navigation items
+ *
+ * This function returns the time needed to drive between two items, including both of them,
+ * in seconds.
+ *
+ * @param from The first item
+ * @param to The last item
+ * @return The travel time in seconds, or -1 on error
+ */
+static int
+navigation_time(struct navigation_itm *from, struct navigation_itm *to)
+{
+ struct navigation_itm *cur;
+ int time;
+
+ time = 0;
+ cur = from;
+ while (cur) {
+ time += cur->time;
+
+ if (cur == to) {
+ break;
+ }
+ cur = cur->next;
+ }
+
+ if (!cur) {
+ return -1;
+ }
+
+ return time;
+}
+
+/**
* @brief Clears the ways one can drive from itm
*
* @param itm The item that should have its ways cleared
if (this_->cmd_first && this_->cmd_first->itm == itm->next) {
cmd=this_->cmd_first;
this_->cmd_first=cmd->next;
+ if (cmd->next) {
+ cmd->next->prev = NULL;
+ }
g_free(cmd);
}
map_convert_free(itm->name1);
navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
{
struct attr length, time;
+
if (! item_attr_get(ritem, attr_length, &length)) {
dbg(0,"no length\n");
return;
struct coord c[5];
if (ritem) {
- ret->told=0;
+ ret->streetname_told=0;
if (! item_attr_get(ritem, attr_street_item, &street_item)) {
- dbg(0,"no street item\n");
+ dbg(1, "no street item\n");
return NULL;
}
if (item_attr_get(ritem, attr_direction, &direction))
ret->item=*sitem;
item_hash_insert(this_->hash, sitem, ret);
mr=map_rect_new(sitem->map, NULL);
- sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo);
+ if (! (sitem=map_rect_get_item_byid(mr, sitem->id_hi, sitem->id_lo)))
+ return NULL;
if (item_attr_get(sitem, attr_street_name, &attr))
ret->name1=map_convert_string(sitem->map,attr.u.str);
if (item_attr_get(sitem, attr_street_name_systematic, &attr))
return 0;
}
+#if 0
/**
* @brief Checks if two navigation items are on the same street
*
}
return 1;
}
+#endif
static int maneuver_category(enum item_type type)
{
static int
maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta, char **reason)
{
- int ret=0,d,dw,dlim,straight_limit=20,ext_straight_limit=45;
+ int ret=0,d,dw,dlim;
char *r=NULL;
struct navigation_way *w;
int cat,ncat,wcat,maxcat,left=-180,right=180,is_unambigous=0,is_same_street;
if (!new->ways) {
/* No announcement necessary */
r="no: Only one possibility";
- } else if (!new->ways->next && new->ways->item.type == type_ramp) {
+ } else if (!new->ways->next && new->ways->item.type == type_ramp && !is_way_allowed(new->ways)) {
/* If the other way is only a ramp and it is one-way in the wrong direction, no announcement necessary */
- /* TODO: check for one way in wrong direction */
r="no: Only ramp";
}
if (! r) {
dlim=80;
else
dlim=120;
+ /* if the street is really straight, the others might be closer to straight */
+ if (abs(d) < 20)
+ dlim/=2;
if ((maxcat == ncat && maxcat == cat) || (ncat == 0 && cat == 0))
dlim=abs(d)*620/256;
else if (maxcat < ncat && maxcat < cat)
dbg(1,"enter this_=%p itm=%p delta=%d\n", this_, itm, delta);
ret->delta=delta;
ret->itm=itm;
- if (this_->cmd_last)
+ if (itm && itm->prev && itm->ways && itm->prev->ways && !(itm->flags & AF_ROUNDABOUT) && (itm->prev->flags & AF_ROUNDABOUT)) {
+ int len=0;
+ int angle=0;
+ int entry_angle;
+ struct navigation_itm *itm2=itm->prev;
+ int exit_angle=angle_median(itm->prev->angle_end, itm->ways->angle2);
+ dbg(1,"exit %d median from %d,%d\n", exit_angle,itm->prev->angle_end, itm->ways->angle2);
+ while (itm2 && (itm2->flags & AF_ROUNDABOUT)) {
+ len+=itm2->length;
+ angle=itm2->angle_end;
+ itm2=itm2->prev;
+ }
+ if (itm2 && itm2->next && itm2->next->ways) {
+ itm2=itm2->next;
+ entry_angle=angle_median(angle_opposite(itm2->angle_start), itm2->ways->angle2);
+ dbg(1,"entry %d median from %d(%d),%d\n", entry_angle,angle_opposite(itm2->angle_start), itm2->angle_start, itm2->ways->angle2);
+ } else {
+ entry_angle=angle_opposite(angle);
+ }
+ dbg(0,"entry %d exit %d\n", entry_angle, exit_angle);
+ ret->roundabout_delta=angle_delta(entry_angle, exit_angle);
+ ret->length=len;
+
+ }
+ if (this_->cmd_last) {
this_->cmd_last->next=ret;
+ ret->prev = this_->cmd_last;
+ }
this_->cmd_last=ret;
if (!this_->cmd_first)
char *ret=g_malloc(len+strlen(replace)+1);
strncpy(ret, name, len);
strcpy(ret+len, replace);
+ if (isupper(name[len])) {
+ ret[len]=toupper(ret[len]);
+ }
return ret;
}
/* TRANSLATORS: gives the name of the next road to turn into (into the E17) */
ret=g_strdup_printf(_("%sinto the %s"),prefix,itm->name2);
name1=ret;
- while (*name1) {
+ while (name1 && *name1) {
switch (*name1) {
case '|':
*name1='\0';
}
static char *
-show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
+show_maneuver(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type, int connect)
{
/* TRANSLATORS: right, as in 'Turn right' */
char *dir=_("right"),*strength="";
int distance=itm->dest_length-cmd->itm->dest_length;
- char *d,*ret;
+ char *d,*ret=NULL;
int delta=cmd->delta;
int level;
int strength_needed;
struct navigation_itm *cur;
struct navigation_way *w;
+ if (connect) {
+ level = -2; // level = -2 means "connect to another maneuver via 'then ...'"
+ } else {
+ level=1;
+ }
+
w = itm->next->ways;
strength_needed = 0;
- if ((itm->next->angle_start - itm->angle_end) < 0) {
+ if (angle_delta(itm->next->angle_start,itm->angle_end) < 0) {
while (w) {
- if (w->angle2-itm->next->angle_start < 0) {
+ if (angle_delta(w->angle2,itm->angle_end) < 0) {
strength_needed = 1;
break;
}
}
} else {
while (w) {
- if (w->angle2-itm->next->angle_start > 0) {
+ if (angle_delta(w->angle2,itm->angle_end) > 0) {
strength_needed = 1;
break;
}
}
}
- level=1;
if (delta < 0) {
/* TRANSLATORS: left, as in 'Turn left' */
dir=_("left");
} else if (delta < 165) {
/* TRANSLATORS: Don't forget the ending space */
strength=_("strongly ");
+ } else if (delta < 180) {
+ /* TRANSLATORS: Don't forget the ending space */
+ strength=_("really strongly ");
} else {
dbg(1,"delta=%d\n", delta);
/* TRANSLATORS: Don't forget the ending space */
if (type == attr_navigation_speech) {
if (nav->turn_around && nav->turn_around == nav->turn_around_limit)
return g_strdup(_("When possible, please turn around"));
- level=navigation_get_announce_level(nav, itm->item.type, distance);
+ if (!connect) {
+ level=navigation_get_announce_level(nav, itm->item.type, distance-cmd->length);
+ }
dbg(1,"distance=%d level=%d type=0x%x\n", distance, level, itm->item.type);
}
return g_strdup(_("Enter the roundabout soon"));
case 1:
d = get_distance(distance, type, 1);
+ /* TRANSLATORS: %s is the distance to the roundabout */
ret = g_strdup_printf(_("In %s, enter the roundabout"), d);
g_free(d);
return ret;
+ case -2:
case 0:
cur = cmd->itm->prev;
count_roundabout = 0;
while (cur && (cur->flags & AF_ROUNDABOUT)) {
- if (cur->next->ways) { // If the next segment has no exit, don't count it
+ if (cur->next->ways && is_way_allowed(cur->next->ways)) { // If the next segment has no exit or the exit isn't allowed, don't count it
count_roundabout++;
}
cur = cur->prev;
}
- ret = g_strdup_printf(_("Leave the roundabout at the %s exit"), get_count_str(count_roundabout));
+ switch (level) {
+ case 0:
+ ret = g_strdup_printf(_("Leave the roundabout at the %s"), get_exit_count_str(count_roundabout));
+ break;
+ case -2:
+ ret = g_strdup_printf(_("then leave the roundabout at the %s"), get_exit_count_str(count_roundabout));
+ break;
+ }
return ret;
}
}
d=g_strdup(_("now"));
}
break;
+ case -2:
+ skip_roads = count_possible_turns(cmd->prev->itm,cmd->itm,cmd->delta);
+ if (skip_roads > 0) {
+ /* TRANSLATORS: First argument is the how manieth street to take, second the direction */
+ if (get_count_str(skip_roads+1)) {
+ ret = g_strdup_printf(_("then take the %1$s road to the %2$s"), get_count_str(skip_roads+1), dir);
+ return ret;
+ } else {
+ d = g_strdup_printf(_("after %i roads"), skip_roads);
+ }
+
+ } else {
+ d = g_strdup("");
+ }
+ break;
default:
d=g_strdup(_("error"));
}
if (cmd->itm->next) {
int tellstreetname = 0;
- char *destination = NULL;
+ char *destination = NULL;
if(type == attr_navigation_speech) { // In voice mode
// In Voice Mode only tell the street name in level 1 or in level 0 if level 1
// was skipped
if (level == 1) { // we are close to the intersection
- cmd->itm->told = 1; // remeber to be checked when we turn
+ cmd->itm->streetname_told = 1; // remeber to be checked when we turn
tellstreetname = 1; // Ok so we tell the name of the street
}
if (level == 0) {
- if(cmd->itm->told == 0) // we are right at the intersection
+ if(cmd->itm->streetname_told == 0) // we are right at the intersection
tellstreetname = 1;
else
- cmd->itm->told = 0; // reset just in case we come to the same street again
+ cmd->itm->streetname_told = 0; // reset just in case we come to the same street again
}
}
else
tellstreetname = 1;
- if(tellstreetname)
+ if(nav->tell_street_name && tellstreetname)
destination=navigation_item_destination(cmd->itm, itm, " ");
- /* 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' */
- ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
+
+ if (level != -2) {
+ /* 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' */
+ ret=g_strdup_printf(_("Turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
+ } else {
+ /* TRANSLATORS: First argument is strength, second direction, third how many roads to skip, fourth destination */
+ ret=g_strdup_printf(_("then turn %1$s%2$s %3$s%4$s"), strength, dir, d, destination ? destination:"");
+ }
g_free(destination);
- } else
- ret=g_strdup_printf(_("You have reached your destination %s"), d);
+ } else {
+ if (!connect) {
+ ret=g_strdup_printf(_("You have reached your destination %s"), d);
+ } else {
+ ret=g_strdup_printf(_("then you have reached your destination."));
+ }
+ }
g_free(d);
return ret;
}
+/**
+ * @brief Creates announcements for maneuvers, plus maneuvers immediately following the next maneuver
+ *
+ * This function does create an announcement for the current maneuver and for maneuvers
+ * immediately following that maneuver, if these are too close and we're in speech navigation.
+ *
+ * @return An announcement that should be made
+ */
+static char *
+show_next_maneuvers(struct navigation *nav, struct navigation_itm *itm, struct navigation_command *cmd, enum attr_type type)
+{
+ struct navigation_command *cur,*prev;
+ int distance=itm->dest_length-cmd->itm->dest_length;
+ int level, dist, i, time;
+ int speech_time,time2nav;
+ char *ret,*old,*buf,*next;
+
+ if (type != attr_navigation_speech) {
+ return show_maneuver(nav, itm, cmd, type, 0); // We accumulate maneuvers only in speech navigation
+ }
+
+ level=navigation_get_announce_level(nav, itm->item.type, distance-cmd->length);
+
+ if (level > 1) {
+ return show_maneuver(nav, itm, cmd, type, 0); // We accumulate maneuvers only if they are close
+ }
+
+ if (cmd->itm->told) {
+ return g_strdup("");
+ }
+
+ ret = show_maneuver(nav, itm, cmd, type, 0);
+ time2nav = navigation_time(itm,cmd->itm->prev);
+ old = NULL;
+
+ cur = cmd->next;
+ prev = cmd;
+ i = 0;
+ while (cur && cur->itm) {
+ // We don't merge more than 3 announcements...
+ if (i > 1) { // if you change this, please also change the value below, that is used to terminate the loop
+ break;
+ }
+
+ next = show_maneuver(nav,prev->itm, cur, type, 0);
+ speech_time = navit_speech_estimate(nav->navit,next);
+ g_free(next);
+
+ if (speech_time == -1) { // user didn't set cps
+ speech_time = 30; // assume 3 seconds
+ }
+
+ dist = prev->itm->dest_length - cur->itm->dest_length;
+ time = navigation_time(prev->itm,cur->itm->prev);
+
+ if (time >= (speech_time + 30)) { // 3 seconds for understanding what has been said
+ break;
+ }
+
+ old = ret;
+ buf = show_maneuver(nav, prev->itm, cur, type, 1);
+ ret = g_strdup_printf("%s, %s", old, buf);
+ g_free(buf);
+ if (navit_speech_estimate(nav->navit,ret) > time2nav) {
+ g_free(ret);
+ ret = old;
+ i = 2; // This will terminate the loop
+ } else {
+ g_free(old);
+ }
+
+ // If the two maneuvers are *really* close, we shouldn't tell the second one again, because TTS won't be fast enough
+ if (time <= speech_time) {
+ cur->itm->told = 1;
+ }
+
+ prev = cur;
+ cur = cur->next;
+ i++;
+ }
+
+ return ret;
+}
+
static void
navigation_call_callbacks(struct navigation *this_, int force_speech)
{
}
} else if (!this_->turn_around_limit || this_->turn_around == -this_->turn_around_limit+1) {
this_->distance_turn=50;
+ distance-=this_->cmd_first->length;
level=navigation_get_announce_level(this_, this_->first->item.type, distance);
if (this_->cmd_first->itm->prev) {
level2=navigation_get_announce_level(this_, this_->cmd_first->itm->prev->item.type, distance);
}
}
-void
-navigation_update(struct navigation *this_, struct route *route)
+static void
+navigation_update(struct navigation *this_, struct route *route, struct attr *attr)
{
struct map *map;
struct map_rect *mr;
struct item *sitem; /* Holds the corresponding item from the actual map */
struct attr street_item,street_direction;
struct navigation_itm *itm;
- int incr=0,first=1;
+ int mode=0, incr=0, first=1;
+ if (attr->type != attr_route_status)
+ return;
- if (! route)
+ dbg(1,"enter %d\n", mode);
+ if (attr->u.num == route_status_no_destination || attr->u.num == route_status_not_found || attr->u.num == route_status_path_done_new)
+ navigation_flush(this_);
+ if (attr->u.num != route_status_path_done_new && attr->u.num != route_status_path_done_incremental)
+ return;
+
+ if (! this_->route)
return;
- map=route_get_map(route);
+ map=route_get_map(this_->route);
if (! map)
return;
mr=map_rect_new(map, NULL);
return;
dbg(1,"enter\n");
while ((ritem=map_rect_get_item(mr))) {
+ if (ritem->type == type_route_start && this_->turn_around > -this_->turn_around_limit+1)
+ this_->turn_around--;
+ if (ritem->type == type_route_start_reverse && this_->turn_around < this_->turn_around_limit)
+ this_->turn_around++;
+ if (ritem->type != type_street_route)
+ continue;
if (first && item_attr_get(ritem, attr_street_item, &street_item)) {
first=0;
if (!item_attr_get(ritem, attr_direction, &street_direction))
}
navigation_itm_new(this_, ritem);
}
+ dbg(2,"turn_around=%d\n", this_->turn_around);
if (first)
navigation_destroy_itms_cmds(this_, NULL);
else {
if (! ritem) {
navigation_itm_new(this_, NULL);
- make_maneuvers(this_,route);
+ make_maneuvers(this_,this_->route);
}
calculate_dest_distance(this_, incr);
- dbg(2,"destination distance old=%d new=%d\n", this_->distance_last, this_->first->dest_length);
- if (this_->first->dest_length > this_->distance_last && this_->distance_last >= 0)
- this_->turn_around++;
- else
- this_->turn_around--;
- if (this_->turn_around > this_->turn_around_limit)
- this_->turn_around=this_->turn_around_limit;
- else if (this_->turn_around < -this_->turn_around_limit+1)
- this_->turn_around=-this_->turn_around_limit+1;
- dbg(2,"turn_around=%d\n", this_->turn_around);
- this_->distance_last=this_->first->dest_length;
profile(0,"end");
navigation_call_callbacks(this_, FALSE);
}
map_rect_destroy(mr);
}
-void
+static void
navigation_flush(struct navigation *this_)
{
navigation_destroy_itms_cmds(this_, NULL);
case attr_navigation_short:
this_->attr_next=attr_navigation_long;
if (cmd) {
- this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
+ this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
return 1;
}
return 0;
case attr_navigation_long:
this_->attr_next=attr_navigation_long_exact;
if (cmd) {
- this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
+ this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
return 1;
}
return 0;
case attr_navigation_long_exact:
this_->attr_next=attr_navigation_speech;
if (cmd) {
- this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, cmd, attr_type);
+ this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, cmd, attr_type);
return 1;
}
return 0;
case attr_navigation_speech:
this_->attr_next=attr_length;
if (cmd) {
- this_->str=attr->u.str=show_maneuver(this_->nav, this_->cmd_itm, this_->cmd, attr_type);
+ this_->str=attr->u.str=show_next_maneuvers(this_->nav, this_->cmd_itm, this_->cmd, attr_type);
return 1;
}
return 0;
if (priv->cmd_itm_next && !priv->cmd_itm_next->next)
ret->type=type_nav_destination;
else {
- delta=priv->cmd->delta;
- if (delta < 0) {
- delta=-delta;
- if (delta < 45)
- ret->type=type_nav_left_1;
- else if (delta < 105)
- ret->type=type_nav_left_2;
- else if (delta < 165)
- ret->type=type_nav_left_3;
- else
- ret->type=type_none;
+ if (priv->itm && priv->itm->prev && !(priv->itm->flags & AF_ROUNDABOUT) && (priv->itm->prev->flags & AF_ROUNDABOUT)) {
+
+ switch (((180+22)-priv->cmd->roundabout_delta)/45) {
+ case 0:
+ case 1:
+ ret->type=type_nav_roundabout_r1;
+ break;
+ case 2:
+ ret->type=type_nav_roundabout_r2;
+ break;
+ case 3:
+ ret->type=type_nav_roundabout_r3;
+ break;
+ case 4:
+ ret->type=type_nav_roundabout_r4;
+ break;
+ case 5:
+ ret->type=type_nav_roundabout_r5;
+ break;
+ case 6:
+ ret->type=type_nav_roundabout_r6;
+ break;
+ case 7:
+ ret->type=type_nav_roundabout_r7;
+ break;
+ case 8:
+ ret->type=type_nav_roundabout_r8;
+ break;
+ }
} else {
- if (delta < 45)
- ret->type=type_nav_right_1;
- else if (delta < 105)
- ret->type=type_nav_right_2;
- else if (delta < 165)
- ret->type=type_nav_right_3;
- else
- ret->type=type_none;
+ delta=priv->cmd->delta;
+ if (delta < 0) {
+ delta=-delta;
+ if (delta < 45)
+ ret->type=type_nav_left_1;
+ else if (delta < 105)
+ ret->type=type_nav_left_2;
+ else if (delta < 165)
+ ret->type=type_nav_left_3;
+ else
+ ret->type=type_none;
+ } else {
+ if (delta < 45)
+ ret->type=type_nav_right_1;
+ else if (delta < 105)
+ ret->type=type_nav_right_2;
+ else if (delta < 165)
+ ret->type=type_nav_right_3;
+ else
+ ret->type=type_none;
+ }
}
}
}
return ret;
}
+void
+navigation_set_route(struct navigation *this_, struct route *route)
+{
+ struct attr callback;
+ this_->route=route;
+ this_->route_cb=callback_new_attr_1(callback_cast(navigation_update), attr_route_status, this_);
+ callback.type=attr_callback;
+ callback.u.callback=this_->route_cb;
+ route_add_attr(route, &callback);
+}
void
navigation_init(void)