summaryrefslogtreecommitdiff
path: root/navit/traffic.c
diff options
context:
space:
mode:
Diffstat (limited to 'navit/traffic.c')
-rw-r--r--navit/traffic.c930
1 files changed, 783 insertions, 147 deletions
diff --git a/navit/traffic.c b/navit/traffic.c
index 7a0b74480..475659834 100644
--- a/navit/traffic.c
+++ b/navit/traffic.c
@@ -76,18 +76,25 @@
/** Flag to indicate the message store should not be exported */
#define PROCESS_MESSAGES_NO_DUMP_STORE 1 << 1
-/** The lowest order of items to consider */
-#define ROUTE_ORDER 18
+/** The lowest order of items to consider (always the default order for the next-lower road type) */
+#define ROUTE_ORDER(x) (((x == type_highway_land) || (x == type_highway_city) || (x == type_street_n_lanes)) \
+ ? 10 : ((x == type_street_4_land) || (x == type_street_4_city)) ? 12 : 18)
/** The buffer zone around the enclosing rectangle used in route calculations, absolute distance */
-#define ROUTE_RECT_DIST_ABS 1000
+#define ROUTE_RECT_DIST_ABS(x) ((x == location_fuzziness_low_res) ? 1000 : 100)
/** The buffer zone around the enclosing rectangle used in route calculations, relative to rect size */
-#define ROUTE_RECT_DIST_REL 0
+#define ROUTE_RECT_DIST_REL(x) 0
+
+/** Maximum textfile line size */
+#define TEXTFILE_LINE_SIZE 512
/** Time slice for idle loops, in milliseconds */
#define TIME_SLICE 40
+/** Default value assumed for access flags if we cannot get flags for the item, nor for the item type */
+int item_default_flags_value = AF_ALL;
+
/**
* @brief Private data shared between all traffic instances.
*/
@@ -95,6 +102,9 @@ struct traffic_shared_priv {
GList * messages; /**< Currently active messages */
GList * message_queue; /**< Queued messages, waiting to be processed */
// TODO messages by ID? In a later phase…
+ struct mapset *ms; /**< The mapset used for routing */
+ struct route *rt; /**< The route to notify of traffic changes */
+ struct map *map; /**< The traffic map, in which traffic distortions are stored */
};
/**
@@ -112,12 +122,10 @@ struct traffic {
struct event_timeout * timeout; /**< The timeout event that triggers the loop function */
struct callback *idle_cb; /**< Idle callback to process new messages */
struct event_idle *idle_ev; /**< The pointer to the idle event */
- struct mapset *ms; /**< The mapset used for routing */
- struct route *rt; /**< The route to notify of traffic changes */
- struct map *map; /**< The traffic map, in which traffic distortions are stored */
};
struct traffic_location_priv {
+ char * txt_data; /*!< Persisted location data in txtfile map format. */
struct coord_geo * sw; /*!< Southwestern corner of rectangle enclosing all points.
* Calculated by Navit from the points of the location. */
struct coord_geo * ne; /*!< Northeastern corner of rectangle enclosing all points.
@@ -135,6 +143,7 @@ struct traffic_message_priv {
*/
struct map_priv {
GList * items; /**< The map items */
+ struct traffic_shared_priv *shared; /**< Private data shared between all instances */
// TODO items by start/end coordinates? In a later phase…
};
@@ -179,6 +188,21 @@ struct item_priv {
};
/**
+ * @brief Parsed data for a cached item
+ */
+struct parsed_item {
+ enum item_type type; /**< The item type */
+ int id_hi; /**< The high-order part of the identifier */
+ int id_lo; /**< The low-order part of the identifier */
+ int flags; /**< Access and other flags for the item */
+ struct attr **attrs; /**< The attributes for the item, `NULL`-terminated */
+ struct coord *coords; /**< The coordinates for the item */
+ int coord_count; /**< The number of elements in `coords` */
+ int length; /**< The length of the segment in meters */
+ int is_matched; /**< Whether any of the maps has a matching item */
+};
+
+/**
* @brief Data for segments affected by a traffic message.
*
* Speed can be specified in three different ways:
@@ -232,6 +256,7 @@ struct xml_state {
struct traffic_point * not_via; /**< A point NOT between `from` and `to`. Required on ring roads
* unless `via` is used; cannot be used together with `at`. */
struct traffic_location * location; /**< The location to which the next message refers. */
+ char * location_txt_data; /**< Persisted location data in txtfile map format. */
GList * si; /**< Supplementary information items for the next event. */
GList * events; /**< The events for the next message. */
};
@@ -249,6 +274,8 @@ struct xml_element {
char * text; /**< Character data (NULL-terminated) */
};
+static struct map_methods traffic_map_meth;
+
static struct seg_data * seg_data_new(void);
static struct item * tm_add_item(struct map *map, enum item_type type, int id_hi, int id_lo,
int flags, struct attr **attrs, struct coord *c, int count, char * id);
@@ -265,14 +292,18 @@ static int tm_coord_get(void *priv_data, struct coord *c, int count);
static void tm_attr_rewind(void *priv_data);
static int tm_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr);
static int tm_type_set(void *priv_data, enum item_type type);
+static struct map_selection * traffic_location_get_rect(struct traffic_location * this_, enum projection projection);
static struct route_graph * traffic_location_get_route_graph(struct traffic_location * this_,
struct mapset * ms);
static int traffic_location_match_attributes(struct traffic_location * this_, struct item *item);
static int traffic_message_add_segments(struct traffic_message * this_, struct mapset * ms, struct seg_data * data,
struct map *map, struct route * route);
+static int traffic_message_restore_segments(struct traffic_message * this_, struct mapset * ms,
+ struct map *map, struct route * route);
static void traffic_location_populate_route_graph(struct traffic_location * this_, struct route_graph * rg,
struct mapset * ms);
-static void traffic_dump_messages_to_xml(struct traffic * this_);
+static void traffic_location_set_enclosing_rect(struct traffic_location * this_, struct coord_geo ** coords);
+static void traffic_dump_messages_to_xml(struct traffic_shared_priv * shared);
static void traffic_loop(struct traffic * this_);
static struct traffic * traffic_new(struct attr *parent, struct attr **attrs);
static int traffic_process_messages_int(struct traffic * this_, int flags);
@@ -280,6 +311,8 @@ static void traffic_message_dump_to_stderr(struct traffic_message * this_);
static struct seg_data * traffic_message_parse_events(struct traffic_message * this_);
static struct route_graph_point * traffic_route_flood_graph(struct route_graph * rg, struct seg_data * data,
struct coord * c_start, struct coord * c_dst, struct route_graph_point * start_existing);
+static void traffic_message_remove_item_data(struct traffic_message * old, struct traffic_message * new,
+ struct route * route);
static struct item_methods methods_traffic_item = {
tm_coord_rewind,
@@ -324,6 +357,18 @@ static int boolean_new(const char * string, int deflt) {
}
/**
+ * @brief Destructor for `struct parsed_item`
+ *
+ * This frees up the `struct parsed_item` and all associated data. The pointer passed to this function will
+ * be invalid after it returns.
+ */
+static void parsed_item_destroy(struct parsed_item * this_) {
+ g_free(this_->coords);
+ attr_list_free(this_->attrs);
+ g_free(this_);
+}
+
+/**
* @brief Creates a new `struct seg_data` and initializes it with default values.
*/
static struct seg_data * seg_data_new(void) {
@@ -405,7 +450,7 @@ static int seg_data_equals(struct seg_data * l, struct seg_data * r) {
* @param msgid The message ID
* @param speed The maximum speed for the segment (`INT_MAX` if none given)
* @param delay The delay for the segment, in tenths of seconds (0 for none)
- * @param attrs Additional attributes specified by the message
+ * @param attrs Additional attributes specified by the message, can be NULL
* @param route The route affected by the changes
*
* @return true if data was changed, false if not
@@ -723,6 +768,43 @@ static struct item * tm_find_item(struct map_rect *mr, enum item_type type, stru
return ret;
}
+/**
+ * @brief Dumps an item to a file in textfile format.
+ *
+ * All data passed to this method is safe to free after the method returns, and doing so is the
+ * responsibility of the caller.
+ *
+ * @param item The item
+ * @param f The file to write to
+ */
+static void tm_item_dump_to_file(struct item * item, FILE * f) {
+ struct item_priv * ip = (struct item_priv *) item->priv_data;
+ struct attr **attrs = ip->attrs;
+ struct coord *c = ip->coords;
+ int i;
+ char * attr_text;
+
+ fprintf(f, "type=%s", item_to_name(item->type));
+ fprintf(f, " id=0x%x,0x%x", item->id_hi, item->id_lo);
+ while (*attrs) {
+ if ((*attrs)->type == attr_flags) {
+ /* special handling for flags */
+ fprintf(f, " flags=0x%x", (unsigned int)(*attrs)->u.num);
+ } else {
+ attr_text = attr_to_text(*attrs, NULL, 0);
+ /* FIXME this may not work properly for all attribute types */
+ fprintf(f, " %s=%s", attr_to_name((*attrs)->type), attr_text);
+ g_free(attr_text);
+ }
+ attrs++;
+ }
+ fprintf(f, "\n");
+
+ for (i = 0; i < ip->coord_count; i++) {
+ fprintf(f,"0x%x 0x%x\n", c[i].x, c[i].y);
+ }
+}
+
#ifdef TRAFFIC_DEBUG
/**
* @brief Dumps an item to a textfile map.
@@ -749,19 +831,7 @@ static void tm_dump_item_to_textfile(struct item * item) {
if (dist_filename) {
FILE *map = fopen(dist_filename,"a");
if (map) {
- fprintf(map, "type=%s", item_to_name(item->type));
- while (*attrs) {
- attr_text = attr_to_text(*attrs, NULL, 0);
- /* FIXME this may not work properly for all attribute types */
- fprintf(map, " %s=%s", attr_to_name((*attrs)->type), attr_text);
- g_free(attr_text);
- attrs++;
- }
- fprintf(map, "\n");
-
- for (i = 0; i < ip->coord_count; i++) {
- fprintf(map,"0x%x 0x%x\n", c[i].x, c[i].y);
- }
+ tm_item_dump_to_file(item, map);
fclose(map);
} else {
dbg(lvl_error,"could not open file for distortions !!");
@@ -867,11 +937,62 @@ static void tm_destroy(struct map_priv *priv) {
*/
static struct map_rect_priv * tm_rect_new(struct map_priv *priv, struct map_selection *sel) {
struct map_rect_priv * mr;
+
+ /* Iterator over active messages */
+ GList * msgiter;
+
+ /* Current message */
+ struct traffic_message * message;
+
+ /* Map selection for current message, current map rect selection */
+ struct map_selection * msg_sel, * rect_sel;
+
+ /* Attributes for traffic distortions generated from the current traffic message */
+ struct seg_data * data;
+
+ /* Whether new segments have been added */
+ int dirty = 0;
+
dbg(lvl_debug,"enter");
mr=g_new0(struct map_rect_priv, 1);
mr->mpriv = priv;
mr->next_item = priv->items;
/* all other pointers are initially NULL */
+
+ /* lazy location matching */
+ if (sel != NULL)
+ /* TODO experimental: if no selection is passed, do not resolve any locations */
+ for (msgiter = priv->shared->messages; msgiter; msgiter = g_list_next(msgiter)) {
+ message = (struct traffic_message *) msgiter->data;
+ if (message->priv->items == NULL) {
+ traffic_location_set_enclosing_rect(message->location, NULL);
+ msg_sel = traffic_location_get_rect(message->location, traffic_map_meth.pro);
+ for (rect_sel = sel; rect_sel; rect_sel = rect_sel->next)
+ if (coord_rect_overlap(&(msg_sel->u.c_rect), &(rect_sel->u.c_rect))) {
+ /* TODO do this in an idle loop, not here */
+ /* lazy cache restore */
+ if (message->location->priv->txt_data) {
+ dbg(lvl_debug, "location has txt_data, trying to restore");
+ traffic_message_restore_segments(message, priv->shared->ms,
+ priv->shared->map, priv->shared->rt);
+ } else {
+ dbg(lvl_debug, "location has no txt_data, nothing to restore");
+ }
+ /* if cache restore yielded no items, expand from scratch */
+ if (message->priv->items == NULL) {
+ data = traffic_message_parse_events(message);
+ traffic_message_add_segments(message, priv->shared->ms, data, priv->shared->map, priv->shared->rt);
+ g_free(data);
+ }
+ dirty = 1;
+ break;
+ }
+ map_selection_destroy(msg_sel);
+ }
+ }
+ if (dirty)
+ /* dump message store if new messages have been received */
+ traffic_dump_messages_to_xml(priv->shared);
return mr;
}
@@ -953,6 +1074,27 @@ static struct item * tm_rect_create_item(struct map_rect_priv *mr, enum item_typ
return ret;
}
+
+/**
+ * @brief Gets an attribute from the traffic map
+ *
+ * This only supports the `attr_traffic` attribute, which is currently only used for the purpose of
+ * identifying the map as a traffic map. Note, however, that for now the attribute will have a null pointer.
+ *
+ * @param map_priv Private data of the traffic map
+ * @param type The type of the attribute to be read
+ * @param attr Pointer to an attrib-structure where the attribute should be written to
+ * @return True if the attribute type was found, false if not
+ */
+static int tm_get_attr(struct map_priv *priv, enum attr_type type, struct attr *attr) {
+ if (attr_type == attr_traffic) {
+ attr->type = attr_traffic;
+ attr->u.traffic = NULL;
+ return 1;
+ } else
+ return 0;
+}
+
/**
* @brief Rewinds the coordinates of the currently selected item.
*
@@ -1072,7 +1214,7 @@ static struct map_methods traffic_map_meth = {
NULL, /* map_search_destroy: Destroy a map search struct, ignored if `map_search_new` is NULL */
NULL, /* map_search_get_item: Get the next item of a search on the map */
tm_rect_create_item, /* map_rect_create_item: Create a new item in the map */
- NULL, /* map_get_attr */
+ tm_get_attr, /* map_get_attr */
NULL, /* map_set_attr */
};
@@ -1704,6 +1846,27 @@ static void traffic_location_set_enclosing_rect(struct traffic_location * this_,
}
/**
+ * @brief Obtains a map selection for the traffic location.
+ *
+ * The map selection is a rectangle around the points of the traffic location, with some extra padding as
+ * specified in `ROUTE_RECT_DIST_REL` and `ROUTE_RECT_DIST_ABS`, with a map order specified in `ROUTE_ORDER`.
+ *
+ * @param this_ The traffic location
+ * @param projection The projection to be used by coordinates of the selection (should correspond to the
+ * projection of the target map)
+ *
+ * @return A map selection
+ */
+static struct map_selection * traffic_location_get_rect(struct traffic_location * this_, enum projection projection) {
+ /* Corners of the enclosing rectangle, in Mercator coordinates */
+ struct coord c1, c2;
+ transform_from_geo(projection, this_->priv->sw, &c1);
+ transform_from_geo(projection, this_->priv->ne, &c2);
+ return route_rect(ROUTE_ORDER(this_->road_type), &c1, &c2, ROUTE_RECT_DIST_REL(this_->fuzziness),
+ ROUTE_RECT_DIST_ABS(this_->fuzziness));
+}
+
+/**
* @brief Opens a map rectangle around the end points of the traffic location.
*
* Prior to calling this function, the caller must ensure `rg->m` points to the map to be used, and the enclosing
@@ -1716,13 +1879,7 @@ static void traffic_location_set_enclosing_rect(struct traffic_location * this_,
*/
static struct map_rect * traffic_location_open_map_rect(struct traffic_location * this_, struct route_graph * rg) {
/* Corners of the enclosing rectangle, in Mercator coordinates */
- struct coord c1, c2;
-
- transform_from_geo(map_projection(rg->m), this_->priv->sw, &c1);
- transform_from_geo(map_projection(rg->m), this_->priv->ne, &c2);
-
- rg->sel = route_rect(ROUTE_ORDER, &c1, &c2, ROUTE_RECT_DIST_REL, ROUTE_RECT_DIST_ABS);
-
+ rg->sel = traffic_location_get_rect(this_, map_projection(rg->m));
if (!rg->sel)
return NULL;
rg->mr = map_rect_new(rg->m, rg->sel);
@@ -1763,9 +1920,6 @@ static void traffic_location_populate_route_graph(struct traffic_location * this
/* Whether the current item is segmented */
int segmented;
- /* Default value assumed for access flags if we cannot get flags for the item, nor for the item type */
- int default_flags_value = AF_ALL;
-
/* Default flags assumed for the current item type */
int *default_flags;
@@ -1780,6 +1934,9 @@ static void traffic_location_populate_route_graph(struct traffic_location * this
rg->h = mapset_open(ms);
while ((rg->m = mapset_next(rg->h, 2))) {
+ /* Skip traffic map (identified by the `attr_traffic` attribute) */
+ if (map_get_attr(rg->m, attr_traffic, &attr, NULL))
+ continue;
if (!traffic_location_open_map_rect(this_, rg))
continue;
while ((item = map_rect_get_item(rg->mr))) {
@@ -1787,6 +1944,23 @@ static void traffic_location_populate_route_graph(struct traffic_location * this
route_graph_add_turn_restriction(rg, item);
else if ((item->type < route_item_first) || (item->type > route_item_last))
continue;
+ /* If road class is motorway, trunk or primary, ignore roads more than one level below */
+ if ((this_->road_type == type_highway_land) || (this_->road_type == type_highway_city)) {
+ if ((item->type != type_highway_land) && (item->type != type_highway_city) &&
+ (item->type != type_street_n_lanes) && (item->type != type_ramp))
+ continue;
+ } else if (this_->road_type == type_street_n_lanes) {
+ if ((item->type != type_highway_land) && (item->type != type_highway_city) &&
+ (item->type != type_street_n_lanes) && (item->type != type_ramp) &&
+ (item->type != type_street_4_land) && (item->type != type_street_4_city))
+ continue;
+ } else if ((this_->road_type == type_street_4_land) || (this_->road_type == type_street_4_city)) {
+ if ((item->type != type_highway_land) && (item->type != type_highway_city) &&
+ (item->type != type_street_n_lanes) && (item->type != type_ramp) &&
+ (item->type != type_street_4_land) && (item->type != type_street_4_city) &&
+ (item->type != type_street_3_land) && (item->type != type_street_3_city))
+ continue;
+ }
if (item_get_default_flags(item->type)) {
item_coord_rewind(item);
@@ -1800,7 +1974,7 @@ static void traffic_location_populate_route_graph(struct traffic_location * this
segmented = 0;
if (!(default_flags = item_get_default_flags(item->type)))
- default_flags = &default_flags_value;
+ default_flags = &item_default_flags_value;
if (item_attr_get(item, attr_flags, &attr)) {
data.flags = attr.u.num;
segmented = (data.flags & AF_SEGMENTED);
@@ -2442,6 +2616,9 @@ static GList * traffic_location_get_matching_points(struct traffic_location * th
/* The point from the location to match */
struct traffic_point * trpoint = NULL;
+ /* Map attribute (currently not evaluated) */
+ struct attr attr;
+
/* The item being processed */
struct item *item;
@@ -2467,6 +2644,9 @@ static GList * traffic_location_get_matching_points(struct traffic_location * th
rg->h = mapset_open(ms);
while ((rg->m = mapset_next(rg->h, 2))) {
+ /* Skip traffic map (identified by the `attr_traffic` attribute) */
+ if (map_get_attr(rg->m, attr_traffic, &attr, NULL))
+ continue;
if (!traffic_location_open_map_rect(this_, rg))
continue;
while ((item = map_rect_get_item(rg->mr))) {
@@ -2569,6 +2749,105 @@ static int route_graph_point_is_endpoint_candidate(struct route_graph_point *thi
}
/**
+ * @brief Gets the speed for a traffic distortion item.
+ *
+ * @param item The road item to which the traffic distortion refers (not the traffic distortion item)
+ * @param data Segment data
+ * @param item_maxspeed Speed limit for the item, `INT_MAX` if none
+ */
+static int traffic_get_item_speed(struct item * item, struct seg_data * data, int item_maxspeed) {
+ /* Speed calculated in various ways */
+ int maxspeed, speed, penalized_speed, factor_speed;
+
+ speed = data->speed;
+ if ((data->speed != INT_MAX) || data->speed_penalty || (data->speed_factor != 100)) {
+ if (item_maxspeed != INT_MAX) {
+ maxspeed = item_maxspeed;
+ } else {
+ switch (item->type) {
+ case type_highway_land:
+ case type_street_n_lanes:
+ maxspeed = 100;
+ break;
+ case type_highway_city:
+ case type_street_4_land:
+ maxspeed = 80;
+ break;
+ case type_street_3_land:
+ maxspeed = 70;
+ break;
+ case type_street_2_land:
+ maxspeed = 65;
+ break;
+ case type_street_1_land:
+ maxspeed = 60;
+ break;
+ case type_street_4_city:
+ maxspeed = 50;
+ break;
+ case type_ramp:
+ case type_street_3_city:
+ case type_street_unkn:
+ maxspeed = 40;
+ break;
+ case type_street_2_city:
+ case type_track_paved:
+ maxspeed = 30;
+ break;
+ case type_track:
+ case type_cycleway:
+ maxspeed = 20;
+ break;
+ case type_roundabout:
+ case type_street_1_city:
+ case type_street_0:
+ case type_living_street:
+ case type_street_service:
+ case type_street_parking_lane:
+ case type_path:
+ case type_track_ground:
+ case type_track_gravelled:
+ case type_track_unpaved:
+ case type_track_grass:
+ case type_bridleway:
+ maxspeed = 10;
+ break;
+ case type_street_pedestrian:
+ case type_footway:
+ case type_steps:
+ maxspeed = 5;
+ break;
+ default:
+ maxspeed = 50;
+ }
+ }
+ penalized_speed = maxspeed - data->speed_penalty;
+ if (penalized_speed < 5)
+ penalized_speed = 5;
+ factor_speed = maxspeed * data->speed_factor / 100;
+ if (speed > penalized_speed)
+ speed = penalized_speed;
+ if (speed > factor_speed)
+ speed = factor_speed;
+ }
+ return speed;
+}
+
+/**
+ * @brief Gets the delay for a traffic distortion item
+ *
+ * @param delay Total delay for all items associated with the same message and direction
+ * @param item_len Length of the current item
+ * @param len Combined length of all items associated with the same message and direction
+ */
+static int traffic_get_item_delay(int delay, int item_len, int len) {
+ if (delay)
+ return delay * item_len / len;
+ else
+ return delay;
+}
+
+/**
* @brief Generates segments affected by a traffic message.
*
* This translates the approximate coordinates in the `from`, `at`, `to`, `via` and `not_via` members of
@@ -2622,8 +2901,8 @@ static int traffic_message_add_segments(struct traffic_message * this_, struct m
/* Coordinates of matched segment, sorted */
struct coord *cd, *cs;
- /* Speed calculated in various ways */
- int maxspeed, speed, penalized_speed, factor_speed;
+ /* Speed for the current segment */
+ int speed;
/* Delay for the current segment */
int delay;
@@ -3025,82 +3304,10 @@ static int traffic_message_add_segments(struct traffic_message * this_, struct m
cs = g_new0(struct coord, ccnt);
cd = cs;
- speed = data->speed;
- if ((data->speed != INT_MAX) || data->speed_penalty || (data->speed_factor != 100)) {
- if (s->data.flags & AF_SPEED_LIMIT) {
- maxspeed = RSD_MAXSPEED(&s->data);
- } else {
- switch (s->data.item.type) {
- case type_highway_land:
- case type_street_n_lanes:
- maxspeed = 100;
- break;
- case type_highway_city:
- case type_street_4_land:
- maxspeed = 80;
- break;
- case type_street_3_land:
- maxspeed = 70;
- break;
- case type_street_2_land:
- maxspeed = 65;
- break;
- case type_street_1_land:
- maxspeed = 60;
- break;
- case type_street_4_city:
- maxspeed = 50;
- break;
- case type_ramp:
- case type_street_3_city:
- case type_street_unkn:
- maxspeed = 40;
- break;
- case type_street_2_city:
- case type_track_paved:
- maxspeed = 30;
- break;
- case type_track:
- case type_cycleway:
- maxspeed = 20;
- break;
- case type_roundabout:
- case type_street_1_city:
- case type_street_0:
- case type_living_street:
- case type_street_service:
- case type_street_parking_lane:
- case type_path:
- case type_track_ground:
- case type_track_gravelled:
- case type_track_unpaved:
- case type_track_grass:
- case type_bridleway:
- maxspeed = 10;
- break;
- case type_street_pedestrian:
- case type_footway:
- case type_steps:
- maxspeed = 5;
- break;
- default:
- maxspeed = 50;
- }
- }
- penalized_speed = maxspeed - data->speed_penalty;
- if (penalized_speed < 5)
- penalized_speed = 5;
- factor_speed = maxspeed * data->speed_factor / 100;
- if (speed > penalized_speed)
- speed = penalized_speed;
- if (speed > factor_speed)
- speed = factor_speed;
- }
+ speed = traffic_get_item_speed(&(s->data.item), data,
+ (s->data.flags & AF_SPEED_LIMIT) ? RSD_MAXSPEED(&s->data) : INT_MAX);
- if (data->delay)
- delay = data->delay * s->data.len / len;
- else
- delay = data->delay;
+ delay = traffic_get_item_delay(data->delay, s->data.len, len);
for (i = 0; i < ccnt; i++) {
*cd++ = *c++;
@@ -3152,6 +3359,366 @@ static int traffic_message_add_segments(struct traffic_message * this_, struct m
}
/**
+ * @brief Restores segments associated with a traffic message from cached data.
+ *
+ * This reads textfile map data and compares it to data in the current map set. If one or more items
+ * (identified by their ID) are no longer present in the map, or their coordinates no longer match, the
+ * cached data is discarded and the location needs to be expanded into a set of segments as for a new
+ * message. Otherwise the cached segments are added to the traffic map.
+ *
+ * While this operation does require extensive examination of map data, it is still less expensive than
+ * expanding the location from scratch, as the most expensive operation in the latter is routing between the
+ * points involved.
+ *
+ * @param this_ The traffic message
+ * @param ms The mapset to use for matching
+ * @param data Data for the segments to be added to the map, in textfile format
+ * @param map The traffic map
+ * @param route The route affected by the changes
+ *
+ * @return `true` if the locations were matched successfully, `false` if there was a failure.
+ */
+static int traffic_message_restore_segments(struct traffic_message * this_, struct mapset * ms,
+ struct map *map, struct route * route) {
+ /* Textfile data: pointers to current and next line, copy and length of current line */
+ char * data_curr = this_->location->priv->txt_data, * data_next, * line = NULL;
+ int len;
+
+ /* Iterator */
+ int i;
+
+ /* Data for attribute parsing */
+ int pos;
+ char name[TEXTFILE_LINE_SIZE];
+ char value[TEXTFILE_LINE_SIZE];
+
+ /* Item data */
+ enum item_type type;
+ int id_hi;
+ int id_lo;
+ int flags;
+ struct attr * attrs[TEXTFILE_LINE_SIZE / 4];
+ int acnt;
+
+ /* For map matching */
+ struct mapset_handle *msh;
+ struct map * m;
+ struct attr attr;
+ struct map_selection * msel;
+ struct map_rect * mr;
+ struct item * map_item;
+ int * default_flags;
+ int item_flags, segmented, maxspeed;
+ struct coord map_c;
+
+ /*
+ * Coordinate count for matched segment
+ * (-1 if we are expecting item type and attributes in the next line rather than coordinates)
+ */
+ int ccnt = -1;
+
+ /* Coordinates of matched segment and pointer into it, order as read from map */
+ struct coord ca[2048];
+
+ /* Newly added item */
+ struct parsed_item * pitem;
+ struct item * item;
+
+ /* Location length */
+ int loc_len = 0;
+
+ /* List of parsed items */
+ GList * items = NULL, * curr_item;
+
+ /* Whether all items are matched by a map item */
+ int is_matched;
+
+ struct seg_data * seg_data;
+
+ dbg(lvl_debug, "*****checkpoint RESTORE-1, txt_data:\n%s", this_->location->priv->txt_data);
+ traffic_location_set_enclosing_rect(this_->location, NULL);
+
+ while (1) {
+ if (data_curr) {
+ data_next = strchr(data_curr, 0x0a);
+ len = data_next ? (data_next - data_curr) : strlen(data_curr);
+ line = g_new0(char, len + 1);
+ strncpy(line, data_curr, len);
+ dbg(lvl_debug, "*****checkpoint RESTORE-2, line: %s", line);
+ }
+ if (line && (ccnt < 0)) {
+ /* first line with item type and attributes */
+ dbg(lvl_debug, "*****checkpoint RESTORE-3, item/attribute line");
+ pos = 0;
+ type = type_none;
+ id_hi = -1;
+ id_lo = -1;
+ acnt = 0;
+ while (attr_from_line(line, NULL, &pos, value, name)) {
+ dbg(lvl_debug, "*****checkpoint RESTORE-4, parsing %s=%s", name, value);
+ ccnt = 0;
+ if (!strcmp(name, "type")) {
+ /* item type */
+ dbg(lvl_debug, "*****checkpoint RESTORE-4.1, parsing type: %s", value);
+ type = item_from_name(value);
+ } else if (!strcmp(name, "id")) {
+ /* item ID */
+ dbg(lvl_debug, "*****checkpoint RESTORE-4.1, parsing ID: %s", value);
+ sscanf(value, "%i,%i", &id_hi, &id_lo);
+ dbg(lvl_debug, "*****checkpoint RESTORE-4.2, ID is 0x%x,0x%x", id_hi, id_lo);
+ } else if (!strcmp(name, "flags")) {
+ dbg(lvl_debug, "*****checkpoint RESTORE-4.1, parsing flags: %s", value);
+ char *tail;
+ if (value[0] == '0' && value[1] == 'x')
+ flags = strtoul(value, &tail, 0);
+ else
+ flags = strtol(value, &tail, 0);
+ if (*tail) {
+ dbg(lvl_warning, "Incorrect value '%s' for attribute '%s': expected a number, assuming 0x%x. \n", value, name, flags);
+ }
+ } else {
+ /* generic attribute */
+ dbg(lvl_debug, "*****checkpoint RESTORE-4.1, parsing attribute %s=%s", name, value);
+ attrs[acnt] = attr_new_from_text(name, value);
+ if (attrs[acnt])
+ acnt++;
+ }
+ }
+ if (ccnt < 0) {
+ /* empty line, ignore */
+ dbg(lvl_debug, "*****checkpoint RESTORE-4, skipping empty line");
+ }
+ attrs[acnt] = NULL;
+ g_free(line);
+ line = NULL;
+ if (data_next)
+ data_curr = data_next + 1;
+ else {
+ data_curr = NULL;
+ // TODO abort (last item is invalid as it has no coords)
+ }
+ } else if (line && coord_parse(line, projection_mg, &ca[ccnt])) {
+ /* add coordinates until we hit a line without */
+ ccnt++;
+ g_free(line);
+ line = NULL;
+ if (data_next)
+ data_curr = data_next + 1;
+ else
+ data_curr = NULL;
+ } else {
+ /* end of coordinates, find matching item */
+ if (line) {
+ g_free(line);
+ line = NULL;
+ }
+ if (ccnt < 1) {
+ /* not a complete item, possibly trailing empty line */
+ dbg(lvl_debug, "*****checkpoint RESTORE-5, skipping incomplete item (possibly trailing empty line)");
+ break;
+ }
+
+ pitem = g_new0(struct parsed_item, 1);
+ pitem->id_hi = id_hi;
+ pitem->id_lo = id_lo;
+ pitem->type = type;
+ pitem->flags = flags;
+ pitem->coords = g_new0(struct coord, ccnt);
+ for (i = 0; i < ccnt; i++)
+ pitem->coords[i] = ca[i];
+ pitem->coord_count = ccnt;
+ pitem->attrs = attr_list_dup(attrs);
+ for (i = 0; attrs[i]; i++) {
+ g_free(attrs[i]);
+ attrs[i] = NULL;
+ }
+ items = g_list_append(items, pitem);
+
+ if (!data_curr)
+ /* no more data to process, finish up */
+ break;
+
+ ccnt = -1;
+ }
+ } /* while 1 */
+
+ /*
+ * Walk through mapset and look for a routable item with a matching ID and geometry.
+ * If no match is found, the map data has changed since we generated the cached segments and we
+ * need to recreate the data. In this case, stop processing segments immediately and drop any
+ * segments restored so far.
+ */
+ if (items) {
+ dbg(lvl_debug, "*****checkpoint RESTORE-6, comparing items to map data");
+ msh = mapset_open(ms);
+ map_item = NULL;
+
+ while (!map_item && (m = mapset_next(msh, 2))) {
+ /* Skip traffic map (identified by the `attr_traffic` attribute) */
+ if (map_get_attr(m, attr_traffic, &attr, NULL))
+ continue;
+
+ msel = traffic_location_get_rect(this_->location, map_projection(m));
+ if (!msel)
+ continue;
+ mr = map_rect_new(m, msel);
+ if (!mr) {
+ map_selection_destroy(msel);
+ msel = NULL;
+ continue;
+ }
+ /*
+ * Iterate through items in the map.
+ */
+ while ((map_item = map_rect_get_item(mr))) {
+ /* If item is not routable, continue */
+ if ((map_item->type < route_item_first) || (map_item->type > route_item_last))
+ continue;
+ /* If road class is motorway, trunk or primary, ignore roads more than one level below */
+ if ((this_->location->road_type == type_highway_land) || (this_->location->road_type == type_highway_city)) {
+ if ((map_item->type != type_highway_land) && (map_item->type != type_highway_city) &&
+ (map_item->type != type_street_n_lanes) && (map_item->type != type_ramp))
+ continue;
+ } else if (this_->location->road_type == type_street_n_lanes) {
+ if ((map_item->type != type_highway_land) && (map_item->type != type_highway_city) &&
+ (map_item->type != type_street_n_lanes) && (map_item->type != type_ramp) &&
+ (map_item->type != type_street_4_land) && (map_item->type != type_street_4_city))
+ continue;
+ } else if ((this_->location->road_type == type_street_4_land) || (this_->location->road_type == type_street_4_city)) {
+ if ((map_item->type != type_highway_land) && (map_item->type != type_highway_city) &&
+ (map_item->type != type_street_n_lanes) && (map_item->type != type_ramp) &&
+ (map_item->type != type_street_4_land) && (map_item->type != type_street_4_city) &&
+ (map_item->type != type_street_3_land) && (map_item->type != type_street_3_city))
+ continue;
+ }
+ /* Look for a matching item in the cache */
+ for (curr_item = items; curr_item; curr_item = g_list_next(curr_item)) {
+ pitem = (struct parsed_item *) curr_item->data;
+
+ /* Skip already-matched items */
+ if (pitem->is_matched)
+ continue;
+ /* If IDs do not match, continue */
+ if ((map_item->id_hi != pitem->id_hi) || (map_item->id_lo != pitem->id_lo))
+ continue;
+ dbg(lvl_debug, "*****checkpoint RESTORE-6.0, comparing item 0x%x, 0x%x to map data",
+ pitem->id_hi, pitem->id_lo);
+ /* Get flags (access and other) for the item */
+ if (!(default_flags = item_get_default_flags(map_item->type)))
+ default_flags = &item_default_flags_value;
+ if (item_attr_get(map_item, attr_flags, &attr)) {
+ item_flags = attr.u.num;
+ segmented = (item_flags & AF_SEGMENTED);
+ } else {
+ item_flags = *default_flags;
+ segmented = 0;
+ }
+ /* Get maxspeed, if any */
+ if ((item_flags & AF_SPEED_LIMIT) && (item_attr_get(map_item, attr_maxspeed, &attr)))
+ maxspeed = attr.u.num;
+ else
+ maxspeed = INT_MAX;
+ /* Compare coordinates */
+ item_coord_rewind(map_item);
+ if (!segmented) {
+ for (i = 0; i < pitem->coord_count; i++) {
+ if (!item_coord_get(map_item, &map_c, 1)) {
+ /* map item has fewer coordinates than cached item */
+ dbg(lvl_debug, "*****checkpoint RESTORE-6.1, item 0x%x, 0x%x has fewer coordinates than cached item",
+ pitem->id_hi, pitem->id_lo);
+ map_item = NULL;
+ break;
+ }
+ if ((map_c.x != pitem->coords[i].x) || (map_c.y != pitem->coords[i].y)) {
+ /* coordinate mismatch between map item and cached item */
+ dbg(lvl_debug, "*****checkpoint RESTORE-6.1, coordinate #%d for item 0x%x, 0x%x does not match",
+ i, pitem->id_hi, pitem->id_lo);
+ map_item = NULL;
+ break;
+ }
+ }
+ if (map_item && item_coord_get(map_item, &map_c, 1)) {
+ /* map item has more coordinates than cached item */
+ dbg(lvl_debug, "*****checkpoint RESTORE-6.1, item 0x%x, 0x%x has more coordinates than cached item",
+ pitem->id_hi, pitem->id_lo);
+ map_item = NULL;
+ continue;
+ }
+ } else {
+ /* TODO implement comparison for segmented items */
+ dbg(lvl_debug, "*****checkpoint RESTORE-6.1, restoring segmented items is not supported yet");
+ map_item = NULL;
+ }
+ if (map_item) {
+ pitem->is_matched = 1;
+ for (i = 1; i < ccnt; i++)
+ pitem->length += transform_distance(map_projection(m), &(ca[i-1]), &(ca[i]));
+ loc_len += pitem->length;
+ }
+ }
+ }
+
+ map_selection_destroy(msel);
+ msel = NULL;
+ map_rect_destroy(mr);
+ mr = NULL;
+ }
+ mapset_close(msh);
+ msh = NULL;
+ } else {
+ dbg(lvl_debug, "*****checkpoint RESTORE-6, no items to compare");
+ }
+
+ /* No items = no match; else examine each item */
+ is_matched = !!items;
+ for (curr_item = items; is_matched && curr_item; curr_item = g_list_next(curr_item)) {
+ pitem = (struct parsed_item *) curr_item->data;
+ if (!pitem->is_matched) {
+ dbg(lvl_debug, "*****checkpoint RESTORE-6.2, item 0x%x, 0x%x is unmatched",
+ pitem->id_hi, pitem->id_lo);
+ is_matched = 0;
+ }
+ }
+
+ if (is_matched) {
+ dbg(lvl_debug, "*****checkpoint RESTORE-7, restoring items for message %s from cache", this_->id);
+ seg_data = traffic_message_parse_events(this_);
+ this_->priv->items = g_new0(struct item *, g_list_length(items) + 1);
+ i = 0;
+ for (curr_item = items; curr_item; curr_item = g_list_next(curr_item)) {
+ pitem = (struct parsed_item *) curr_item->data;
+ item = tm_add_item(map, pitem->type, pitem->id_hi, pitem->id_lo, pitem->flags, pitem->attrs,
+ pitem->coords, pitem->coord_count, this_->id);
+ parsed_item_destroy(pitem);
+ tm_item_add_message_data(item, this_->id,
+ traffic_get_item_speed(item, seg_data, maxspeed),
+ traffic_get_item_delay(seg_data->delay, pitem->length, loc_len),
+ NULL, route);
+ this_->priv->items[i] = item;
+ i++;
+ }
+ g_list_free(items);
+ items = NULL;
+ g_free(seg_data);
+ } else {
+ dbg(lvl_debug, "*****checkpoint RESTORE-7, items for message %s need to be regenerated", this_->id);
+ }
+
+ /* clean up */
+ for (curr_item = items; curr_item; curr_item = g_list_next(curr_item)) {
+ pitem = (struct parsed_item *) curr_item->data;
+ parsed_item_destroy(pitem);
+ }
+ if (this_->location->priv->txt_data) {
+ g_free(this_->location->priv->txt_data);
+ this_->location->priv->txt_data = NULL;
+ }
+
+ dbg(lvl_debug, "*****checkpoint RESTORE-8, done");
+ return is_matched;
+}
+
+/**
* @brief Prints a dump of a message to debug output.
*
* @param this_ The message to dump
@@ -3602,7 +4169,7 @@ static void traffic_set_shared(struct traffic *this_) {
/**
* @brief Dumps all currently active traffic messages to an XML file.
*/
-static void traffic_dump_messages_to_xml(struct traffic * this_) {
+static void traffic_dump_messages_to_xml(struct traffic_shared_priv * shared) {
/* add the configuration directory to the name of the file to use */
char *traffic_filename = g_strjoin(NULL, navit_get_user_data_directory(TRUE),
"/traffic.xml", NULL);
@@ -3612,12 +4179,13 @@ static void traffic_dump_messages_to_xml(struct traffic * this_) {
char * point_names[5] = {"from", "at", "via", "not_via", "to"};
struct traffic_point * points[5];
int i, j;
+ struct item ** curr;
if (traffic_filename) {
FILE *f = fopen(traffic_filename,"w");
if (f) {
fprintf(f, "<navit_messages>\n");
- for (msgiter = this_->shared->messages; msgiter; msgiter = g_list_next(msgiter)) {
+ for (msgiter = shared->messages; msgiter; msgiter = g_list_next(msgiter)) {
message = (struct traffic_message *) msgiter->data;
points[0] = message->location->from;
points[1] = message->location->at;
@@ -3687,6 +4255,15 @@ static void traffic_dump_messages_to_xml(struct traffic * this_) {
fprintf(f, "</%s>\n", point_names[i]);
}
+ if (message->priv->items) {
+ fprintf(f, " <navit_items>\n");
+ for (curr = message->priv->items; *curr; curr++) {
+ tm_item_dump_to_file(*curr, f);
+ }
+ fprintf(f, " </navit_items>\n");
+ } else if (message->location->priv->txt_data)
+ fprintf(f, " <navit_items>%s</navit_items>\n", message->location->priv->txt_data);
+
fprintf(f, " </location>\n");
fprintf(f, " <events>\n");
@@ -3782,6 +4359,12 @@ static int traffic_process_messages_int(struct traffic * this_, int flags) {
struct traffic_location * swap_location;
struct item ** swap_items;
+ /* Holds queried attributes */
+ struct attr attr;
+
+ /* Map selections for the location and the route, and iterator */
+ struct map_selection * loc_ms, * rt_ms, * ms_iter;
+
/* Time elapsed since start */
double msec = 0;
@@ -3836,8 +4419,40 @@ static int traffic_process_messages_int(struct traffic * this_, int flags) {
swap_candidate->priv->items = swap_items;
} else {
dbg(lvl_debug, "*****checkpoint PROCESS-4, need to find matching segments");
- /* else find matching segments from scratch */
- traffic_message_add_segments(message, this_->ms, data, this_->map, this_->rt);
+ if (route_get_attr(this_->shared->rt, attr_route_status, &attr, NULL)
+ && route_get_pos(this_->shared->rt)
+ && ((attr.u.num & route_status_destination_set))) {
+ traffic_location_set_enclosing_rect(message->location, NULL);
+ loc_ms = traffic_location_get_rect(message->location, traffic_map_meth.pro);
+ rt_ms = route_get_selection(this_->shared->rt);
+ for (ms_iter = rt_ms; ms_iter; ms_iter = ms_iter->next)
+ if (coord_rect_overlap(&(loc_ms->u.c_rect), &(ms_iter->u.c_rect))) {
+ /*
+ * If we have cached segments, restore them.
+ */
+ if (message->location->priv->txt_data) {
+ dbg(lvl_debug, "location has txt_data, trying to restore segments");
+ traffic_message_restore_segments(message, this_->shared->ms,
+ this_->shared->map, this_->shared->rt);
+ } else {
+ dbg(lvl_debug, "location has no txt_data, nothing to restore");
+ }
+ /*
+ * We need to find matching segments from scratch.
+ * This needs to happen immediately if we have a route and the location is within its map
+ * selection, as the message might have an effect on the route. Otherwise this operation
+ * is deferred until a rectangle overlapping with the location is queried.
+ */
+ if (!message->priv->items) {
+ /* TODO do this in an idle loop, not here */
+ traffic_message_add_segments(message, this_->shared->ms, data,
+ this_->shared->map, this_->shared->rt);
+ break;
+ map_selection_destroy(loc_ms);
+ map_selection_destroy(rt_ms);
+ }
+ }
+ }
ret |= MESSAGE_UPDATE_SEGMENTS;
}
@@ -3856,7 +4471,7 @@ static int traffic_process_messages_int(struct traffic * this_, int flags) {
if (stored_msg->priv->items)
ret |= MESSAGE_UPDATE_SEGMENTS;
this_->shared->messages = g_list_remove_all(this_->shared->messages, stored_msg);
- traffic_message_remove_item_data(stored_msg, message, this_->rt);
+ traffic_message_remove_item_data(stored_msg, message, this_->shared->rt);
traffic_message_destroy(stored_msg);
}
@@ -3908,7 +4523,7 @@ static int traffic_process_messages_int(struct traffic * this_, int flags) {
if (stored_msg->priv->items)
ret |= MESSAGE_UPDATE_SEGMENTS;
this_->shared->messages = g_list_remove_all(this_->shared->messages, stored_msg);
- traffic_message_remove_item_data(stored_msg, NULL, this_->rt);
+ traffic_message_remove_item_data(stored_msg, NULL, this_->shared->rt);
traffic_message_destroy(stored_msg);
}
@@ -3925,11 +4540,11 @@ static int traffic_process_messages_int(struct traffic * this_, int flags) {
#endif
/* dump message store if new messages have been received */
- traffic_dump_messages_to_xml(this_);
+ traffic_dump_messages_to_xml(this_->shared);
}
/* TODO see comment on route_recalculate_partial about thread-safety */
- route_recalculate_partial(this_->rt);
+ route_recalculate_partial(this_->shared->rt);
/* trigger redraw if segments have changed */
if ((ret & MESSAGE_UPDATE_SEGMENTS) && (navit_get_ready(this_->navit) == 3))
@@ -4018,8 +4633,6 @@ static struct traffic * traffic_new(struct attr *parent, struct attr **attrs) {
this_->callback = callback_new_1(callback_cast(traffic_loop), this_);
this_->timeout = event_add_timeout(1000, 1, this_->callback); // TODO make interval configurable
- this_->map = NULL;
-
if (!this_->shared)
traffic_set_shared(this_);
@@ -4153,7 +4766,8 @@ static int traffic_xml_is_tagstack_valid(struct xml_state * state) {
|| !g_ascii_strcasecmp(el->tag_name, "to")
|| !g_ascii_strcasecmp(el->tag_name, "at")
|| !g_ascii_strcasecmp(el->tag_name, "via")
- || !g_ascii_strcasecmp(el->tag_name, "not_via"))
+ || !g_ascii_strcasecmp(el->tag_name, "not_via")
+ || !g_ascii_strcasecmp(el->tag_name, "navit_items"))
ret = (el_parent && !g_ascii_strcasecmp(el_parent->tag_name, "location"));
else if (!g_ascii_strcasecmp(el->tag_name, "supplementary_info"))
ret = (el_parent && !g_ascii_strcasecmp(el_parent->tag_name, "event"));
@@ -4212,6 +4826,7 @@ static void traffic_xml_start(xml_context *dummy, const char *tag_name, const ch
* event: Everything handled in end callback
* merge: No attributes, everything handled in children's callbacks
* from, to, at, via, not_via: Everything handled in end callback
+ * navit_items: Everything handled in end callback
*/
}
@@ -4303,6 +4918,8 @@ static void traffic_xml_end(xml_context *dummy, const char *tag_name, void *data
state->at = NULL;
state->via = NULL;
state->not_via = NULL;
+ state->location->priv->txt_data = state->location_txt_data;
+ state->location_txt_data = NULL;
} else if (!g_ascii_strcasecmp((char *) tag_name, "event")) {
count = g_list_length(state->si);
if (count) {
@@ -4342,6 +4959,8 @@ static void traffic_xml_end(xml_context *dummy, const char *tag_name, void *data
point = &state->via;
} else if (!g_ascii_strcasecmp((char *) tag_name, "not_via")) {
point = &state->not_via;
+ } else if (!g_ascii_strcasecmp((char *) tag_name, "navit_items")) {
+ state->location_txt_data = g_strdup(el->text);
}
/*
@@ -4372,6 +4991,8 @@ static void traffic_xml_end(xml_context *dummy, const char *tag_name, void *data
traffic_xml_element_destroy(el);
state->tagstack = g_list_remove(state->tagstack, state->tagstack->data);
}
+ if (!state->is_valid)
+ state->is_valid = traffic_xml_is_tagstack_valid(state);
state->is_opened = 0;
}
@@ -4917,6 +5538,8 @@ void traffic_location_destroy(struct traffic_location * this_) {
g_free(this_->road_ref);
if (this_->tmc_table)
g_free(this_->tmc_table);
+ if (this_->priv->txt_data)
+ g_free(this_->priv->txt_data);
if (this_->priv->sw)
g_free(this_->priv->sw);
if (this_->priv->ne)
@@ -5132,9 +5755,17 @@ struct item ** traffic_message_get_items(struct traffic_message * this_) {
*/
static struct map_priv * traffic_map_new(struct map_methods *meth, struct attr **attrs, struct callback_list *cbl) {
struct map_priv *ret;
+ struct attr *traffic_attr;
+
+ traffic_attr = attr_search(attrs, NULL, attr_traffic);
+ if (!traffic_attr) {
+ dbg(lvl_error, "attr_traffic not found!");
+ return NULL;
+ }
ret = g_new0(struct map_priv, 1);
*meth = traffic_map_meth;
+ ret->shared = traffic_attr->u.traffic->shared;
return ret;
}
@@ -5145,44 +5776,31 @@ void traffic_init(void) {
}
struct map * traffic_get_map(struct traffic *this_) {
- struct attr_iter *iter;
- struct attr *attr;
- struct traffic * traffic;
char * filename;
struct traffic_message ** messages;
struct traffic_message ** cur_msg;
- if (!this_->map) {
- /* see if any of the other instances has already created a map */
- attr = g_new0(struct attr, 1);
- iter = navit_attr_iter_new();
- while (navit_get_attr(this_->navit, attr_traffic, attr, iter)) {
- traffic = (struct traffic *) attr->u.navit_object;
- if (traffic->map)
- this_->map = traffic->map;
- }
- navit_attr_iter_destroy(iter);
- g_free(attr);
- }
-
- if (!this_->map) {
+ if (!this_->shared->map) {
/* no map yet, create a new one */
- struct attr *attrs[4];
- struct attr a_type,data,a_description;
+ struct attr *attrs[5];
+ struct attr a_type,data,a_description,a_traffic;
a_type.type = attr_type;
a_type.u.str = "traffic";
data.type = attr_data;
data.u.str = "";
a_description.type = attr_description;
a_description.u.str = "Traffic";
+ a_traffic.type = attr_traffic;
+ a_traffic.u.traffic = this_;
attrs[0] = &a_type;
attrs[1] = &data;
attrs[2] = &a_description;
- attrs[3] = NULL;
+ attrs[3] = &a_traffic;
+ attrs[4] = NULL;
- this_->map = map_new(NULL, attrs);
- navit_object_ref((struct navit_object *) this_->map);
+ this_->shared->map = map_new(NULL, attrs);
+ navit_object_ref((struct navit_object *) this_->shared->map);
/* populate map with previously stored messages */
filename = g_strjoin(NULL, navit_get_user_data_directory(TRUE), "/traffic.xml", NULL);
@@ -5203,7 +5821,7 @@ struct map * traffic_get_map(struct traffic *this_) {
}
}
- return this_->map;
+ return this_->shared->map;
}
/**
@@ -5270,6 +5888,24 @@ struct traffic_message ** traffic_get_stored_messages(struct traffic *this_) {
struct traffic_message ** out = ret;
GList * in = this_->shared->messages;
+ /* Iterator over active messages */
+ GList * msgiter;
+
+ /* Current message */
+ struct traffic_message * message;
+
+ /* Attributes for traffic distortions generated from the current traffic message */
+ struct seg_data * data;
+
+ /* Ensure all locations are fully resolved */
+ for (msgiter = this_->shared->messages; msgiter; msgiter = g_list_next(msgiter)) {
+ message = (struct traffic_message *) msgiter->data;
+ if (message->priv->items == NULL) {
+ data = traffic_message_parse_events(message);
+ traffic_message_add_segments(message, this_->shared->ms, data, this_->shared->map, this_->shared->rt);
+ g_free(data);
+ }
+ }
while (in) {
*out = (struct traffic_message *) in->data;
in = g_list_next(in);
@@ -5295,11 +5931,11 @@ void traffic_process_messages(struct traffic * this_, struct traffic_message **
}
void traffic_set_mapset(struct traffic *this_, struct mapset *ms) {
- this_->ms = ms;
+ this_->shared->ms = ms;
}
void traffic_set_route(struct traffic *this_, struct route *rt) {
- this_->rt = rt;
+ this_->shared->rt = rt;
}
struct object_func traffic_func = {