summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authormvglasow <michael -at- vonglasow.com>2018-09-23 21:27:17 +0300
committermvglasow <michael -at- vonglasow.com>2018-09-23 21:27:17 +0300
commitad65a4a0a29c4220599dec8db2f1c1a5e8f07469 (patch)
tree0f1dd344839f8c238b299523afab64ba46b55e08
parent1181a66b363fb6d0477b5bf81e2c15971142918d (diff)
downloadnavit-ad65a4a0a29c4220599dec8db2f1c1a5e8f07469.tar.gz
Add:traffic:Rewrite point attribute matching
Points without attributes of their own can now be matched. Analyzing all route graph points in advance is in fact more efficient than fetching each point on the route from the map individually. Signed-off-by: mvglasow <michael -at- vonglasow.com>
-rw-r--r--navit/route.c2
-rw-r--r--navit/route_protected.h2
-rw-r--r--navit/traffic.c125
3 files changed, 97 insertions, 32 deletions
diff --git a/navit/route.c b/navit/route.c
index 3b3bdd0eb..6bf773bfe 100644
--- a/navit/route.c
+++ b/navit/route.c
@@ -1225,7 +1225,7 @@ void route_remove_waypoint(struct route *this) {
* or {@code NULL} to return the first point
* @return The point at the specified coordinates or NULL if not found
*/
-static struct route_graph_point *route_graph_get_point_next(struct route_graph *this, struct coord *c,
+struct route_graph_point *route_graph_get_point_next(struct route_graph *this, struct coord *c,
struct route_graph_point *last) {
struct route_graph_point *p;
int seen=0,hashval=HASHCOORD(c);
diff --git a/navit/route_protected.h b/navit/route_protected.h
index be38749f2..1de3c7206 100644
--- a/navit/route_protected.h
+++ b/navit/route_protected.h
@@ -164,6 +164,8 @@ struct route_graph_point * route_graph_add_point(struct route_graph *this, struc
void route_graph_add_turn_restriction(struct route_graph *this, struct item *item);
void route_graph_free_points(struct route_graph *this);
struct route_graph_point *route_graph_get_point(struct route_graph *this, struct coord *c);
+struct route_graph_point *route_graph_get_point_next(struct route_graph *this, struct coord *c,
+ struct route_graph_point *last);
void route_graph_add_segment(struct route_graph *this, struct route_graph_point *start,
struct route_graph_point *end, struct route_graph_segment_data *data);
int route_graph_segment_is_duplicate(struct route_graph_point *start, struct route_graph_segment_data *data);
diff --git a/navit/traffic.c b/navit/traffic.c
index b8303eca3..56d3115a0 100644
--- a/navit/traffic.c
+++ b/navit/traffic.c
@@ -2230,6 +2230,62 @@ static struct route_graph_point * traffic_route_prepend(struct route_graph * rg,
}
/**
+ * @brief Compares a given point to the traffic location and returns a score.
+ *
+ * This method obtains all points at coordinates `c` from the map_rect used to build the route graph, compares their
+ * attributes to those supplied with the location, assigns a match score from 0 (no matching attributes) to 100 (all
+ * supplied attributes match) and returns the highest score obtained. If no matching point is found, 0 is returned.
+ *
+ * @param this_ The traffic location
+ * @param p The route graph point to examine for matches
+ * @param point The point of the traffic location to use for matching (0 = from, 1 = at, 2 = to, 16 = start, 17 = end)
+ * @param rg The route graph
+ * @param start The first point of the path
+ * @param match_start True to evaluate for the start point of a route, false for the end point
+ * @param ms The mapset to read the items from
+ *
+ * @return A score from 0 (worst) to 100 (best).
+ */
+static int traffic_location_get_point_match(struct traffic_location * this_, struct route_graph_point * p, int point,
+ struct route_graph * rg, struct route_graph_point * start, int match_start, struct mapset * ms) {
+ int ret = 0;
+
+ /* The point from the location to match */
+ struct traffic_point * trpoint = NULL;
+
+ /* The attribute matching score for the current item */
+ int score;
+
+ switch(point) {
+ case 0:
+ trpoint = this_->from;
+ break;
+ case 1:
+ trpoint = this_->at;
+ break;
+ case 2:
+ trpoint = this_->to;
+ break;
+ case 16:
+ trpoint = this_->from ? this_->from : this_->at;
+ break;
+ case 17:
+ trpoint = this_->to ? this_->to : this_->at;
+ break;
+ default:
+ break;
+ }
+
+ if (!trpoint)
+ return 0;
+
+ /* First examine route graph points and connected segments */
+ score = traffic_point_match_segment_attributes(trpoint, p, start, match_start);
+ if (ret < score)
+ ret = score;
+}
+
+/**
* @brief Returns points from the route graph which match a traffic location.
*
* This method obtains point items from the map_rect from which the route graph was built and compares
@@ -2237,6 +2293,9 @@ static struct route_graph_point * traffic_route_prepend(struct route_graph * rg,
* (no matching attributes) to 100 (all supplied attributes match), and a list of all points with a
* nonzero score is returned.
*
+ * Points which have no corresponding map item (i.e. points which have no additional attributes) are not included in
+ * the result and must be analyzed separately if needed.
+ *
* @param this_ The traffic location
* @param point The point of the traffic location to use for matching (0 = from, 1 = at, 2 = to, 16 = start, 17 = end)
* @param rg The route graph
@@ -2266,7 +2325,7 @@ static GList * traffic_location_get_matching_points(struct traffic_location * th
struct route_graph_point * p;
/* The attribute matching score for the current item */
- int score, new_score;
+ int score;
/* Data for the current point */
struct point_data * data;
@@ -2312,9 +2371,6 @@ static GList * traffic_location_get_matching_points(struct traffic_location * th
rg->sel = NULL;
continue;
}
- /* FIXME:
- * - Some route graph points do not have a corresponding point-type item on the map
- * - We are currently only interested in points on the route; examining the whole route graph is inefficient */
while ((item = map_rect_get_item(rg->mr))) {
/* exclude non-point items */
if ((item->type < type_town_label) || (item->type >= type_line))
@@ -2324,21 +2380,15 @@ static GList * traffic_location_get_matching_points(struct traffic_location * th
if (!item_coord_get(item, &c, 1))
continue;
- /* exclude items not in the route graph */
- if (!(p = route_graph_get_point(rg, &c)))
- continue;
-
- /* exclude points where turn restrictions apply */
- if (p->flags & RP_TURN_RESTRICTION)
+ /* exclude items not in the route graph (points with turn restrictions are ignored) */
+ p = route_graph_get_point(rg, &c);
+ while (p && (p->flags & RP_TURN_RESTRICTION))
+ p = route_graph_get_point_next(rg, &c, p);
+ if (!p)
continue;
/* determine score */
score = traffic_point_match_attributes(trpoint, item);
- if (score < 100) {
- new_score = traffic_point_match_segment_attributes(trpoint, p, start, match_start);
- if (new_score > score)
- score = new_score;
- }
/* exclude items with a zero score */
if (!score)
@@ -2346,11 +2396,15 @@ static GList * traffic_location_get_matching_points(struct traffic_location * th
dbg(lvl_debug, "adding item, score: %d", score);
- data = g_new0(struct point_data, 1);
- data->score = score;
- data->p = p;
+ do {
+ if (!(p->flags & RP_TURN_RESTRICTION)) {
+ data = g_new0(struct point_data, 1);
+ data->score = score;
+ data->p = p;
- ret = g_list_append(ret, data);
+ ret = g_list_append(ret, data);
+ }
+ } while ((p = route_graph_get_point_next(rg, &c, p)));
}
map_selection_destroy(rg->sel);
rg->sel = NULL;
@@ -2465,6 +2519,9 @@ static int traffic_message_add_segments(struct traffic_message * this_, struct m
/* The corresponding point data */
struct point_data * pd;
+ /* The match score of the current point */
+ int score;
+
/* Current and minimum cost to reference point */
int val, minval;
@@ -2637,19 +2694,22 @@ static int traffic_message_add_segments(struct traffic_message * this_, struct m
}
if (is_candidate) {
+ score = traffic_location_get_point_match(this_->location, p_iter,
+ this_->location->at ? 1 : (dir > 0) ? 2 : 0,
+ rg, p_start, 0, ms);
pd = NULL;
- for (points_iter = points; points_iter; points_iter = g_list_next(points_iter)) {
+ for (points_iter = points; points_iter && (score < 100); points_iter = g_list_next(points_iter)) {
pd = (struct point_data *) points_iter->data;
- if (pd->p == p_iter)
- break;
+ if ((pd->p == p_iter) && (pd->score > score))
+ score = pd->score;
}
val = transform_distance(projection_mg, &p_iter->c, (dir > 0) ? c_to : c_from);
- val += (val * (100 - (points_iter ? pd->score : 0)) * (PENALTY_POINT_MATCH) / 100);
+ val += (val * (100 - score) * (PENALTY_POINT_MATCH) / 100);
if (val < minval) {
minval = val;
p_to = p_iter;
- dbg(lvl_debug, "candidate end point found, point %p, data %p, value %d (score %d)",
- p_iter, points_iter ? pd : NULL, val, points_iter ? pd->score : 0);
+ dbg(lvl_debug, "candidate end point found, point %p, value %d (score %d)",
+ p_iter, val, score);
}
}
@@ -2725,20 +2785,23 @@ static int traffic_message_add_segments(struct traffic_message * this_, struct m
}
if (is_candidate) {
+ score = traffic_location_get_point_match(this_->location, p_iter,
+ this_->location->at ? 1 : (dir > 0) ? 0 : 2,
+ rg, p_start, 1, ms);
pd = NULL;
- for (points_iter = points; points_iter; points_iter = g_list_next(points_iter)) {
+ for (points_iter = points; points_iter && (score < 100); points_iter = g_list_next(points_iter)) {
pd = (struct point_data *) points_iter->data;
- if (pd->p == p_iter)
- break;
+ if ((pd->p == p_iter) && (pd->score > score))
+ score = pd->score;
}
val = transform_distance(projection_mg, &p_iter->c, (dir > 0) ? c_from : c_to);
/* TODO does attribute matching make sense for the start segment? */
- val += (val * (100 - (points_iter ? pd->score : 0)) * (PENALTY_POINT_MATCH) / 100);
+ val += (val * (100 - score) * (PENALTY_POINT_MATCH) / 100);
if (val < minval) {
minval = val;
p_from = p_iter;
- dbg(lvl_debug, "candidate start point found, point %p, data %p, value %d (score %d)",
- p_iter, points_iter ? pd : NULL, val, points_iter ? pd->score : 0);
+ dbg(lvl_debug, "candidate start point found, point %p, value %d (score %d)",
+ p_iter, val, score);
}
}