Making navit guide the user if a road is left, even if the angle is below
authortinloaf <tinloaf@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Tue, 14 Oct 2008 19:48:35 +0000 (19:48 +0000)
committertinloaf <tinloaf@ffa7fe5e-494d-0410-b361-a75ebd5db220>
Tue, 14 Oct 2008 19:48:35 +0000 (19:48 +0000)
20°.

git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk/navit@1463 ffa7fe5e-494d-0410-b361-a75ebd5db220

navit/attr_def.h
navit/navigation.c
navit/navit.xml
navit/route.c

index 474d59e..6129f3e 100644 (file)
@@ -89,6 +89,7 @@ ATTR(button)
 ATTR(ondemand)
 ATTR(menu_on_map_click)
 ATTR(direction)
+ATTR(route_follow_straight)
 ATTR(gui_speech)
 ATTR2(0x0002ffff,type_int_end)
 ATTR2(0x00030000,type_string_begin)
index 093e733..1d0e60c 100644 (file)
@@ -132,6 +132,7 @@ struct navigation_itm {
        char *name2;
        struct item item;
        int direction;
+       int straight;
        int angle_start;
        int angle_end;
        struct coord c;
@@ -249,7 +250,7 @@ navigation_destroy_itms_cmds(struct navigation *this_, struct navigation_itm *en
 static void
 navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
 {
-       struct attr length, time;
+       struct attr length, time, straight;
        if (! item_attr_get(ritem, attr_length, &length)) {
                dbg(0,"no length\n");
                return;
@@ -258,6 +259,13 @@ navigation_itm_update(struct navigation_itm *itm, struct item *ritem)
                dbg(0,"no time\n");
                return;
        }
+
+       if (item_attr_get(ritem, attr_route_follow_straight, &straight)) {
+               itm->straight = straight.u.num;
+       } else {
+               itm->straight = 0;
+       }
+
        dbg(1,"length=%d time=%d\n", length.u.num, time.u.num);
        itm->length=length.u.num;
        itm->time=time.u.num;
@@ -267,7 +275,7 @@ static struct navigation_itm *
 navigation_itm_new(struct navigation *this_, struct item *ritem)
 {
        struct navigation_itm *ret=g_new0(struct navigation_itm, 1);
-       int l,i=0;
+       int i=0;
        struct item *sitem;
        struct attr street_item,direction;
        struct map_rect *mr;
@@ -294,10 +302,10 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
                if (item_attr_get(sitem, attr_street_name_systematic, &attr))
                        ret->name2=map_convert_string(sitem->map,attr.u.str);
                navigation_itm_update(ret, ritem);
-               l=-1;
+
                while (item_coord_get(ritem, &c[i], 1)) {
                        dbg(1, "coord %d 0x%x 0x%x\n", i, c[i].x ,c[i].y);
-                       l=i;
+
                        if (i < 4) 
                                i++;
                        else {
@@ -305,11 +313,12 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
                                c[3]=c[4];
                        }
                }
-               dbg(1,"count=%d\n", l);
-               if (l == 4)
-                       l=3;
+               dbg(1,"count=%d\n", i);
+               i--;
+
                ret->angle_start=road_angle(&c[0], &c[1], 0);
-               ret->angle_end=road_angle(&c[l-1], &c[l], 0);
+               ret->angle_end=road_angle(&c[i-1], &c[i], 0);
+
                ret->c=c[0];
                dbg(1,"i=%d start %d end %d '%s' '%s'\n", i, ret->angle_start, ret->angle_end, ret->name1, ret->name2);
                map_rect_destroy(mr);
@@ -325,6 +334,17 @@ navigation_itm_new(struct navigation *this_, struct item *ritem)
        return ret;
 }
 
+/**
+ * @brief Calculates distance and time to the destination
+ *
+ * This function calculates the distance and the time to the destination of a
+ * navigation. If incr is set, this is only calculated for the first navigation
+ * item, which is a lot faster than re-calculation the whole destination, but works
+ * only if the rest of the navigation already has been calculated.
+ *
+ * @param this_ The navigation whose destination / time should be calculated
+ * @param incr Set this to true to only calculate the first item. See description.
+ */
 static void
 calculate_dest_distance(struct navigation *this_, int incr)
 {
@@ -357,6 +377,17 @@ calculate_dest_distance(struct navigation *this_, int incr)
        dbg(1,"len %d time %d\n", len, time);
 }
 
+/**
+ * @brief Checks if two navigation items are on the same street
+ *
+ * This function checks if two navigation items are on the same street. It returns
+ * true if either their name or their "systematic name" (e.g. "A6" or "B256") are the
+ * same.
+ *
+ * @param old The first item to be checked
+ * @param new The second item to be checked
+ * @return True if both old and new are on the same street
+ */
 static int
 is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
 {
@@ -372,6 +403,18 @@ is_same_street2(struct navigation_itm *old, struct navigation_itm *new)
        return 0;
 }
 
+/**
+ * @brief Checks if two navigation items are on the same street
+ *
+ * This function checks if two navigation items are on the same street. It returns
+ * true if the first part of their "systematic name" is equal. If the "systematic name" is
+ * for example "A352/E3" (a german highway which at the same time is part of the international
+ * E-road network), it would only search for "A352" in the second item's systematic name.
+ *
+ * @param old The first item to be checked
+ * @param new The second item to be checked
+ * @return True if the "systematic name" of both items matches. See description.
+ */
 static int
 is_same_street_systematic(struct navigation_itm *old, struct navigation_itm *new)
 {
@@ -385,6 +428,17 @@ is_same_street_systematic(struct navigation_itm *old, struct navigation_itm *new
        return 1;
 }
 
+/**
+ * @brief Checks if navit has to create a maneuver to drive from old to new
+ *
+ * This function checks if it has to create a "maneuver" - i.e. guide the user - to drive 
+ * from "old" to "new".
+ *
+ * @param old The old navigation item, where we're coming from
+ * @param new The new navigation item, where we're going to
+ * @param delta The angle the user has to steer to navigate from old to new
+ * @return True if navit should guide the user, false otherwise
+ */
 static int
 maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *delta)
 {
@@ -416,7 +470,11 @@ maneuver_required2(struct navigation_itm *old, struct navigation_itm *new, int *
                return 1;
        }
        if (*delta < 20 && *delta >-20) {
-               dbg(1, "maneuver_required: delta(%d) < 20: no\n", *delta);
+               if (! new->straight) { /* We're not entering this item straight, so have a maneuver */
+                       return 1;
+               }
+
+               dbg(1, "maneuver_required: delta(%d) < 20: no\n", *delta);              
                return 0;
        }
        dbg(1, "maneuver_required: delta=%d: yes\n", *delta);
@@ -493,7 +551,7 @@ navigation_item_destination(struct navigation_itm *itm, struct navigation_itm *n
                if(next->item.type == type_ramp)
                        return NULL;
                if(itm->item.type == type_highway_city || itm->item.type == type_highway_land )
-                       return g_strdup_printf("%s%s",prefix,_("exit"));                                 
+                       return g_strdup_printf("%s%s",prefix,_("exit"));        /* %FIXME Can this even be reached? */                   
                else
                        return g_strdup_printf("%s%s",prefix,_("ramp"));
                
@@ -698,7 +756,8 @@ navigation_update(struct navigation *this_, struct route *route)
 {
        struct map *map;
        struct map_rect *mr;
-       struct item *ritem,*sitem;
+       struct item *ritem;                     /* Holds an item from the route map */
+       struct item *sitem;                     /* Holds the corresponding item from the actual map */
        struct attr street_item,street_direction;
        struct navigation_itm *itm;
        int incr=0;
index 7fd81bf..1ffdb4b 100644 (file)
@@ -10,7 +10,7 @@ http://wiki.navit-project.org/index.php/Configuring_NavIt
                <plugin path="$NAVIT_LIBDIR/*/${NAVIT_LIBPREFIX}lib*.so"/>
                <plugin path="$NAVIT_LIBDIR/*/${NAVIT_LIBPREFIX}libgraphics_null.so" active="no" />
        </plugins>
-       <debug name="navit:do_draw" level="0" />
+       <debug name="navit" level="0" />
 
        <!--
        Center coordinates format:
@@ -53,7 +53,7 @@ http://wiki.navit-project.org/index.php/Configuring_NavIt
                <!-- Use one of gtk_drawing_area, qt_qpainter or sdl. For cegui, use opengl -->
                <graphics type="gtk_drawing_area" />
 
-               <vehicle name="Local GPS" enabled="yes" active="1" source="gpsd://localhost" gpsd_query="w+xj" color="#0000ff">
+               <vehicle name="Local GPS" enabled="no" active="1" source="gpsd://localhost" gpsd_query="w+xj" color="#0000ff">
                        <!--Navit can write a tracklog in several formats (gpx, nmea or textfile):
                        <log type="gpx" data="track_%Y%m%d-%i.gpx" flush_size="1000" flush_time="30" />
                        -->
@@ -66,7 +66,7 @@ http://wiki.navit-project.org/index.php/Configuring_NavIt
                <vehicle name="Meins" enabled="yes" source="gpsd://localhost" color="#0000ff" follow="1" refresh="1"/>
                -->
 
-               <vehicle name="Demo" enabled="no" source="demo://" color="#0000aa"/>
+               <vehicle name="Demo" enabled="no" active="1" follow="1" source="demo://" color="#0000aa"/>
 
                <tracking>
                </tracking>
@@ -102,17 +102,13 @@ http://wiki.navit-project.org/index.php/Configuring_NavIt
                <!--<speech type="cmdline" data="flite -t '%s'" />-->
 
                <!-- If you have the reiseplaner maps installed, set enabled="yes" in the next line -->
-               <mapset enabled="no">
-                       <map type="mg" enabled="yes" data="/opt/reiseplaner/travel/DE.map" />
-                       <map type="mg" enabled="yes" data="/opt/reiseplaner/travel/DE.map/smp1.smp" />
-                       <map type="mg" enabled="yes" data="/opt/reiseplaner/travel/DE.map/smp2.smp" />
-                       <map type="mg" enabled="yes" data="/opt/reiseplaner/travel/DE.map/smp3.smp" />
-                       <map type="mg" enabled="yes" data="/opt/reiseplaner/travel/DE.map/smp4.smp" />
-                       <map type="mg" enabled="yes" data="/opt/reiseplaner/travel/DE.map/smp5.smp" />
+               <mapset enabled="yes">
+                       <map type="mg" enabled="yes" data="/opt/maps/DIRLAN_GER/DEM.map" />
+                       <map type="mg" enabled="yes" data="/opt/maps/DIRLAN_GER/DEM.map/smp3.smp" />
                </mapset>
 
                <!-- If you dont want to use the sample map, either set enabled="no" in the next line or remove the xml file from the maps directory -->
-               <mapset enabled="yes">
+               <mapset enabled="no">
                        <xi:include href="$NAVIT_SHAREDIR/maps/*.xml" />
                </mapset>
 
index dc8982d..ff2ada9 100644 (file)
@@ -129,7 +129,9 @@ struct route_path_segment {
                                                                                 *  coordinate of the segment is the first coordinate of the item", <=0 
                                                                                 *  means reverse. */
        unsigned ncoords;                                       /**< How many coordinates does this segment have? */
+       struct attr **attrs;                            /**< Attributes of this route path segment */
        struct coord c[0];                                      /**< Pointer to the ncoords coordinates of this segment */
+       /* WARNING: There will be coordinates following here, so do not create new fields after c! */
 };
 
 /**
@@ -904,20 +906,23 @@ route_path_add_item(struct route_path *this, struct item *item, int len, struct
  * @param len Length of the item to be added
  * @param offset Offset of rgs within the item it represents
  * @param dir Order in which to add the coordinates. See route_path_add_item()
+ * @param straight Indicates if this segment is being entered "straight". See route_check_straight().
  */
 static void
 route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpath,
-               struct route_graph_segment *rgs, int len, int offset, int dir)
+                                  struct route_graph_segment *rgs, int len, int offset, int dir, int straight)
 {
        struct route_path_segment *segment;
        int i,ccnt = 0;
        struct coord ca[2048];
+       struct attr straight_attr;
 
        if (oldpath) {
                ccnt = (int)item_hash_lookup(oldpath->path_hash, &rgs->item);
                if (ccnt) {
                        segment = route_extract_segment_from_path(oldpath,
                                                         &rgs->item, offset);
+                       
                        if (segment)
                                goto linkold;
                }
@@ -944,6 +949,12 @@ linkold:
        segment->length=len;
        segment->next=NULL;
        item_hash_insert(this->path_hash,  &rgs->item, (void *)ccnt);
+
+       straight_attr.type = attr_route_follow_straight;
+       straight_attr.u.num = straight;
+
+       segment->attrs = attr_generic_set_attr(segment->attrs, &straight_attr);
+
        route_path_add_segment(this, segment);
 }
 
@@ -1274,6 +1285,137 @@ route_path_new_trivial(struct route_graph *this, struct route_info *pos, struct
 }
 
 /**
+ * @brief Calculates of two coordinates' connection
+ *
+ * This function calculates the angle between coordinates, with north = 0
+ * and east = 90.
+ *
+ * %FIXME This is a duplicate of road_angle() in navigation.c - combine them?
+ *
+ * @param c1 Coordinate 1
+ * @param c2 Coordinate 2
+ * @param dir Set to true if c1 is the prior, and c2 the later coordinate.
+ * @return The angle of the coordinate's connection  
+ */
+static int
+route_road_angle(struct coord *c1, struct coord *c2, int dir)
+{
+       int ret=transform_get_angle_delta(c1, c2, dir);
+       dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
+       return ret;
+}
+
+/**
+ * @brief Checks if entering one segment from another is a "straight" road
+ *
+ * This checks if one can enter seg_to from seg_from by driving "straight" - i.e. 
+ * if seg_to is the segment you can drive to from seg_from by steering less than
+ * all to all other segments.
+ *
+ * This function returns true on failure, so we don't create maneuvers on every error.
+ *
+ * @param seg_from Segment we are driving from
+ * @param seg_to Segment we are driving to
+ * @param dir Set to true to indicate that seg_from is left throught its "start" instead through its "end"
+ * @return True if driving from seg_from to seg_to is "straight", false otherwise
+ */
+static int
+route_check_straight(struct route_graph_segment *seg_from, struct route_graph_segment *seg_to, int dir)
+{
+       struct route_graph_segment *curr;
+       struct route_graph_point *conn;
+       int from_angle, to_angle, curr_angle, angle_diff; 
+       int ccnt;
+       struct coord ca[2048];
+
+       if (!dir) {
+               if ((seg_from->end != seg_to->start) && (seg_from->end != seg_to->end)) {
+                       // Not connected!
+                       return 0;
+               }
+
+               ccnt = get_item_seg_coords(&seg_from->item, ca, 2047, &seg_from->start->c, &seg_from->end->c);
+               from_angle = route_road_angle(&ca[ccnt-2], &ca[ccnt-1],1);
+
+               conn = seg_from->end;
+       } else {
+               if ((seg_from->start != seg_to->start) && (seg_from->start != seg_to->end)) {
+                       // Not connected!
+                       return 0;
+               }
+
+               ccnt = get_item_seg_coords(&seg_from->item, ca, 2, &seg_from->start->c, &seg_from->end->c);
+               from_angle = route_road_angle(&ca[1], &ca[0],1);
+
+               conn = seg_from->start;
+       }
+
+       if (seg_to->end == conn) {
+               ccnt = get_item_seg_coords(&seg_to->item, ca, 2047, &seg_to->start->c, &seg_to->end->c);
+               to_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2],1);
+       } else {
+               ccnt = get_item_seg_coords(&seg_to->item, ca, 2, &seg_to->start->c, &seg_to->end->c);
+               to_angle = route_road_angle(&ca[0], &ca[1],1);
+       }                       
+       
+       
+       angle_diff = from_angle - to_angle;
+       if (angle_diff < 0) {
+               angle_diff *= -1;
+       }
+
+
+       curr = conn->start;
+       while (curr != NULL) {
+               if (curr==seg_to) {
+                       curr = curr->start_next;
+                       continue;
+               }
+               
+               ccnt = get_item_seg_coords(&curr->item, ca, 2, &curr->start->c, &curr->end->c);
+               curr_angle = route_road_angle(&ca[0], &ca[1], 1);
+
+               curr_angle = from_angle - curr_angle;
+
+               if (curr_angle < 0) {
+                       curr_angle *= -1;
+               }
+               
+
+               if (curr_angle <= angle_diff) {
+                       return 0;
+               }
+
+               curr = curr->start_next;
+       }
+
+       curr = conn->end;
+       while (curr != NULL) {
+               if (curr==seg_to) {
+                       curr = curr->end_next;
+                       continue;
+               }
+               
+               ccnt = get_item_seg_coords(&curr->item, ca, 2047, &curr->start->c, &curr->end->c);
+               curr_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2], 1);
+
+               curr_angle = from_angle - curr_angle;
+
+               if (curr_angle < 0) {
+                       curr_angle *= -1;
+               }
+
+               if (curr_angle <= angle_diff) {
+                       return 0;
+               }
+
+               curr = curr->end_next;
+       }
+
+       return 1;
+}
+
+/**
  * @brief Creates a new route path
  * 
  * This creates a new non-trivial route. It therefore needs the routing information created by route_graph_flood, so
@@ -1291,6 +1433,8 @@ route_path_new(struct route_graph *this, struct route_path *oldpath, struct rout
 {
        struct route_graph_point *start1=NULL,*start2=NULL,*start;
        struct route_graph_segment *s=NULL;
+       struct route_graph_segment *lastseg = NULL;
+       int is_straight;
        int len=0,segs=0;
        int seg_len;
 #if 0
@@ -1350,13 +1494,22 @@ route_path_new(struct route_graph *this, struct route_path *oldpath, struct rout
 #endif
                seg_len=s->len;
                len+=seg_len;
-               if (s->start == start) {
-                       route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, 1);
+               
+               if (lastseg) {
+                       is_straight = route_check_straight(lastseg,s,(s->end == start));
+               } else {
+                       is_straight = 0;
+               }
+
+               if (s->start == start) {                
+                       route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, 1, is_straight);
                        start=s->end;
                } else {
-                       route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, -1);
+                       route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, -1, is_straight);
                        start=s->start;
                }
+
+               lastseg = s;
        }
        sd=dst->street;
        dbg(1,"start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
@@ -1685,12 +1838,18 @@ rm_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
                        }
                        return 0;
                case attr_street_item:
-                       mr->attr_next=attr_direction;
+                       mr->attr_next=attr_route_follow_straight;
                        if (seg && seg->item.map)
                                attr->u.item=&seg->item;
                        else
                                return 0;
                        return 1;
+               case attr_route_follow_straight:
+                       mr->attr_next=attr_direction;
+                       if (seg) {
+                               return attr_generic_get_attr(seg->attrs,NULL,attr_route_follow_straight,attr,NULL);
+                       }
+                       return 0;
                case attr_direction:
                        mr->attr_next=attr_length;
                        if (seg)