int dest_length;
int told;
int dest_count;
+ int flags;
struct navigation_itm *next;
struct navigation_itm *prev;
struct navigation_way *ways; /**< Pointer to all ways one could drive from here */
itm->time=time.u.num;
}
+/**
+ * @brief This check if an item is part of a roundabout
+ *
+ * @param itm The item to be checked
+ * @return True if the item is part of a roundabout
+ */
+static int
+check_roundabout(struct navigation_itm *itm, struct map *graph_map)
+{
+ struct map_selection coord_sel;
+ struct map_rect *g_rect; // Contains a map rectangle from the route graph's map
+ struct item *i,*sitem;
+ struct attr sitem_attr,flags_attr;
+
+ // These values cause the code in route.c to get us only the route graph point and connected segments
+ coord_sel.next = NULL;
+ coord_sel.u.c_rect.lu = itm->start;
+ coord_sel.u.c_rect.rl = itm->start;
+ // the selection's order is ignored
+
+ g_rect = map_rect_new(graph_map, &coord_sel);
+
+ i = map_rect_get_item(g_rect);
+ if (!i || i->type != type_rg_point) { // probably offroad?
+ return 0;
+ }
+
+ while (1) {
+ i = map_rect_get_item(g_rect);
+
+ if (!i) {
+ break;
+ }
+
+ if (i->type != type_rg_segment) {
+ continue;
+ }
+
+ if (!item_attr_get(i,attr_street_item,&sitem_attr)) {
+ continue;
+ }
+
+ sitem = sitem_attr.u.item;
+ if (item_is_equal(itm->item,*sitem)) {
+ if (item_attr_get(i,attr_flags,&flags_attr) && (flags_attr.u.num & AF_ROUNDABOUT)) {
+ map_rect_destroy(g_rect);
+ return 1;
+ }
+ }
+ }
+
+ map_rect_destroy(g_rect);
+ return 0;
+}
+
static struct navigation_itm *
navigation_itm_new(struct navigation *this_, struct item *ritem)
{
else
ret->direction=0;
- item_attr_get(ritem, attr_route, &route_attr);
- graph_map = route_get_graph_map(route_attr.u.route);
-
sitem=street_item.u.item;
ret->item=*sitem;
item_hash_insert(this_->hash, sitem, ret);
ret->start=c[0];
ret->end=c[i];
+
+ item_attr_get(ritem, attr_route, &route_attr);
+ graph_map = route_get_graph_map(route_attr.u.route);
+ if (check_roundabout(ret, graph_map)) {
+ ret->flags |= AF_ROUNDABOUT;
+ }
+
dbg(1,"i=%d start %d end %d '%s' '%s'\n", i, ret->angle_start, ret->angle_end, ret->name1, ret->name2);
map_rect_destroy(mr);
} else {
}
}
+
/**
* @brief Check if the new item is entered "straight"
*
dbg(1,"enter %p %p %p\n",old, new, delta);
*delta=angle_delta(old->angle_end, new->angle_start);
+ if ((old->flags & AF_ROUNDABOUT) && ! (new->flags & AF_ROUNDABOUT)) {
+ dbg(1, "maneuver_required: leaving roundabout: yes\n");
+ return 1;
+ } else if (!(old->flags & AF_ROUNDABOUT) && (new->flags & AF_ROUNDABOUT)) {
+ dbg(1, "maneuver_required: entering roundabout: no\n");
+ return 0;
+ } else if ((old->flags & AF_ROUNDABOUT) && (new->flags & AF_ROUNDABOUT)) {
+ dbg(1, "maneuver_required: staying in roundabout: no\n");
+ return 0;
+ }
+
if (new->item.type == old->item.type || (new->item.type != type_ramp && old->item.type != type_ramp)) {
if (is_same_street2(old, new)) {
if (! entering_straight(new, abs(*delta))) {
}
/**
+ * @brief Checks if the last segment returned from a route_graph_point_iterator comes from the end
+ *
+ * @param it The route graph point iterator to be checked
+ * @return 1 if the last segment returned comes from the end of the route graph point, 0 otherwise
+ */
+static int
+rp_iterator_end(struct route_graph_point_iterator *it) {
+ if (it->end && (it->next != it->p->end)) {
+ return 1;
+ } else {
+ return 0;
+ }
+}
+
+/**
* @brief Destroys a route_path
*
* @param this The route_path to be destroyed
}
/**
+ * @brief Checks if a segment is part of a roundabout
+ *
+ * This function checks if a segment is part of a roundabout.
+ *
+ * @param seg The segment to be checked
+ * @param level How deep to scan the route graph
+ * @param direction Set this to 1 if we're entering the segment through its end, to 0 otherwise
+ * @param origin Used internally, set to NULL
+ * @return 1 If a roundabout was detected, 0 otherwise
+ */
+static int
+route_check_roundabout(struct route_graph_segment *seg, int level, int direction, struct route_graph_segment *origin)
+{
+ struct route_graph_point_iterator it;
+ struct route_graph_segment *cur;
+
+ if (!level) {
+ return 0;
+ }
+ if (!direction && !(seg->flags & AF_ONEWAY)) {
+ return 0;
+ }
+ if (direction && !(seg->flags & AF_ONEWAYREV)) {
+ return 0;
+ }
+
+ if (!origin) {
+ origin = seg;
+ }
+
+ if (!direction) {
+ it = rp_iterator_new(seg->end);
+ } else {
+ it = rp_iterator_new(seg->start);
+ }
+
+ cur = rp_iterator_next(&it);
+ while (cur) {
+ if (cur == seg) {
+ cur = rp_iterator_next(&it);
+ continue;
+ }
+
+ if (cur == origin) {
+ seg->flags |= AF_ROUNDABOUT;
+ return 1;
+ }
+
+ if (route_check_roundabout(cur, (level-1), rp_iterator_end(&it), origin)) {
+ seg->flags |= AF_ROUNDABOUT;
+ return 1;
+ }
+
+ cur = rp_iterator_next(&it);
+ }
+
+ return 0;
+}
+
+/**
* @brief Sets the mapset of the route passwd
*
* @param this The route to set the mapset for
segment->c[i]=ca[ccnt-i-1];
}
segment->ncoords = ccnt;
+
+ /* We check if the route graph segment is part of a roundabout here, because this
+ * only matters for route graph segments which form parts of the route path */
+ if (!(rgs->flags & AF_ROUNDABOUT)) { // We identified this roundabout earlier
+ route_check_roundabout(rgs, 5, (dir < 1), NULL);
+ }
+
segment->item=rgs->item;
segment->offset = offset;
linkold:
else
return 0;
return 1;
+ case attr_flags:
+ if (mr->item.type != type_rg_segment)
+ return 0;
+ mr->attr_next = attr_none;
+ if (seg) {
+ attr->u.num = seg->flags;
+ } else {
+ return 0;
+ }
+ return 1;
case attr_direction:
// This only works if the map has been opened at a single point, and in that case indicates if the
// segment returned last is connected to this point via its start (1) or its end (-1)