From f8879bf8fc86a9b4872bf2544ba7ccfbabd465e8 Mon Sep 17 00:00:00 2001 From: tinloaf Date: Tue, 14 Oct 2008 19:48:35 +0000 Subject: [PATCH] =?utf8?q?Making=20navit=20guide=20the=20user=20if=20a=20r?= =?utf8?q?oad=20is=20left,=20even=20if=20the=20angle=20is=20below=2020?= =?utf8?q?=C2=B0.?= MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@1463 ffa7fe5e-494d-0410-b361-a75ebd5db220 --- navit/navit/attr_def.h | 1 + navit/navit/navigation.c | 81 ++++++++++++++++++++--- navit/navit/navit.xml | 18 ++--- navit/navit/route.c | 169 +++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 242 insertions(+), 27 deletions(-) diff --git a/navit/navit/attr_def.h b/navit/navit/attr_def.h index 474d59e..6129f3e 100644 --- a/navit/navit/attr_def.h +++ b/navit/navit/attr_def.h @@ -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) diff --git a/navit/navit/navigation.c b/navit/navit/navigation.c index 093e733..1d0e60c 100644 --- a/navit/navit/navigation.c +++ b/navit/navit/navigation.c @@ -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; diff --git a/navit/navit/navit.xml b/navit/navit/navit.xml index 7fd81bf..1ffdb4b 100644 --- a/navit/navit/navit.xml +++ b/navit/navit/navit.xml @@ -10,7 +10,7 @@ http://wiki.navit-project.org/index.php/Configuring_NavIt - + - + @@ -66,7 +66,7 @@ http://wiki.navit-project.org/index.php/Configuring_NavIt --> - + @@ -102,17 +102,13 @@ http://wiki.navit-project.org/index.php/Configuring_NavIt - - - - - - - + + + - + diff --git a/navit/navit/route.c b/navit/navit/route.c index dc8982d..ff2ada9 100644 --- a/navit/navit/route.c +++ b/navit/navit/route.c @@ -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) -- 2.7.4