diff options
author | mvglasow <michael@vonglasow.com> | 2015-11-08 15:50:07 +0100 |
---|---|---|
committer | mvglasow <michael@vonglasow.com> | 2015-11-08 15:50:07 +0100 |
commit | ffdc3eace672e5cfd59f0a4f0e78cd3e5e3b5d86 (patch) | |
tree | 0e758aae4d331984fc2456f5d474dd3074694fce | |
parent | 26788fb75cac1b51371e54cedebdbfa6887b597a (diff) | |
parent | 6d94fdea12a166d4d7832d0c3df0df474b276d24 (diff) | |
download | navit-ffdc3eace672e5cfd59f0a4f0e78cd3e5e3b5d86.tar.gz |
Merge pull request #29 from mvglasow/trac1324R6332
Merge:core:Merge fix for #1324
-rw-r--r-- | navit/attr_def.h | 1 | ||||
-rw-r--r-- | navit/navigation.c | 251 | ||||
-rw-r--r-- | navit/navit.c | 3 | ||||
-rw-r--r-- | navit/route.c | 63 | ||||
-rw-r--r-- | navit/route.h | 9 |
5 files changed, 264 insertions, 63 deletions
diff --git a/navit/attr_def.h b/navit/attr_def.h index 421696419..85c9fe908 100644 --- a/navit/attr_def.h +++ b/navit/attr_def.h @@ -193,6 +193,7 @@ ATTR(turn_around_count) ATTR(turn_around_penalty) ATTR(turn_around_penalty2) ATTR(autozoom_max) +ATTR(nav_status) ATTR2(0x00027500,type_rel_abs_begin) /* These attributes are int that can either hold relative * * or absolute values. A relative value is indicated by * diff --git a/navit/navigation.c b/navit/navigation.c index 8cb958703..a78ce1e1a 100644 --- a/navit/navigation.c +++ b/navit/navigation.c @@ -35,6 +35,7 @@ #include "projection.h" #include "map.h" #include "navit.h" +#include "event.h" #include "callback.h" #include "speech.h" #include "vehicleprofile.h" @@ -145,6 +146,23 @@ struct suffix { }; +enum nav_status { + status_no_route = -1, + status_no_destination = 0, + status_position_wait = 1, + status_calculating = 2, + status_recalculating = 3, + status_routing = 4, +}; + +enum nav_status_int { + status_none = 0, + status_busy = 1, + status_has_ritem = 2, + status_has_sitem = 4 +}; + + struct navigation { NAVIT_OBJECT struct route *route; @@ -171,6 +189,11 @@ struct navigation { int curr_delay; int turn_around_count; int flags; + struct map_rect *route_mr; /**< Map rect on the route map, used for maneuver generation */ + enum nav_status_int status_int; /**< Internal status information used during maneuver generation */ + struct callback *idle_cb; /**< Idle callback to process the route map */ + struct event_idle *idle_ev; /**< The pointer to the idle event */ + int nav_status; /**< Status of the navigation engine */ }; /** @brief Set of simplified distance values that are easy to be pronounced. @@ -694,6 +717,9 @@ navigation_get_attr(struct navigation *this_, enum attr_type type, struct attr * case attr_turn_around_count: attr->u.num=this_->turn_around_count; break; + case attr_nav_status: + attr->u.num=this_->nav_status; + break; default: return navit_object_get_attr((struct navit_object *)this_, type, attr, iter); } @@ -714,10 +740,15 @@ navigation_set_turnaround(struct navigation *this_, int val) int navigation_set_attr(struct navigation *this_, struct attr *attr) { + int attr_updated=0; switch (attr->type) { case attr_speech: this_->speech=attr->u.speech; break; + case attr_nav_status: + attr_updated = (this_->nav_status != attr->u.num); + this_->nav_status = attr->u.num; + break; default: break; } @@ -739,6 +770,7 @@ navigation_new(struct attr *parent, struct attr **attrs) ret->turn_around_limit=3; ret->navit=parent->u.navit; ret->tell_street_name=1; + ret->route_mr = NULL; for (j = 0 ; j <= route_item_last-route_item_first ; j++) { for (i = 0 ; i < 3 ; i++) { @@ -3612,57 +3644,110 @@ navigation_call_callbacks(struct navigation *this_, int force_speech) } } +/** + * @brief Cleans up and initiates maneuver creation. + * + * This function is called by {@link navigation_update_idle(struct navigation *)} + * after it has retrieved all objects from the route map. + * + * It will reset the navigation object's idle event/callback, deallocate some temporary objects and + * reset the {@code busy} flag. Arguments correspond to those of + * {@link navigation_update_idle(struct navigation *)}. + * + * @param this_ Points to the navigation object. After the function returns, its {@code map_rect} + * member will no longer be valid. + * @param cancel If true, only cleanup (deallocation of objects) will be done and no maneuvers will be generated. + * If false, maneuvers will be generated. + */ static void -navigation_update(struct navigation *this_, struct route *route, struct attr *attr) -{ - struct map *map; - struct map_rect *mr; +navigation_update_done(struct navigation *this_, int cancel) { + int incr = 0; + struct map_rect *mr = this_->route_mr; + struct attr nav_status; + + if (this_->idle_ev) + event_remove_idle(this_->idle_ev); + if (this_->idle_cb) + callback_destroy(this_->idle_cb); + this_->idle_ev=NULL; + this_->idle_cb=NULL; + + if (!cancel) { + nav_status.type = attr_nav_status; + nav_status.u.num = status_routing; + if (!(this_->status_int & status_has_sitem)) + navigation_destroy_itms_cmds(this_, NULL); + else { + if (!(this_->status_int & status_has_ritem)) { + navigation_itm_new(this_, NULL); + make_maneuvers(this_,this_->route); + } + calculate_dest_distance(this_, incr); + profile(0,"end"); + navigation_call_callbacks(this_, FALSE); + } + navigation_set_attr(this_, &nav_status); + } + /* + * In order to ensure that route_mr holds either NULL or a valid pointer at any given time, + * always pass a copy of it to map_rect_destroy() and set route_mr to NULL prior to calling + * map_rect_destroy(). The reason is that map_rect_destroy() for a route map may indirectly + * call navigation_update(), which will modify the same members. For the same reason, + * status_int must be reset before the call to map_rect_destroy(). + */ + this_->status_int = status_none; + this_->route_mr = NULL; + map_rect_destroy(mr); +} + +/** + * @brief Idle callback function to retrieve items from the route map. + * + * @param this_ Points to the navigation object. The caller is responsible for initializing its + * {@code route_mr} member. After processing completes, the {@code route_mr} member will no longer + * be valid. + */ +static void +navigation_update_idle(struct navigation *this_) { + int count = 100; /* Maximum number of items retrieved in one run of this function. + * This should be set low enough for each pass to complete in less + * than a second even on low-performance devices. */ 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 item *sitem; /* Holds the item from the actual map which corresponds to ritem */ + struct attr street_item, street_direction; struct navigation_itm *itm; - struct attr vehicleprofile; - int mode=0, incr=0, first=1; - if (attr->type != attr_route_status) - return; - dbg(lvl_debug,"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) + /* Do not use the route_path_flag_cancel flag here because it is also used whenever + * destinations or waypoints change, not just when the user stops navigation altogether + */ + if (!route_has_graph(this_->route)) { + navigation_update_done(this_, 1); return; + } - if (! this_->route) - return; - map=route_get_map(this_->route); - if (! map) - return; - mr=map_rect_new(map, NULL); - if (! mr) - return; - if (route_get_attr(route, attr_vehicleprofile, &vehicleprofile, NULL)) - this_->vehicleprofile=vehicleprofile.u.vehicleprofile; - else - this_->vehicleprofile=NULL; - dbg(lvl_debug,"enter\n"); - while ((ritem=map_rect_get_item(mr))) { - if (ritem->type == type_route_start && this_->turn_around > -this_->turn_around_limit+1) + while (count > 0) { + if (!(ritem = map_rect_get_item(this_->route_mr))) { + this_->status_int &= ~(status_has_ritem); + break; + } + this_->status_int |= status_has_ritem; + 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) + if ((ritem)->type == type_route_start_reverse && this_->turn_around < this_->turn_around_limit) this_->turn_around++; - if (ritem->type != type_street_route) + if ((ritem)->type != type_street_route) continue; - if (first && item_attr_get(ritem, attr_street_item, &street_item)) { - first=0; + if ((!(this_->status_int & status_has_sitem)) && item_attr_get(ritem, attr_street_item, &street_item)) { + this_->status_int |= status_has_sitem; if (!item_attr_get(ritem, attr_direction, &street_direction)) - street_direction.u.num=0; - sitem=street_item.u.item; + street_direction.u.num = 0; + sitem = street_item.u.item; dbg(lvl_debug,"sitem=%p\n", sitem); - itm=item_hash_lookup(this_->hash, sitem); + itm = item_hash_lookup(this_->hash, sitem); dbg(lvl_info,"itm for item with id (0x%x,0x%x) is %p\n", sitem->id_hi, sitem->id_lo, itm); if (itm && itm->way.dir != street_direction.u.num) { dbg(lvl_info,"wrong direction\n"); - itm=NULL; + itm = NULL; } navigation_destroy_itms_cmds(this_, itm); if (itm) { @@ -3672,20 +3757,90 @@ navigation_update(struct navigation *this_, struct route *route, struct attr *at dbg(lvl_debug,"not on track\n"); } navigation_itm_new(this_, ritem); + count--; + } + if (count > 0) { + /* if count > 0, one of the break conditions in the loop was true and we're done */ + navigation_update_done(this_, 0); + return; } - dbg(lvl_info,"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_,this_->route); +} + +/** + * @brief Event handler for changes to the route. + * + * This function is added to the callback list of the current route. It is called whenever the + * status of the route changes and will either discard the current list of maneuvers or build a new + * list. + * + * @param this_ The navigation object + * @param route The route + * @param attr The route status attribute + */ +static void +navigation_update(struct navigation *this_, struct route *route, struct attr *attr) +{ + struct map *map; + struct attr vehicleprofile; + struct attr nav_status; + + if (attr->type != attr_route_status) + return; + + dbg(lvl_debug,"enter\n"); + + nav_status.type = attr_nav_status; + switch(attr->u.num) { + case route_status_not_found: + nav_status.u.num = status_no_route; + break; + case route_status_no_destination: + nav_status.u.num = status_no_destination; + break; + case route_status_destination_set: + nav_status.u.num = status_position_wait; + break; + case route_status_building_path: + case route_status_building_graph: + case route_status_path_done_new: + case route_status_path_done_incremental: + nav_status.u.num = (this_->nav_status >= status_recalculating) ? status_recalculating : status_calculating; + } + navigation_set_attr(this_, &nav_status); + + 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) { + if (this_->status_int & status_busy) { + navigation_update_done(this_, 1); } - calculate_dest_distance(this_, incr); - profile(0,"end"); - navigation_call_callbacks(this_, FALSE); + return; + } + + if (! this_->route) + return; + map=route_get_map(this_->route); + if (! map) + return; + this_->route_mr = map_rect_new(map, NULL); + if (! this_->route_mr) + return; + if (route_get_attr(route, attr_vehicleprofile, &vehicleprofile, NULL)) + this_->vehicleprofile=vehicleprofile.u.vehicleprofile; + else + this_->vehicleprofile=NULL; + dbg(lvl_debug,"enter\n"); + + this_->status_int = status_busy; + if (route_get_flags(this_->route) & route_path_flag_async) { + this_->idle_cb = callback_new_1(callback_cast(navigation_update_idle), this_); + this_->idle_ev = event_add_idle(50, this_->idle_cb); + } else { + this_->idle_ev = NULL; + this_->idle_cb = NULL; + while (this_->status_int & status_busy) + navigation_update_idle(this_); } - map_rect_destroy(mr); } static void diff --git a/navit/navit.c b/navit/navit.c index 2fe37c384..0ac6783cd 100644 --- a/navit/navit.c +++ b/navit/navit.c @@ -1552,7 +1552,8 @@ navit_mark_navigation_stopped(char *former_destination_file){ * @param navit The navit instance * @param c The coordinate to start routing to * @param description A label which allows the user to later identify this destination in the former destinations selection - * @returns nothing + * @param async Set to 1 to do route calculation asynchronously + * @return nothing */ void navit_set_destination(struct navit *this_, struct pcoord *c, const char *description, int async) diff --git a/navit/route.c b/navit/route.c index d8d29462e..a55334149 100644 --- a/navit/route.c +++ b/navit/route.c @@ -78,13 +78,6 @@ struct map_priv { int debug_route=0; -enum route_path_flags { - route_path_flag_none=0, - route_path_flag_cancel=1, - route_path_flag_async=2, - route_path_flag_no_rebuild=4, -}; - /** * @brief A point in the route graph * @@ -246,7 +239,7 @@ struct route_path { struct route { NAVIT_OBJECT struct mapset *ms; /**< The mapset this route is built upon */ - unsigned flags; + enum route_path_flags flags; struct route_info *pos; /**< Current position within this route */ GList *destinations; /**< Destinations of the route */ int reached_destinations_count; /**< Used as base to calculate waypoint numbers */ @@ -854,17 +847,28 @@ route_path_update_done(struct route *this, int new_graph) * @brief Updates the route graph and the route path if something changed with the route * * This will update the route graph and the route path of the route if some of the - * route's settings (destination, position) have changed. + * route's settings (destination, position) have changed. + * + * The behavior of this function can be controlled via flags: + * <ul> + * <li>{@code route_path_flag_cancel}: Cancel navigation, clear route graph and route path</li> + * <li>{@code route_path_flag_async}: Perform operations asynchronously</li> + * <li>{@code route_path_flag_no_rebuild}: Do not rebuild the route graph</li> + * </ul> * + * These flags will be stored in the {@code flags} member of the route object. + * * @attention For this to work the route graph has to be destroyed if the route's * @attention destination is changed somewhere! * * @param this The route to update + * @param flags Flags to control the behavior of this function, see description */ static void route_path_update_flags(struct route *this, enum route_path_flags flags) { dbg(lvl_debug,"enter %d\n", flags); + this->flags = flags; if (! this->pos || ! this->destinations) { dbg(lvl_debug,"destroy\n"); route_path_destroy(this->path2,1); @@ -897,6 +901,15 @@ route_path_update_flags(struct route *this, enum route_path_flags flags) } } +/** + * @brief Updates the route graph and the route path if something changed with the route + * + * This function is a wrapper around {@link route_path_update_flags(route *, enum route_path)}. + * + * @param this The route to update + * @param cancel If true, cancel navigation, clear route graph and route path + * @param async If true, perform processing asynchronously + */ static void route_path_update(struct route *this, int cancel, int async) { @@ -1153,8 +1166,8 @@ route_clear_destinations(struct route *this_) * * @param this The route to set the destination for * @param dst Coordinates to set as destination - * @param count: Number of destinations (last one is final) - * @param async: If set, do routing asynchronously + * @param count Number of destinations (last one is final) + * @param async If set, do routing asynchronously */ void @@ -1283,8 +1296,8 @@ route_get_destination_description(struct route *this, int n) * @brief Start a route given set of coordinates * * @param this The route instance - * @param c The coordinate to start routing to - * @param async 1 for async + * @param dst The coordinate to start routing to + * @param async Set to 1 to do route calculation asynchronously * @return nothing */ void @@ -2979,11 +2992,13 @@ route_graph_build_idle(struct route_graph *rg, struct vehicleprofile *profile) * between c1 and c2. * * @param ms The mapset to build the route graph from + * @param c The coordinates of the destination or next waypoint * @param c1 Corner 1 of the rectangle to use from the map * @param c2 Corner 2 of the rectangle to use from the map * @param done_cb The callback which will be called when graph is complete * @return The new route graph. */ +// FIXME documentation does not match argument list static struct route_graph * route_graph_build(struct mapset *ms, struct coord *c, int count, struct callback *done_cb, int async, struct vehicleprofile *profile) { @@ -3019,6 +3034,8 @@ route_graph_update_done(struct route *this, struct callback *cb) * adds routing information afterwards by calling route_graph_flood(). * * @param this The route to update the graph for + * @param cb The callback function to call when the route graph update is complete (used only in asynchronous mode) + * @param async Set to nonzero in order to update the route graph asynchronously */ static void route_graph_update(struct route *this, struct callback *cb, int async) @@ -3723,7 +3740,7 @@ rm_rect_destroy(struct map_rect_priv *mr) } if (mr->path) { mr->path->in_use--; - if (mr->path->update_required && (mr->path->in_use==1)) + if (mr->path->update_required && (mr->path->in_use==1) && (mr->mpriv->route->route_status & ~route_status_destination_set)) route_path_update_done(mr->mpriv->route, mr->path->update_required-1); else if (!mr->path->in_use) g_free(mr->path); @@ -4003,6 +4020,24 @@ route_get_graph_map(struct route *this_) return route_get_map_helper(this_, &this_->graph_map, "route_graph","Route Graph"); } + +/** + * @brief Returns the flags for the route. + */ +enum route_path_flags route_get_flags(struct route *this_) { + return this_->flags; +} + +/** + * @brief Whether the route has a valid graph. + * + * @return True if the route has a graph, false if not. + */ +int +route_has_graph(struct route *this_) { + return (this_->graph != NULL); +} + void route_set_projection(struct route *this_, enum projection pro) { diff --git a/navit/route.h b/navit/route.h index 5daae7f89..5f55f804c 100644 --- a/navit/route.h +++ b/navit/route.h @@ -31,6 +31,13 @@ #ifdef __cplusplus extern "C" { #endif +enum route_path_flags { + route_path_flag_none=0, + route_path_flag_cancel=1, + route_path_flag_async=2, + route_path_flag_no_rebuild=4, +}; + enum route_status { route_status_no_destination=0, route_status_destination_set=1, @@ -111,6 +118,8 @@ void route_info_free(struct route_info *inf); struct street_data *route_info_street(struct route_info *rinf); struct map *route_get_map(struct route *this_); struct map *route_get_graph_map(struct route *this_); +enum route_path_flags route_get_flags(struct route *this_); +int route_has_graph(struct route *this_); void route_set_projection(struct route *this_, enum projection pro); void route_set_destinations(struct route *this_, struct pcoord *dst, int count, int async); int route_set_attr(struct route *this_, struct attr *attr); |