summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormvglasow <michael@vonglasow.com>2015-11-08 15:50:07 +0100
committermvglasow <michael@vonglasow.com>2015-11-08 15:50:07 +0100
commitffdc3eace672e5cfd59f0a4f0e78cd3e5e3b5d86 (patch)
tree0e758aae4d331984fc2456f5d474dd3074694fce
parent26788fb75cac1b51371e54cedebdbfa6887b597a (diff)
parent6d94fdea12a166d4d7832d0c3df0df474b276d24 (diff)
downloadnavit-ffdc3eace672e5cfd59f0a4f0e78cd3e5e3b5d86.tar.gz
Merge pull request #29 from mvglasow/trac1324R6332
Merge:core:Merge fix for #1324
-rw-r--r--navit/attr_def.h1
-rw-r--r--navit/navigation.c251
-rw-r--r--navit/navit.c3
-rw-r--r--navit/route.c63
-rw-r--r--navit/route.h9
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);