FIX: windows build process: enable png build
[navit-package] / navit / route.c
index d314771..65cc9ed 100644 (file)
@@ -54,9 +54,9 @@
 #include "profile.h"
 #include "coord.h"
 #include "projection.h"
+#include "item.h"
 #include "map.h"
 #include "mapset.h"
-#include "item.h"
 #include "route.h"
 #include "track.h"
 #include "point.h"
 #include "transform.h"
 #include "plugin.h"
 #include "fib.h"
+#include "event.h"
+#include "callback.h"
+#include "vehicleprofile.h"
+#include "roadprofile.h"
 
 
 struct map_priv {
@@ -79,7 +83,6 @@ int debug_route=0;
  * but there are also points which don't do that (e.g. at the end of a dead-end).
  */
 struct route_graph_point {
-       struct route_graph_point *next;          /**< Linked-list pointer to a list of all route_graph_points */
        struct route_graph_point *hash_next; /**< Pointer to a chained hashlist of all route_graph_points with this hash */
        struct route_graph_segment *start;       /**< Pointer to a list of segments of which this point is the start. The links 
                                                                                  *  of this linked-list are in route_graph_segment->start_next.*/
@@ -91,8 +94,35 @@ struct route_graph_point {
                                                                                  *  to this point's heap-element */
        int value;                                                       /**< The cost at which one can reach the destination from this point on */
        struct coord c;                                          /**< Coordinates of this point */
+       int flags;                                              /**< Flags for this point (eg traffic distortion) */
+};
+
+#define RP_TRAFFIC_DISTORTION 1
+#define RP_TURN_RESTRICTION 2
+#define RP_TURN_RESTRICTION_RESOLVED 4
+
+/**
+ * @brief A segment in the route graph or path
+ *
+ * This is a segment in the route graph or path. A segment represents a driveable way.
+ */
+
+struct route_segment_data {
+       struct item item;                                                       /**< The item (e.g. street) that this segment represents. */
+       int flags;
+       int len;                                                                        /**< Length of this segment */
+       /*NOTE: After a segment, various fields may follow, depending on what flags are set. Order of fields:
+                               1.) maxspeed                    Maximum allowed speed on this segment. Present if AF_SPEED_LIMIT is set.
+                               2.) offset                              If the item is segmented (i.e. represented by more than one segment), this
+                                                                               indicates the position of this segment in the item. Present if AF_SEGMENTED is set.
+        */
 };
 
+#define RSD_OFFSET(x) *((int *)route_segment_data_field_pos((x), attr_offset))
+#define RSD_MAXSPEED(x) *((int *)route_segment_data_field_pos((x), attr_maxspeed))
+
+
+
 /**
  * @brief A segment in the route graph
  *
@@ -106,13 +136,17 @@ struct route_graph_segment {
                                                                                                 *  same point. Start of this list is in route_graph_point->end. */
        struct route_graph_point *start;                        /**< Pointer to the point this segment starts at. */
        struct route_graph_point *end;                          /**< Pointer to the point this segment ends at. */
-       struct item item;                                                       /**< The item (e.g. street) that this segment represents. */
-       int flags;
-       int len;                                                                        /**< Length of this segment */
-       int offset;                                                                     /**< If the item represented by this segment is "segmented" (i.e. 
-                                                                                                *  is represented by several segments instead of just one), this 
-                                                                                                *  indicates the position of this segment in the item - for items
-                                                                                                *  that are not segmented this should always be 1 */
+       struct route_segment_data data;                         /**< The segment data */
+};
+
+/**
+ * @brief A traffic distortion
+ *
+ * This is distortion in the traffic where you can't drive as fast as usual or have to wait for some time
+ */
+struct route_traffic_distortion {
+       int maxspeed;                                   /**< Maximum speed possible in km/h */
+       int delay;                                      /**< Delay in tenths of seconds */
 };
 
 /**
@@ -122,14 +156,11 @@ struct route_graph_segment {
  */
 struct route_path_segment {
        struct route_path_segment *next;        /**< Pointer to the next segment in the path */
-       struct item item;                                       /**< The item (e.g. street) this segment represents */
-       int length;                                                     /**< Length of the segment */
-       int offset;                                                     /**< Same as in route_graph_segment->offset */
+       struct route_segment_data *data;        /**< The segment data */
        int direction;                                          /**< Order in which the coordinates are ordered. >0 means "First
                                                                                 *  coordinate of the segment is the first coordinate of the item", <=0 
                                                                                 *  means reverse. */
        unsigned ncoords;                                       /**< How many coordinates does this segment have? */
-       struct attr **attrs;                            /**< Attributes of this route path segment */
        struct coord c[0];                                      /**< Pointer to the ncoords coordinates of this segment */
        /* WARNING: There will be coordinates following here, so do not create new fields after c! */
 };
@@ -146,8 +177,10 @@ struct route_info {
        int lenpos;                      /**< Distance between lp and the end of the street */
        int lenneg;                      /**< Distance between lp and the start of the street */
        int lenextra;                    /**< Distance between lp and c */
-
+       int percent;                     /**< ratio of lenneg to lenght of whole street in percent */
        struct street_data *street; /**< The street lp is on */
+       int street_direction;   /**< Direction of vehicle on street -1 = Negative direction, 1 = Positive direction, 0 = Unknown */
+       int dir;                /**< Direction to take when following the route -1 = Negative direction, 1 = Positive direction */
 };
 
 /**
@@ -156,6 +189,9 @@ struct route_info {
  * This structure describes a whole routing path
  */
 struct route_path {
+       int in_use;                                             /**< The path is in use and can not be updated */
+       int update_required;                                    /**< The path needs to be updated after it is no longer in use */
+       int updated;                                            /**< The path has only been updated */
        struct route_path_segment *path;                        /**< The first segment in the path, i.e. the segment one should 
                                                                                                 *  drive in next */
        struct route_path_segment *path_last;           /**< The last segment in the path */
@@ -163,20 +199,12 @@ struct route_path {
        struct item_hash *path_hash;                            /**< A hashtable of all the items represented by this route's segements */
 };
 
-#define RF_FASTEST     (1<<0)
-#define RF_SHORTEST    (1<<1)
-#define RF_AVOIDHW     (1<<2)
-#define RF_AVOIDPAID   (1<<3)
-#define RF_LOCKONROAD  (1<<4)
-#define RF_SHOWGRAPH   (1<<5)
-
 /**
  * @brief A complete route
  * 
  * This struct holds all information about a route.
  */
 struct route {
-       int version;                            /**< Counts how many times this route got updated */
        struct mapset *ms;                      /**< The mapset this route is built upon */
        unsigned flags;
        struct route_info *pos;         /**< Current position within this route */
@@ -184,10 +212,14 @@ struct route {
 
        struct route_graph *graph;      /**< Pointer to the route graph */
        struct route_path *path2;       /**< Pointer to the route path */
-       struct map *map;                        
+       struct map *map;
        struct map *graph_map;
+       struct callback * route_graph_done_cb ; /**< Callback when route graph is done */
+       struct callback * route_graph_flood_done_cb ; /**< Callback when route graph flooding is done */
+       struct callback_list *cbl2;     /**< Callback list to call when route changes */
        int destination_distance;       /**< Distance to the destination at which the destination is considered "reached" */
-       int speedlist[route_item_last-route_item_first+1];      /**< The speedlist for this route */
+       struct vehicleprofile *vehicleprofile; /**< Routing preferences */
+       int route_status;               /**< Route Status */
 };
 
 /**
@@ -196,7 +228,15 @@ struct route {
  * This structure describes a whole routing graph
  */
 struct route_graph {
-       struct route_graph_point *route_points;         /**< Pointer to the first route_graph_point in the linked list of  all points */
+       int busy;                                       /**< The graph is being built */
+       struct map_selection *sel;                      /**< The rectangle selection for the graph */
+       struct mapset_handle *h;                        /**< Handle to the mapset */    
+       struct map *m;                                  /**< Pointer to the currently active map */     
+       struct map_rect *mr;                            /**< Pointer to the currently active map rectangle */
+       struct vehicleprofile *vehicleprofile;          /**< The vehicle profile */
+       struct callback *idle_cb;                       /**< Idle callback to process the graph */
+       struct callback *done_cb;                       /**< Callback when graph is done */
+       struct event_idle *idle_ev;                     /**< The pointer to the idle event */
        struct route_graph_segment *route_segments; /**< Pointer to the first route_graph_segment in the linked list of all segments */
 #define HASH_SIZE 8192
        struct route_graph_point *hash[HASH_SIZE];      /**< A hashtable containing all route_graph_points in this graph */
@@ -204,13 +244,26 @@ struct route_graph {
 
 #define HASHCOORD(c) ((((c)->x +(c)->y) * 2654435761UL) & (HASH_SIZE-1))
 
-static struct route_info * route_find_nearest_street(struct mapset *ms, struct pcoord *c);
+/**
+ * @brief Iterator to iterate through all route graph segments in a route graph point
+ *
+ * This structure can be used to iterate through all route graph segments connected to a
+ * route graph point. Use this with the rp_iterator_* functions.
+ */
+struct route_graph_point_iterator {
+       struct route_graph_point *p;            /**< The route graph point whose segments should be iterated */
+       int end;                                                        /**< Indicates if we have finished iterating through the "start" segments */
+       struct route_graph_segment *next;       /**< The next segment to be returned */
+};
+
+static struct route_info * route_find_nearest_street(struct vehicleprofile *vehicleprofile, struct mapset *ms, struct pcoord *c);
 static struct route_graph_point *route_graph_get_point(struct route_graph *this, struct coord *c);
-static void route_graph_update(struct route *this);
-static struct route_path *route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, int *speedlist);
+static void route_graph_update(struct route *this, struct callback *cb, int async);
+static void route_graph_build_done(struct route_graph *rg, int cancel);
+static struct route_path *route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, struct vehicleprofile *profile);
 static void route_process_street_graph(struct route_graph *this, struct item *item);
 static void route_graph_destroy(struct route_graph *this);
-static void route_path_update(struct route *this);
+static void route_path_update(struct route *this, int cancel, int async);
 
 /**
  * @brief Returns the projection used for this route
@@ -221,11 +274,86 @@ static void route_path_update(struct route *this);
 static enum projection route_projection(struct route *route)
 {
        struct street_data *street;
+       if (!route->pos && !route->dst)
+               return projection_none;
        street = route->pos ? route->pos->street : route->dst->street;
+       if (!street || !street->item.map)
+               return projection_none;
        return map_projection(street->item.map);
 }
 
 /**
+ * @brief Creates a new graph point iterator 
+ *
+ * This function creates a new route graph point iterator, that can be used to
+ * iterate through all segments connected to the point.
+ *
+ * @param p The route graph point to create the iterator from
+ * @return A new iterator.
+ */
+static struct route_graph_point_iterator
+rp_iterator_new(struct route_graph_point *p)
+{
+       struct route_graph_point_iterator it;
+
+       it.p = p;
+       if (p->start) {
+               it.next = p->start;
+               it.end = 0;
+       } else {
+               it.next = p->end;
+               it.end = 1;
+       }
+
+       return it;
+}
+
+/**
+ * @brief Gets the next segment connected to a route graph point from an iterator
+ *
+ * @param it The route graph point iterator to get the segment from
+ * @return The next segment or NULL if there are no more segments
+ */
+static struct route_graph_segment
+*rp_iterator_next(struct route_graph_point_iterator *it) 
+{
+       struct route_graph_segment *ret;
+
+       ret = it->next;
+       if (!ret) {
+               return NULL;
+       }
+
+       if (!it->end) {
+               if (ret->start_next) {
+                       it->next = ret->start_next;
+               } else {
+                       it->next = it->p->end;
+                       it->end = 1;
+               }
+       } else {
+               it->next = ret->end_next;
+       }
+
+       return ret;
+}
+
+/**
+ * @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
@@ -243,9 +371,6 @@ route_path_destroy(struct route_path *this)
        c=this->path;
        while (c) {
                n=c->next;
-               if (c->attrs) { 
-                       attr_list_free(c->attrs);
-               }
                g_free(c);
                c=n;
        }
@@ -259,26 +384,97 @@ route_path_destroy(struct route_path *this)
  * @return The newly created route
  */
 struct route *
-route_new(struct attr **attrs)
+route_new(struct attr *parent, struct attr **attrs)
 {
        struct route *this=g_new0(struct route, 1);
        struct attr dest_attr;
 
-       if (!this) {
-               printf("%s:Out of memory\n", __FUNCTION__);
-               return NULL;
-       }
-
        if (attr_generic_get_attr(attrs, NULL, attr_destination_distance, &dest_attr, NULL)) {
                this->destination_distance = dest_attr.u.num;
        } else {
                this->destination_distance = 50; // Default value
        }
+       this->cbl2=callback_list_new();
 
        return this;
 }
 
 /**
+ * @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,it2;
+       struct route_graph_segment *cur;
+       int count=0;
+
+       if (!level) {
+               return 0;
+       }
+       if (!direction && !(seg->data.flags & AF_ONEWAY)) {
+               return 0;
+       }
+       if (direction && !(seg->data.flags & AF_ONEWAYREV)) {
+               return 0;
+       }
+       if (seg->data.flags & AF_ROUNDABOUT_VALID)
+               return 0;
+       
+       if (!origin) {
+               origin = seg;
+       }
+
+       if (!direction) {
+               it = rp_iterator_new(seg->end);
+       } else {
+               it = rp_iterator_new(seg->start);
+       }
+       it2=it;
+       
+       while ((cur = rp_iterator_next(&it2)))
+               count++;
+
+       if (count > 3)
+               return 0;
+       cur = rp_iterator_next(&it);
+       while (cur) {
+               if (cur == seg) {
+                       cur = rp_iterator_next(&it);
+                       continue;
+               }
+
+               if (cur->data.item.type != origin->data.item.type) {
+                       // This street is of another type, can't be part of the roundabout
+                       cur = rp_iterator_next(&it);
+                       continue;
+               }
+
+               if (cur == origin) {
+                       seg->data.flags |= AF_ROUNDABOUT;
+                       return 1;
+               }
+
+               if (route_check_roundabout(cur, (level-1), rp_iterator_end(&it), origin)) {
+                       seg->data.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
@@ -291,6 +487,22 @@ route_set_mapset(struct route *this, struct mapset *ms)
 }
 
 /**
+ * @brief Sets the vehicle profile of a route
+ *
+ * @param this The route to set the profile for
+ * @param prof The vehicle profile
+ */
+
+void
+route_set_profile(struct route *this, struct vehicleprofile *prof)
+{
+       if (this->vehicleprofile != prof) {
+               this->vehicleprofile=prof;
+               route_path_update(this, 1, 1);
+       }
+}
+
+/**
  * @brief Returns the mapset of the route passed
  *
  * @param this The route to get the mapset of
@@ -327,18 +539,6 @@ route_get_dst(struct route *this)
 }
 
 /**
- * @brief Returns the speedlist of the route passed
- *
- * @param this The route to get the speedlist for
- * @return The speedlist of the route passed
- */
-int *
-route_get_speedlist(struct route *this)
-{
-       return this->speedlist;
-}
-
-/**
  * @brief Checks if the path is calculated for the route passed
  *
  * @param this The route to check
@@ -351,25 +551,6 @@ route_get_path_set(struct route *this)
 }
 
 /**
- * @brief Sets the driving speed for a certain itemtype
- *
- * @param this The route to set the speed for
- * @param type The itemtype to set the speed for
- * @param value The speed that should be set
- * @return True on success, false if the itemtype does not exist
- */
-int
-route_set_speed(struct route *this, enum item_type type, int value)
-{
-       if (type < route_item_first || type > route_item_last) {
-               dbg(0,"street type %d out of range [%d,%d]", type, route_item_first, route_item_last);
-               return 0;
-       }
-       this->speedlist[type-route_item_first]=value;
-       return 1;
-}
-
-/**
  * @brief Checks if the route passed contains a certain item within the route path
  *
  * This function checks if a certain items exists in the path that navit will guide
@@ -385,22 +566,12 @@ route_contains(struct route *this, struct item *item)
 {
        if (! this->path2 || !this->path2->path_hash)
                return 0;
-       return  (int)item_hash_lookup(this->path2->path_hash, item);
-}
-
-/**
- * @brief Checks if the current position in a route is a certain item
- *
- * @param this The route to check for this item
- * @param item The item to search for
- * @return True if the current position is this item, false otherwise
- */
-int
-route_pos_contains(struct route *this, struct item *item)
-{
-       if (! this->pos)
+       if (item_hash_lookup(this->path2->path_hash, item))
+               return 1;
+       if (! this->pos || !this->pos->street)
                return 0;
        return item_is_equal(this->pos->street->item, *item);
+
 }
 
 /**
@@ -413,6 +584,7 @@ int
 route_destination_reached(struct route *this)
 {
        struct street_data *sd = NULL;
+       enum projection pro;
 
        if (!this->pos)
                return 0;
@@ -433,14 +605,42 @@ route_destination_reached(struct route *this)
        if ((sd->flags & AF_ONEWAYREV) && (this->pos->lenpos >= this->dst->lenpos)) {
                return 0;
        }
+       pro=route_projection(this);
+       if (pro == projection_none)
+               return 0;
         
-       if (transform_distance(route_projection(this), &this->pos->c, &this->dst->lp) > this->destination_distance) {
+       if (transform_distance(pro, &this->pos->c, &this->dst->lp) > this->destination_distance) {
                return 0;
        }
        
        return 1;
 }
 
+static void
+route_path_update_done(struct route *this, int new_graph)
+{
+       struct route_path *oldpath=this->path2;
+       struct attr route_status;
+       route_status.type=attr_route_status;
+       if (this->path2 && this->path2->in_use) {
+               this->path2->update_required=1+new_graph;
+               return;
+       }
+       route_status.u.num=route_status_building_path;
+       route_set_attr(this, &route_status);
+
+       this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->vehicleprofile);
+       route_path_destroy(oldpath);
+       if (this->path2) {
+               if (!new_graph && this->path2->updated)
+                       route_status.u.num=route_status_path_done_incremental;
+               else
+                       route_status.u.num=route_status_path_done_new;
+       } else
+               route_status.u.num=route_status_not_found;
+       route_set_attr(this, &route_status);
+}
+
 /**
  * @brief Updates the route graph and the route path if something changed with the route
  *
@@ -453,31 +653,38 @@ route_destination_reached(struct route *this)
  * @param this The route to update
  */
 static void
-route_path_update(struct route *this)
+route_path_update(struct route *this, int cancel, int async)
 {
-       struct route_path *oldpath = NULL;
+       dbg(1,"enter %d\n", cancel);
        if (! this->pos || ! this->dst) {
+               dbg(1,"destroy\n");
                route_path_destroy(this->path2);
                this->path2 = NULL;
                return;
        }
+       if (cancel) {
+               route_graph_destroy(this->graph);
+               this->graph=NULL;
+       }
        /* the graph is destroyed when setting the destination */
-       if (this->graph && this->pos && this->dst && this->path2) {
+       if (this->graph) {
+               if (this->graph->busy) {
+                       dbg(1,"busy building graph\n");
+                       return;
+               }
                // we can try to update
-               oldpath = this->path2;
+               dbg(1,"try update\n");
+               route_path_update_done(this, 0);
+       } else {
+               route_path_destroy(this->path2);
                this->path2 = NULL;
        }
-       if (! this->graph || !(this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->speedlist))) {
-               profile(0,NULL);
-               route_graph_update(this);
-               this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->speedlist);
-               profile(1,"route_path_new");
-               profile(0,"end");
-       }
-
-       if (oldpath) {
-               /* Destroy what's left */
-               route_path_destroy(oldpath);
+       if (!this->graph || !this->path2) {
+               dbg(1,"rebuild graph\n");
+               if (! this->route_graph_flood_done_cb)
+                       this->route_graph_flood_done_cb=callback_new_2(callback_cast(route_path_update_done), this, (long)1);
+               dbg(1,"route_graph_update\n");
+               route_graph_update(this, this->route_graph_flood_done_cb, async);
        }
 }
 
@@ -496,6 +703,10 @@ route_info_distances(struct route_info *ri, enum projection pro)
        ri->lenextra=transform_distance(pro, &ri->lp, &ri->c);
        ri->lenneg=transform_polyline_length(pro, sd->c, npos)+transform_distance(pro, &sd->c[ri->pos], &ri->lp);
        ri->lenpos=transform_polyline_length(pro, sd->c+npos, sd->count-npos)+transform_distance(pro, &sd->c[npos], &ri->lp);
+       if (ri->lenneg || ri->lenpos)
+               ri->percent=(ri->lenneg*100)/(ri->lenneg+ri->lenpos);
+       else
+               ri->percent=50;
 }
 
 /**
@@ -513,13 +724,15 @@ route_set_position(struct route *this, struct pcoord *pos)
        if (this->pos)
                route_info_free(this->pos);
        this->pos=NULL;
-       this->pos=route_find_nearest_street(this->ms, pos);
+       this->pos=route_find_nearest_street(this->vehicleprofile, this->ms, pos);
+
+       // If there is no nearest street, bail out.
+       if (!this->pos) return;
+
+       this->pos->street_direction=0;
        dbg(1,"this->pos=%p\n", this->pos);
-       if (! this->pos)
-               return;
        route_info_distances(this->pos, pos->pro);
-       if (this->dst) 
-               route_path_update(this);
+       route_path_update(this, 0, 1);
 }
 
 /**
@@ -529,10 +742,11 @@ route_set_position(struct route *this, struct pcoord *pos)
  * @param tracking The tracking to get the coordinates from
  */
 void
-route_set_position_from_tracking(struct route *this, struct tracking *tracking)
+route_set_position_from_tracking(struct route *this, struct tracking *tracking, enum projection pro)
 {
        struct coord *c;
        struct route_info *ret;
+       struct street_data *sd;
 
        dbg(2,"enter\n");
        c=tracking_get_pos(tracking);
@@ -547,13 +761,17 @@ route_set_position_from_tracking(struct route *this, struct tracking *tracking)
        ret->c=*c;
        ret->lp=*c;
        ret->pos=tracking_get_segment_pos(tracking);
-       ret->street=street_data_dup(tracking_get_street_data(tracking));
-       route_info_distances(ret, projection_mg);
+       ret->street_direction=tracking_get_street_direction(tracking);
+       sd=tracking_get_street_data(tracking);
+       if (sd) {
+               ret->street=street_data_dup(sd);
+               route_info_distances(ret, pro);
+       }
        dbg(3,"c->x=0x%x, c->y=0x%x pos=%d item=(0x%x,0x%x)\n", c->x, c->y, ret->pos, ret->street->item.id_hi, ret->street->item.id_lo);
        dbg(3,"street 0=(0x%x,0x%x) %d=(0x%x,0x%x)\n", ret->street->c[0].x, ret->street->c[0].y, ret->street->count-1, ret->street->c[ret->street->count-1].x, ret->street->c[ret->street->count-1].y);
        this->pos=ret;
        if (this->dst) 
-               route_path_update(this);
+               route_path_update(this, 0, 1);
        dbg(2,"ret\n");
 }
 
@@ -572,9 +790,9 @@ route_rect(int order, struct coord *c1, struct coord *c2, int rel, int abs)
                printf("%s:Out of memory\n", __FUNCTION__);
                return sel;
        }
-       sel->order[layer_town]=0;
-       sel->order[layer_poly]=0;
-       sel->order[layer_street]=order;
+       sel->order=order;
+       sel->range.min=route_item_first;
+       sel->range.max=route_item_last;
        dbg(1,"%p %p\n", c1, c2);
        dx=c1->x-c2->x;
        dy=c1->y-c2->y;
@@ -598,7 +816,7 @@ route_rect(int order, struct coord *c1, struct coord *c2, int rel, int abs)
                d=dx*sx;
        else
                d=dy*sy;
-       m=d*rel/100+abs;        
+       m=d*rel/100+abs;
        sel->u.c_rect.lu.x-=m;
        sel->u.c_rect.rl.x+=m;
        sel->u.c_rect.lu.y+=m;
@@ -661,23 +879,28 @@ route_free_selection(struct map_selection *sel)
  * @param dst Coordinates to set as destination
  */
 void
-route_set_destination(struct route *this, struct pcoord *dst)
+route_set_destination(struct route *this, struct pcoord *dst, int async)
 {
        profile(0,NULL);
        if (this->dst)
                route_info_free(this->dst);
        this->dst=NULL;
        if (dst) {
-               this->dst=route_find_nearest_street(this->ms, dst);
+               this->dst=route_find_nearest_street(this->vehicleprofile, this->ms, dst);
                if(this->dst)
-               route_info_distances(this->dst, dst->pro);
+                       route_info_distances(this->dst, dst->pro);
+       } else  {
+               struct attr route_status;
+               route_status.type=attr_route_status;
+               route_status.u.num=route_status_no_destination;
+               route_set_attr(this, &route_status);
        }
        profile(1,"find_nearest_street");
 
        /* The graph has to be destroyed and set to NULL, otherwise route_path_update() doesn't work */
        route_graph_destroy(this->graph);
        this->graph=NULL;
-       route_path_update(this);
+       route_path_update(this, 1, async);
        profile(0,"end");
 }
 
@@ -686,22 +909,81 @@ route_set_destination(struct route *this, struct pcoord *dst)
  *
  * @param this The route in which to search
  * @param c Coordinates to search for
+ * @param last The last route graph point returned to iterate over multiple points with the same coordinates
  * @return The point at the specified coordinates or NULL if not found
  */
 static struct route_graph_point *
-route_graph_get_point(struct route_graph *this, struct coord *c)
+route_graph_get_point_next(struct route_graph *this, struct coord *c, struct route_graph_point *last)
 {
        struct route_graph_point *p;
-       int hashval=HASHCOORD(c);
+       int seen=0,hashval=HASHCOORD(c);
        p=this->hash[hashval];
        while (p) {
-               if (p->c.x == c->x && p->c.y == c->y) 
-                       return p;
+               if (p->c.x == c->x && p->c.y == c->y) {
+                       if (!last || seen)
+                               return p;
+                       if (p == last)
+                               seen=1;
+               }
                p=p->hash_next;
        }
        return NULL;
 }
 
+static struct route_graph_point *
+route_graph_get_point(struct route_graph *this, struct coord *c)
+{
+       return route_graph_get_point_next(this, c, NULL);
+}
+
+/**
+ * @brief Gets the last route_graph_point with the specified coordinates 
+ *
+ * @param this The route in which to search
+ * @param c Coordinates to search for
+ * @return The point at the specified coordinates or NULL if not found
+ */
+static struct route_graph_point *
+route_graph_get_point_last(struct route_graph *this, struct coord *c)
+{
+       struct route_graph_point *p,*ret=NULL;
+       int hashval=HASHCOORD(c);
+       p=this->hash[hashval];
+       while (p) {
+               if (p->c.x == c->x && p->c.y == c->y)
+                       ret=p;
+               p=p->hash_next;
+       }
+       return ret;
+}
+
+
+
+/**
+ * @brief Create a new point for the route graph with the specified coordinates
+ *
+ * @param this The route to insert the point into
+ * @param f The coordinates at which the point should be created
+ * @return The point created
+ */
+
+static struct route_graph_point *
+route_graph_point_new(struct route_graph *this, struct coord *f)
+{
+       int hashval;
+       struct route_graph_point *p;
+
+       hashval=HASHCOORD(f);
+       if (debug_route)
+               printf("p (0x%x,0x%x)\n", f->x, f->y);
+       p=g_new0(struct route_graph_point,1);
+       p->hash_next=this->hash[hashval];
+       this->hash[hashval]=p;
+       p->value=INT_MAX;
+       p->c=*f;
+       return p;
+}
+
 /**
  * @brief Inserts a point into the route graph at the specified coordinates
  *
@@ -715,30 +997,11 @@ route_graph_get_point(struct route_graph *this, struct coord *c)
 static struct route_graph_point *
 route_graph_add_point(struct route_graph *this, struct coord *f)
 {
-       int hashval;
        struct route_graph_point *p;
 
        p=route_graph_get_point(this,f);
-       if (!p) {
-               hashval=HASHCOORD(f);
-               if (debug_route)
-                       printf("p (0x%x,0x%x)\n", f->x, f->y);
-               p=g_new(struct route_graph_point,1);
-               if (!p) {
-                       printf("%s:Out of memory\n", __FUNCTION__);
-                       return p;
-               }
-               p->hash_next=this->hash[hashval];
-               this->hash[hashval]=p;
-               p->next=this->route_points;
-               p->el=NULL;
-               p->start=NULL;
-               p->end=NULL;
-               p->seg=NULL;
-               p->value=INT_MAX;
-               p->c=*f;
-               this->route_points=p;
-       }
+       if (!p)
+               p=route_graph_point_new(this,f);
        return p;
 }
 
@@ -751,48 +1014,110 @@ static void
 route_graph_free_points(struct route_graph *this)
 {
        struct route_graph_point *curr,*next;
-       curr=this->route_points;
-       while (curr) {
-               next=curr->next;
-               g_free(curr);
-               curr=next;
+       int i;
+       for (i = 0 ; i < HASH_SIZE ; i++) {
+               curr=this->hash[i];
+               while (curr) {
+                       next=curr->hash_next;
+                       g_free(curr);
+                       curr=next;
+               }
+               this->hash[i]=NULL;
        }
-       this->route_points=NULL;
-       memset(this->hash, 0, sizeof(this->hash));
 }
 
 /**
- * @brief Inserts a new segment into the route graph
+ * @brief Returns the position of a certain field appended to a route graph segment
  *
- * This function performs a check if a segment for the item specified already exists, and inserts
- * a new segment representing this item if it does not.
+ * This function returns a pointer to a field that is appended to a route graph
+ * segment.
  *
- * @param this The route graph to insert the segment into
- * @param start The graph point which should be connected to the start of this segment
- * @param end The graph point which should be connected to the end of this segment
- * @param len The length of this segment
- * @param item The item that is represented by this segment
- * @param flags Flags for this segment
- * @param offset If the item passed in "item" is segmented (i.e. divided into several segments), this indicates the position of this segment within the item
+ * @param seg The route graph segment the field is appended to
+ * @param type Type of the field that should be returned
+ * @return A pointer to a field of a certain type, or NULL if no such field is present
  */
-static void
-route_graph_add_segment(struct route_graph *this, struct route_graph_point *start,
-                       struct route_graph_point *end, int len, struct item *item,
-                       int flags, int offset)
+static void *
+route_segment_data_field_pos(struct route_segment_data *seg, enum attr_type type)
+{
+       unsigned char *ptr;
+       
+       ptr = ((unsigned char*)seg) + sizeof(struct route_segment_data);
+
+       if (seg->flags & AF_SPEED_LIMIT) {
+               if (type == attr_maxspeed) 
+                       return (void*)ptr;
+               ptr += sizeof(int);
+       }
+       if (seg->flags & AF_SEGMENTED) {
+               if (type == attr_offset) 
+                       return (void*)ptr;
+               ptr += sizeof(int);
+       }
+       return NULL;
+}
+
+/**
+ * @brief Calculates the size of a route_segment_data struct with given flags
+ *
+ * @param flags The flags of the route_segment_data
+ */
+
+static int
+route_segment_data_size(int flags)
+{
+       int ret=sizeof(struct route_segment_data);
+       if (flags & AF_SPEED_LIMIT)
+               ret+=sizeof(int);
+       if (flags & AF_SEGMENTED)
+               ret+=sizeof(int);
+       return ret;
+}
+
+
+static int
+route_graph_segment_is_duplicate(struct route_graph_point *start, struct item *item, int flags, int offset)
 {
        struct route_graph_segment *s;
-/*     
-       FIXME: commented out becouse
-       it is possible to have one item with two different
-       offsets as segments 
        s=start->start;
        while (s) {
-               if (item_is_equal(*item, s->item)) 
-                       return;
-               s=s->start_next;
+               if (item_is_equal(*item, s->data.item)) {
+                       if (flags & AF_SEGMENTED) {
+                               if (RSD_OFFSET(&s->data) == offset) {
+                                       return 1;
+                               }
+                       } else
+                               return 1;
+               }
+               s=s->start_next;
        } 
-*/
-       s = g_new0(struct route_graph_segment, 1);
+       return 0;
+}
+
+/**
+ * @brief Inserts a new segment into the route graph
+ *
+ * This function performs a check if a segment for the item specified already exists, and inserts
+ * a new segment representing this item if it does not.
+ *
+ * @param this The route graph to insert the segment into
+ * @param start The graph point which should be connected to the start of this segment
+ * @param end The graph point which should be connected to the end of this segment
+ * @param len The length of this segment
+ * @param item The item that is represented by this segment
+ * @param flags Flags for this segment
+ * @param offset If the item passed in "item" is segmented (i.e. divided into several segments), this indicates the position of this segment within the item
+ * @param maxspeed The maximum speed allowed on this segment in km/h. -1 if not known.
+ */
+static void
+route_graph_add_segment(struct route_graph *this, struct route_graph_point *start,
+                       struct route_graph_point *end, int len, struct item *item,
+                       int flags, int offset, int maxspeed)
+{
+       struct route_graph_segment *s;
+       int size;
+
+       size = sizeof(struct route_graph_segment)-sizeof(struct route_segment_data)+route_segment_data_size(flags);
+       s = g_malloc0(size);
        if (!s) {
                printf("%s:Out of memory\n", __FUNCTION__);
                return;
@@ -804,10 +1129,15 @@ route_graph_add_segment(struct route_graph *this, struct route_graph_point *star
        s->end_next=end->end;
        end->end=s;
        dbg_assert(len >= 0);
-       s->len=len;
-       s->item=*item;
-       s->flags=flags;
-       s->offset = offset;
+       s->data.len=len;
+       s->data.item=*item;
+       s->data.flags=flags;
+
+       if (flags & AF_SPEED_LIMIT) 
+               RSD_MAXSPEED(&s->data)=maxspeed;
+       if (flags & AF_SEGMENTED) 
+               RSD_OFFSET(&s->data)=offset;
+
        s->next=this->route_segments;
        this->route_segments=s;
        if (debug_route)
@@ -822,7 +1152,7 @@ route_graph_add_segment(struct route_graph *this, struct route_graph_point *star
  * returned to all the coordinates of the item between the two coordinates
  * start end end.
  *
- * @important Make shure that whatever c points to has enough memory allocated
+ * @important Make sure that whatever c points to has enough memory allocated
  * @important to hold max coordinates!
  *
  * @param i The item to get the coordinates of
@@ -830,6 +1160,7 @@ route_graph_add_segment(struct route_graph *this, struct route_graph_point *star
  * @param max Maximum number of coordinates to return
  * @param start First coordinate to get
  * @param end Last coordinate to get
+ * @return The number of coordinates returned
  */
 static int get_item_seg_coords(struct item *i, struct coord *c, int max,
                struct coord *start, struct coord *end)
@@ -870,16 +1201,23 @@ static struct route_path_segment *
 route_extract_segment_from_path(struct route_path *path, struct item *item,
                                                 int offset)
 {
+       int soffset;
        struct route_path_segment *sp = NULL, *s;
        s = path->path;
        while (s) {
-               if (s->offset == offset && item_is_equal(s->item,*item)) {
-                       if (sp) {
-                               sp->next = s->next;
-                               break;
-                       } else {
-                               path->path = s->next;
-                               break;
+               if (item_is_equal(s->data->item,*item)) {
+                       if (s->data->flags & AF_SEGMENTED)
+                               soffset=RSD_OFFSET(s->data);
+                       else
+                               soffset=1;
+                       if (soffset == offset) {
+                               if (sp) {
+                                       sp->next = s->next;
+                                       break;
+                               } else {
+                                       path->path = s->next;
+                                       break;
+                               }
                        }
                }
                sp = s;
@@ -907,50 +1245,39 @@ route_path_add_segment(struct route_path *this, struct route_path_segment *segme
 }
 
 /**
- * @brief Adds a new item to a path
+ * @brief Adds a two coordinate line to a path
  *
- * This adds a new item to a path, creating a new segment for it. Please note that this function does not check
- * if the item passed is segmented - it will create exactly one segment.
+ * This adds a new line to a path, creating a new segment for it.
  *
  * @param this The path to add the item to
- * @param item The item to add
+ * @param start coordinate to add to the start of the item. If none should be added, make this NULL.
+ * @param end coordinate to add to the end of the item. If none should be added, make this NULL.
  * @param len The length of the item
- * @param first (Optional) coordinate to add to the start of the item. If none should be added, make this NULL.
- * @param c Pointer to count coordinates of the item.
- * @param cound Number of coordinates in c
- * @param last (Optional) coordinate to add to the end of the item. If none should be added, make this NULL.
- * @param dir Direction to add the coordinates in. Greater than zero means "start with the first coordinate in c", all other values mean "start with the last coordinate in c"
  */
 static void
-route_path_add_item(struct route_path *this, struct item *item, int len, struct coord *first, struct coord *c, int count, struct coord *last, int dir)
+route_path_add_line(struct route_path *this, struct coord *start, struct coord *end, int len)
 {
-       int i,idx=0,ccount=count + (first ? 1:0) + (last ? 1:0);
+       int ccnt=2;
        struct route_path_segment *segment;
-       
-       segment=g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccount);
-       segment->ncoords=ccount;
-       segment->direction=dir;
-       if (first)
-               segment->c[idx++]=*first;
-       if (dir > 0) {
-               for (i = 0 ; i < count ; i++)
-                       segment->c[idx++]=c[i];
-       } else {
-               for (i = 0 ; i < count ; i++)
-                       segment->c[idx++]=c[count-i-1];
-       }
-       if (last)
-               segment->c[idx++]=*last;
-       segment->length=len;
-       if (item)
-               segment->item=*item;
+       int seg_size,seg_dat_size;
+
+       dbg(1,"line from 0x%x,0x%x-0x%x,0x%x\n", start->x, start->y, end->x, end->y);
+       seg_size=sizeof(*segment) + sizeof(struct coord) * ccnt;
+        seg_dat_size=sizeof(struct route_segment_data);
+        segment=g_malloc0(seg_size + seg_dat_size);
+        segment->data=(struct route_segment_data *)((char *)segment+seg_size);
+       segment->ncoords=ccnt;
+       segment->direction=0;
+       segment->c[0]=*start;
+       segment->c[1]=*end;
+       segment->data->len=len;
        route_path_add_segment(this, segment);
 }
 
 /**
  * @brief Inserts a new item into the path
  * 
- * This function does almost the same as "route_apth_add_item()", but identifies
+ * This function does almost the same as "route_path_add_item()", but identifies
  * the item to add by a segment from the route graph. Another difference is that it "copies" the
  * segment from the route graph, i.e. if the item is segmented, only the segment passed in rgs will
  * be added to the route path, not all segments of the item. 
@@ -962,59 +1289,121 @@ route_path_add_item(struct route_path *this, struct item *item, int len, struct
  * @param this The path to add the item to
  * @param oldpath Old path containing the segment to be added. Speeds up the function, but can be NULL.
  * @param rgs Segment of the route graph that should be "copied" to the route path
- * @param len Length of the item to be added
- * @param offset Offset of rgs within the item it represents
  * @param dir Order in which to add the coordinates. See route_path_add_item()
- * @param straight Indicates if this segment is being entered "straight". See route_check_straight().
+ * @param pos  Information about start point if this is the first segment
+ * @param dst  Information about end point if this is the last segment
  */
-static void
-route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpath,
-                                  struct route_graph_segment *rgs, int len, int offset, int dir, int straight)
+
+static int
+route_path_add_item_from_graph(struct route_path *this, struct route_path *oldpath, struct route_graph_segment *rgs, int dir, struct route_info *pos, struct route_info *dst)
 {
        struct route_path_segment *segment;
-       int i,ccnt = 0;
-       struct coord ca[2048];
-       struct attr straight_attr;
-
+       int i, ccnt, extra=0, ret=0;
+       struct coord *c,*cd,ca[2048];
+       int offset=1;
+       int seg_size,seg_dat_size;
+       int len=rgs->data.len;
+       if (rgs->data.flags & AF_SEGMENTED) 
+               offset=RSD_OFFSET(&rgs->data);
+
+       dbg(1,"enter (0x%x,0x%x) dir=%d pos=%p dst=%p\n", rgs->data.item.id_hi, rgs->data.item.id_lo, dir, pos, dst);
        if (oldpath) {
-               ccnt = (int)item_hash_lookup(oldpath->path_hash, &rgs->item);
-               if (ccnt) {
-                       segment = route_extract_segment_from_path(oldpath,
-                                                        &rgs->item, offset);
-                       
-                       if (segment)
-                               goto linkold;
+               segment=item_hash_lookup(oldpath->path_hash, &rgs->data.item);
+               if (segment && segment->direction == dir) {
+                       segment = route_extract_segment_from_path(oldpath, &rgs->data.item, offset);
+                       if (segment) {
+                               ret=1;
+                               if (!pos)
+                                       goto linkold;
+                       }
                }
        }
 
-       ccnt = get_item_seg_coords(&rgs->item, ca, 2047, &rgs->start->c, &rgs->end->c);
-       segment= g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccnt);
-       if (!segment) {
-               printf("%s:Out of memory\n", __FUNCTION__);
-               return;
+       if (pos) {
+               if (dst) {
+                       extra=2;
+                       if (dst->lenneg >= pos->lenneg) {
+                               dir=1;
+                               ccnt=dst->pos-pos->pos;
+                               c=pos->street->c+pos->pos+1;
+                               len=dst->lenneg-pos->lenneg;
+                       } else {
+                               dir=-1;
+                               ccnt=pos->pos-dst->pos;
+                               c=pos->street->c+dst->pos+1;
+                               len=pos->lenneg-dst->lenneg;
+                       }
+               } else {
+                       extra=1;
+                       dbg(1,"pos dir=%d\n", dir);
+                       dbg(1,"pos pos=%d\n", pos->pos);
+                       dbg(1,"pos count=%d\n", pos->street->count);
+                       if (dir > 0) {
+                               c=pos->street->c+pos->pos+1;
+                               ccnt=pos->street->count-pos->pos-1;
+                               len=pos->lenpos;
+                       } else {
+                               c=pos->street->c;
+                               ccnt=pos->pos+1;
+                               len=pos->lenneg;
+                       }
+               }
+               pos->dir=dir;
+       } else  if (dst) {
+               extra=1;
+               dbg(1,"dst dir=%d\n", dir);
+               dbg(1,"dst pos=%d\n", dst->pos);
+               if (dir > 0) {
+                       c=dst->street->c;
+                       ccnt=dst->pos+1;
+                       len=dst->lenpos;
+               } else {
+                       c=dst->street->c+dst->pos+1;
+                       ccnt=dst->street->count-dst->pos-1;
+                       len=dst->lenneg;
+               }
+       } else {
+               ccnt=get_item_seg_coords(&rgs->data.item, ca, 2047, &rgs->start->c, &rgs->end->c);
+               c=ca;
        }
+       seg_size=sizeof(*segment) + sizeof(struct coord) * (ccnt + extra);
+       seg_dat_size=route_segment_data_size(rgs->data.flags);
+       segment=g_malloc0(seg_size + seg_dat_size);
+       segment->data=(struct route_segment_data *)((char *)segment+seg_size);
        segment->direction=dir;
-       if (dir > 0) {
-               for (i = 0 ; i < ccnt ; i++)
-                       segment->c[i]=ca[i];
-       } else {
-               for (i = 0 ; i < ccnt ; i++)
-                       segment->c[i]=ca[ccnt-i-1];
+       cd=segment->c;
+       if (pos && (c[0].x != pos->lp.x || c[0].y != pos->lp.y))
+               *cd++=pos->lp;
+       if (dir < 0)
+               c+=ccnt-1;
+       for (i = 0 ; i < ccnt ; i++) {
+               *cd++=*c;
+               c+=dir; 
+       }
+       segment->ncoords+=ccnt;
+       if (dst && (cd[-1].x != dst->lp.x || cd[-1].y != dst->lp.y)) 
+               *cd++=dst->lp;
+       segment->ncoords=cd-segment->c;
+       if (segment->ncoords <= 1) {
+               g_free(segment);
+               return 1;
        }
-       segment->ncoords = ccnt;
-       segment->item=rgs->item;
-       segment->offset = offset;
-linkold:
-       segment->length=len;
-       segment->next=NULL;
-       item_hash_insert(this->path_hash,  &rgs->item, (void *)ccnt);
 
-       straight_attr.type = attr_route_follow_straight;
-       straight_attr.u.num = straight;
+       /* 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->data.flags & AF_ROUNDABOUT)) { // We identified this roundabout earlier
+               route_check_roundabout(rgs, 13, (dir < 1), NULL);
+       }
 
-       segment->attrs = attr_generic_set_attr(segment->attrs, &straight_attr);
+       memcpy(segment->data, &rgs->data, seg_dat_size);
+linkold:
+       segment->data->len=len;
+       segment->next=NULL;
+       item_hash_insert(this->path_hash,  &rgs->data.item, segment);
 
        route_path_add_segment(this, segment);
+
+       return ret;
 }
 
 /**
@@ -1044,6 +1433,7 @@ static void
 route_graph_destroy(struct route_graph *this)
 {
        if (this) {
+               route_graph_build_done(this, 1);
                route_graph_free_points(this);
                route_graph_free_segments(this);
                g_free(this);
@@ -1053,44 +1443,168 @@ route_graph_destroy(struct route_graph *this)
 /**
  * @brief Returns the time needed to drive len on item
  *
- * @param speedlist The speedlist that should be used
- * @param item The item to be driven on
- * @param len The length to drive
- * @return The time needed to drive len on item
+ * This function returns the time needed to drive len meters on 
+ * the item passed in item in tenth of seconds.
+ *
+ * @param profile The routing preferences
+ * @param over The segment which is passed
+ * @return The time needed to drive len on item in thenth of senconds
  */
-int
-route_time(int *speedlist, struct item *item, int len)
-{
-       if (item->type < route_item_first || item->type > route_item_last) {
-               dbg(0,"street type %d out of range [%d,%d]\n", item->type, route_item_first, route_item_last);
-               return len*36;
+
+static int
+route_time_seg(struct vehicleprofile *profile, struct route_segment_data *over, struct route_traffic_distortion *dist)
+{
+       struct roadprofile *roadprofile=vehicleprofile_get_roadprofile(profile, over->item.type);
+       int speed,maxspeed;
+       if (!roadprofile || !roadprofile->route_weight)
+               return INT_MAX;
+       /* maxspeed_handling: 0=always, 1 only if maxspeed restricts the speed, 2 never */
+       speed=roadprofile->route_weight;
+       if (profile->maxspeed_handling != 2) {
+               if (over->flags & AF_SPEED_LIMIT) {
+                       maxspeed=RSD_MAXSPEED(over);
+                       if (!profile->maxspeed_handling)
+                               speed=maxspeed;
+               } else
+                       maxspeed=INT_MAX;
+               if (dist && maxspeed > dist->maxspeed)
+                       maxspeed=dist->maxspeed;
+               if (maxspeed != INT_MAX && (profile->maxspeed_handling != 1 || maxspeed < speed))
+                       speed=maxspeed;
        }
-       if (!speedlist[item->type-route_item_first]) {
-               dbg(0,"street type %d speed is zero\n", item->type);
-               return len*36;
+       if (!speed)
+               return INT_MAX;
+       return over->len*36/speed+(dist ? dist->delay : 0);
+}
+
+static int
+route_get_traffic_distortion(struct route_graph_segment *seg, struct route_traffic_distortion *ret)
+{
+       struct route_graph_point *start=seg->start;
+       struct route_graph_point *end=seg->end;
+       struct route_graph_segment *tmp,*found=NULL;
+       tmp=start->start;
+       while (tmp && !found) {
+               if (tmp->data.item.type == type_traffic_distortion && tmp->start == start && tmp->end == end)
+                       found=tmp;
+               tmp=tmp->start_next;
+       }
+       tmp=start->end;
+       while (tmp && !found) {
+               if (tmp->data.item.type == type_traffic_distortion && tmp->end == start && tmp->start == end) 
+                       found=tmp;
+               tmp=tmp->end_next;
+       }
+       if (found) {
+               ret->delay=found->data.len;
+               if (found->data.flags & AF_SPEED_LIMIT)
+                       ret->maxspeed=RSD_MAXSPEED(&found->data);
+               else
+                       ret->maxspeed=INT_MAX;
+               return 1;
        }
-       return len*36/speedlist[item->type-route_item_first];
+       return 0;
 }
 
 /**
- * @brief Returns the "costs" of driving len on item
+ * @brief Returns the "costs" of driving from point from over segment over in direction dir
  *
- * @param speedlist The speedlist that should be used
- * @param item The item to be driven on
- * @param len The length to drive
+ * @param profile The routing preferences
+ * @param from The point where we are starting
+ * @param over The segment we are using
+ * @param dir The direction of segment which we are driving
  * @return The "costs" needed to drive len on item
  */  
+
 static int
-route_value(int *speedlist, struct item *item, int len)
+route_value_seg(struct vehicleprofile *profile, struct route_graph_point *from, struct route_graph_segment *over, int dir)
 {
-       int ret;
-       if (len < 0) {
-               printf("len=%d\n", len);
+#if 0
+       dbg(0,"flags 0x%x mask 0x%x flags 0x%x\n", over->flags, dir >= 0 ? profile->flags_forward_mask : profile->flags_reverse_mask, profile->flags);
+#endif
+       if ((over->data.flags & (dir >= 0 ? profile->flags_forward_mask : profile->flags_reverse_mask)) != profile->flags)
+               return INT_MAX;
+       if (dir > 0 && (over->start->flags & RP_TURN_RESTRICTION))
+               return INT_MAX;
+       if (dir < 0 && (over->end->flags & RP_TURN_RESTRICTION))
+               return INT_MAX;
+       if (from && from->seg == over)
+               return INT_MAX;
+       if ((over->start->flags & RP_TRAFFIC_DISTORTION) && (over->end->flags & RP_TRAFFIC_DISTORTION)) {
+               struct route_traffic_distortion dist;
+               if (route_get_traffic_distortion(over, &dist))
+                       return route_time_seg(profile, &over->data, &dist);
+       }
+       return route_time_seg(profile, &over->data, NULL);
+}
+
+/**
+ * @brief Adds a route distortion item to the route graph
+ *
+ * @param this The route graph to add to
+ * @param item The item to add
+ */
+static void
+route_process_traffic_distortion(struct route_graph *this, struct item *item)
+{
+       struct route_graph_point *s_pnt,*e_pnt;
+       struct coord c,l;
+       struct attr delay_attr, maxspeed_attr;
+       int len=0;
+       int flags = 0;
+       int offset = 1;
+       int maxspeed = INT_MAX;
+
+       if (item_coord_get(item, &l, 1)) {
+               s_pnt=route_graph_add_point(this,&l);
+               while (item_coord_get(item, &c, 1)) {
+                       l=c;
+               }
+               e_pnt=route_graph_add_point(this,&l);
+               s_pnt->flags |= RP_TRAFFIC_DISTORTION;
+               e_pnt->flags |= RP_TRAFFIC_DISTORTION;
+               if (item_attr_get(item, attr_maxspeed, &maxspeed_attr)) {
+                       flags |= AF_SPEED_LIMIT;
+                       maxspeed=maxspeed_attr.u.num;
+               }
+               if (item_attr_get(item, attr_delay, &delay_attr))
+                       len=delay_attr.u.num;
+               route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset, maxspeed);
        }
-       dbg_assert(len >= 0);
-       ret=route_time(speedlist, item, len);
-       dbg(1, "route_value(0x%x, %d)=%d\n", item->type, len, ret);
-       return ret;
+}
+
+/**
+ * @brief Adds a route distortion item to the route graph
+ *
+ * @param this The route graph to add to
+ * @param item The item to add
+ */
+static void
+route_process_turn_restriction(struct route_graph *this, struct item *item)
+{
+       struct route_graph_point *pnt[4];
+       struct coord c[5];
+       int i,count;
+
+       count=item_coord_get(item, c, 5);
+       if (count != 3 && count != 4) {
+               dbg(0,"wrong count %d\n",count);
+               return;
+       }
+       if (count == 4)
+               return;
+       for (i = 0 ; i < count ; i++) 
+               pnt[i]=route_graph_add_point(this,&c[i]);
+       dbg(1,"%s: (0x%x,0x%x)-(0x%x,0x%x)-(0x%x,0x%x) %p-%p-%p\n",item_to_name(item->type),c[0].x,c[0].y,c[1].x,c[1].y,c[2].x,c[2].y,pnt[0],pnt[1],pnt[2]);
+       route_graph_add_segment(this, pnt[0], pnt[1], 0, item, 0, 0, 0);
+       route_graph_add_segment(this, pnt[1], pnt[2], 0, item, 0, 0, 0);
+       if (count == 4) {
+               pnt[1]->flags |= RP_TURN_RESTRICTION;
+               pnt[2]->flags |= RP_TURN_RESTRICTION;
+               route_graph_add_segment(this, pnt[2], pnt[3], 0, item, 0, 0, 0);
+       } else 
+               pnt[1]->flags |= RP_TURN_RESTRICTION;
+       
 }
 
 /**
@@ -1112,17 +1626,30 @@ route_process_street_graph(struct route_graph *this, struct item *item)
 #endif
        struct route_graph_point *s_pnt,*e_pnt;
        struct coord c,l;
-       struct attr attr;
+       struct attr flags_attr, maxspeed_attr;
        int flags = 0;
        int segmented = 0;
        int offset = 1;
+       int maxspeed = -1;
 
        if (item_coord_get(item, &l, 1)) {
-               if (item_attr_get(item, attr_flags, &attr)) {
-                       flags = attr.u.num;
+               int *default_flags=item_get_default_flags(item->type);
+               if (! default_flags)
+                       return;
+               if (item_attr_get(item, attr_flags, &flags_attr)) {
+                       flags = flags_attr.u.num;
                        if (flags & AF_SEGMENTED)
                                segmented = 1;
+               } else
+                       flags = *default_flags;
+               
+
+               if (flags & AF_SPEED_LIMIT) {
+                       if (item_attr_get(item, attr_maxspeed, &maxspeed_attr)) {
+                               maxspeed = maxspeed_attr.u.num;
+                       }
                }
+
                s_pnt=route_graph_add_point(this,&l);
                if (!segmented) {
                        while (item_coord_get(item, &c, 1)) {
@@ -1131,7 +1658,8 @@ route_process_street_graph(struct route_graph *this, struct item *item)
                        }
                        e_pnt=route_graph_add_point(this,&l);
                        dbg_assert(len >= 0);
-                       route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
+                       if (!route_graph_segment_is_duplicate(s_pnt, item, flags, offset))
+                               route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset, maxspeed);
                } else {
                        int isseg,rc;
                        int sc = 0;
@@ -1143,7 +1671,8 @@ route_process_street_graph(struct route_graph *this, struct item *item)
                                        l=c;
                                        if (isseg) {
                                                e_pnt=route_graph_add_point(this,&l);
-                                               route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
+                                               if (!route_graph_segment_is_duplicate(s_pnt, item, flags, offset))
+                                                       route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset, maxspeed);
                                                offset++;
                                                s_pnt=route_graph_add_point(this,&l);
                                                len = 0;
@@ -1153,30 +1682,32 @@ route_process_street_graph(struct route_graph *this, struct item *item)
                        e_pnt=route_graph_add_point(this,&l);
                        dbg_assert(len >= 0);
                        sc++;
-                       route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset);
+                       if (!route_graph_segment_is_duplicate(s_pnt, item, flags, offset))
+                               route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset, maxspeed);
                }
        }
 }
 
-/**
- * @brief Compares the costs of reaching the destination from two points on
- * 
- * @important Do not pass anything other than route_graph_points in v1 and v2!
- *
- * @param v1 Point1 
- * @param v2 Point2
- * @return The additional costs of v1 compared to v2 (may be negative)
- */
-static int
-compare(void *v1, void *v2)
+static struct route_graph_segment *
+route_graph_get_segment(struct route_graph *graph, struct street_data *sd, struct route_graph_segment *last)
 {
-       struct route_graph_point *p1=v1;
-       struct route_graph_point *p2=v2;
-#if 0
-       if (debug_route)
-               printf("compare %d (%p) vs %d (%p)\n", p1->value,p1,p2->value,p2);
-#endif
-       return p1->value-p2->value;
+       struct route_graph_point *start=NULL;
+       struct route_graph_segment *s;
+       int seen=0;
+
+       while ((start=route_graph_get_point_next(graph, &sd->c[0], start))) {
+               s=start->start;
+               while (s) {
+                       if (item_is_equal(sd->item, s->data.item)) {
+                               if (!last || seen)
+                                       return s;
+                               if (last == s)
+                                       seen=1;
+                       }
+                       s=s->start_next;
+               }
+       }
+       return NULL;
 }
 
 /**
@@ -1191,32 +1722,31 @@ compare(void *v1, void *v2)
  * at this algorithm.
  */
 static void
-route_graph_flood(struct route_graph *this, struct route_info *dst, int *speedlist)
+route_graph_flood(struct route_graph *this, struct route_info *dst, struct vehicleprofile *profile, struct callback *cb)
 {
-       struct route_graph_point *p_min,*end=NULL;
-       struct route_graph_segment *s;
+       struct route_graph_point *p_min;
+       struct route_graph_segment *s=NULL;
        int min,new,old,val;
        struct fibheap *heap; /* This heap will hold all points with "temporarily" calculated costs */
-       struct street_data *sd=dst->street;
 
-       heap = fh_makeheap();   
-       fh_setcmp(heap, compare);
+       heap = fh_makekeyheap();   
 
-       if (! (sd->flags & AF_ONEWAYREV)) { /* If we may drive in the direction of the coordinates of the item, the first coordinate is one starting point */
-               end=route_graph_get_point(this, &sd->c[0]);
-               dbg_assert(end != 0);
-               end->value=route_value(speedlist, &sd->item, dst->lenneg);
-               end->el=fh_insert(heap, end);
-       }
-
-       if (! (sd->flags & AF_ONEWAY)) { /* If we may drive against the direction of the coordinates, the last coordinate is another starting point */
-               end=route_graph_get_point(this, &sd->c[sd->count-1]);
-               dbg_assert(end != 0);
-               end->value=route_value(speedlist, &sd->item, dst->lenpos);
-               end->el=fh_insert(heap, end);
+       while ((s=route_graph_get_segment(this, dst->street, s))) {
+               val=route_value_seg(profile, NULL, s, -1);
+               if (val != INT_MAX) {
+                       val=val*(100-dst->percent)/100;
+                       s->end->seg=s;
+                       s->end->value=val;
+                       s->end->el=fh_insertkey(heap, s->end->value, s->end);
+               }
+               val=route_value_seg(profile, NULL, s, 1);
+               if (val != INT_MAX) {
+                       val=val*dst->percent/100;
+                       s->start->seg=s;
+                       s->start->value=val;
+                       s->start->el=fh_insertkey(heap, s->start->value, s->start);
+               }
        }
-
-       dbg(1,"0x%x,0x%x\n", end->c.x, end->c.y);
        for (;;) {
                p_min=fh_extractmin(heap); /* Starting Dijkstra by selecting the point with the minimum costs on the heap */
                if (! p_min) /* There are no more points with temporarily calculated costs, Dijkstra has finished */
@@ -1227,62 +1757,65 @@ route_graph_flood(struct route_graph *this, struct route_info *dst, int *speedli
                p_min->el=NULL; /* This point is permanently calculated now, we've taken it out of the heap */
                s=p_min->start;
                while (s) { /* Iterating all the segments leading away from our point to update the points at their ends */
-                       val=route_value(speedlist, &s->item, s->len);
-#if 0
-                       val+=val*2*street_route_contained(s->str->segid);
-#endif
-                       new=min+val;
-                       if (debug_route)
-                               printf("begin %d len %d vs %d (0x%x,0x%x)\n",new,val,s->end->value, s->end->c.x, s->end->c.y);
-                       if (new < s->end->value && !(s->flags & AF_ONEWAY)) { /* We've found a less costly way to reach the end of s, update it */
-                               s->end->value=new;
-                               s->end->seg=s;
-                               if (! s->end->el) {
-                                       if (debug_route)
-                                               printf("insert_end p=%p el=%p val=%d ", s->end, s->end->el, s->end->value);
-                                       s->end->el=fh_insert(heap, s->end);
-                                       if (debug_route)
-                                               printf("el new=%p\n", s->end->el);
-                               }
-                               else {
-                                       if (debug_route)
-                                               printf("replace_end p=%p el=%p val=%d\n", s->end, s->end->el, s->end->value);
-                                       fh_replacedata(heap, s->end->el, s->end);
+                       val=route_value_seg(profile, p_min, s, -1);
+                       if (val != INT_MAX) {
+                               new=min+val;
+                               if (debug_route)
+                                       printf("begin %d len %d vs %d (0x%x,0x%x)\n",new,val,s->end->value, s->end->c.x, s->end->c.y);
+                               if (new < s->end->value) { /* We've found a less costly way to reach the end of s, update it */
+                                       s->end->value=new;
+                                       s->end->seg=s;
+                                       if (! s->end->el) {
+                                               if (debug_route)
+                                                       printf("insert_end p=%p el=%p val=%d ", s->end, s->end->el, s->end->value);
+                                               s->end->el=fh_insertkey(heap, new, s->end);
+                                               if (debug_route)
+                                                       printf("el new=%p\n", s->end->el);
+                                       }
+                                       else {
+                                               if (debug_route)
+                                                       printf("replace_end p=%p el=%p val=%d\n", s->end, s->end->el, s->end->value);
+                                               fh_replacekey(heap, s->end->el, new);
+                                       }
                                }
+                               if (debug_route)
+                                       printf("\n");
                        }
-                       if (debug_route)
-                               printf("\n");
                        s=s->start_next;
                }
                s=p_min->end;
                while (s) { /* Doing the same as above with the segments leading towards our point */
-                       val=route_value(speedlist, &s->item, s->len);
-                       new=min+val;
-                       if (debug_route)
-                               printf("end %d len %d vs %d (0x%x,0x%x)\n",new,val,s->start->value,s->start->c.x, s->start->c.y);
-                       if (new < s->start->value && !(s->flags & AF_ONEWAYREV)) {
-                               old=s->start->value;
-                               s->start->value=new;
-                               s->start->seg=s;
-                               if (! s->start->el) {
-                                       if (debug_route)
-                                               printf("insert_start p=%p el=%p val=%d ", s->start, s->start->el, s->start->value);
-                                       s->start->el=fh_insert(heap, s->start);
-                                       if (debug_route)
-                                               printf("el new=%p\n", s->start->el);
-                               }
-                               else {
-                                       if (debug_route)
-                                               printf("replace_start p=%p el=%p val=%d\n", s->start, s->start->el, s->start->value);
-                                       fh_replacedata(heap, s->start->el, s->start);
+                       val=route_value_seg(profile, p_min, s, 1);
+                       if (val != INT_MAX) {
+                               new=min+val;
+                               if (debug_route)
+                                       printf("end %d len %d vs %d (0x%x,0x%x)\n",new,val,s->start->value,s->start->c.x, s->start->c.y);
+                               if (new < s->start->value) {
+                                       old=s->start->value;
+                                       s->start->value=new;
+                                       s->start->seg=s;
+                                       if (! s->start->el) {
+                                               if (debug_route)
+                                                       printf("insert_start p=%p el=%p val=%d ", s->start, s->start->el, s->start->value);
+                                               s->start->el=fh_insertkey(heap, new, s->start);
+                                               if (debug_route)
+                                                       printf("el new=%p\n", s->start->el);
+                                       }
+                                       else {
+                                               if (debug_route)
+                                                       printf("replace_start p=%p el=%p val=%d\n", s->start, s->start->el, s->start->value);
+                                               fh_replacekey(heap, s->start->el, new);
+                                       }
                                }
+                               if (debug_route)
+                                       printf("\n");
                        }
-                       if (debug_route)
-                               printf("\n");
                        s=s->end_next;
                }
        }
        fh_deleteheap(heap);
+       callback_call_0(cb);
+       dbg(1,"return\n");
 }
 
 /**
@@ -1298,291 +1831,372 @@ route_graph_flood(struct route_graph *this, struct route_info *dst, int *speedli
  * @return The new path
  */
 static struct route_path *
-route_path_new_offroad(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
+route_path_new_offroad(struct route_graph *this, struct route_info *pos, struct route_info *dst)
 {
        struct route_path *ret;
 
        ret=g_new0(struct route_path, 1);
        ret->path_hash=item_hash_new();
-       route_path_add_item(ret, NULL, pos->lenextra+dst->lenextra, &pos->c, NULL, 0, &dst->c, 1);
+       route_path_add_line(ret, &pos->c, &dst->c, pos->lenextra+dst->lenextra);
+       ret->updated=1;
 
        return ret;
 }
 
 /**
- * @brief Creates a new "trivial" route
- * 
- * This function creates a new "trivial" route. A trivial route is a route that starts and ends on the same street,
- * so there is no routing needed. Depending on pos and dst it can optionally add some "offroad" part to the route.
+ * @brief Returns a coordinate at a given distance
  *
- * @param this The route graph to place the route on
- * @param pos The starting position for the new path
- * @param dst The destination of the new path
- * @param dir Direction of the coordinates to be added
- * @return The new path
+ * This function returns the coordinate, where the user will be if he
+ * follows the current route for a certain distance.
+ *
+ * @param this_ The route we're driving upon
+ * @param dist The distance in meters
+ * @return The coordinate where the user will be in that distance
  */
-static struct route_path *
-route_path_new_trivial(struct route_graph *this, struct route_info *pos, struct route_info *dst, int dir)
+struct coord 
+route_get_coord_dist(struct route *this_, int dist)
 {
-       struct street_data *sd=pos->street;
-       struct route_path *ret;
+       int d,l,i,len;
+       int dx,dy;
+       double frac;
+       struct route_path_segment *cur;
+       struct coord ret;
+       enum projection pro=route_projection(this_);
 
-       if (dir > 0) {
-               if (pos->lenextra + dst->lenextra + pos->lenneg-dst->lenneg > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
-                       return route_path_new_offroad(this, pos, dst, dir);
-       } else {
-               if (pos->lenextra + dst->lenextra + pos->lenpos-dst->lenpos > transform_distance(map_projection(sd->item.map), &pos->c, &dst->c))
-                       return route_path_new_offroad(this, pos, dst, dir);
+       d = dist;
+
+       if (!this_->path2 || pro == projection_none) {
+               return this_->pos->c;
+       }
+       
+       ret = this_->pos->c;
+       cur = this_->path2->path;
+       while (cur) {
+               if (cur->data->len < d) {
+                       d -= cur->data->len;
+               } else {
+                       for (i=0; i < (cur->ncoords-1); i++) {
+                               l = d;
+                               len = (int)transform_polyline_length(pro, (cur->c + i), 2);
+                               d -= len;
+                               if (d <= 0) { 
+                                       // We interpolate a bit here...
+                                       frac = (double)l / len;
+                                       
+                                       dx = (cur->c + i + 1)->x - (cur->c + i)->x;
+                                       dy = (cur->c + i + 1)->y - (cur->c + i)->y;
+                                       
+                                       ret.x = (cur->c + i)->x + (frac * dx);
+                                       ret.y = (cur->c + i)->y + (frac * dy);
+                                       return ret;
+                               }
+                       }
+                       return cur->c[(cur->ncoords-1)];
+               }
+               cur = cur->next;
        }
-       ret=g_new0(struct route_path, 1);
-       ret->path_hash=item_hash_new();
-       if (pos->lenextra) 
-               route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
-       if (dir > 0)
-               route_path_add_item(ret, &sd->item, pos->lenneg-dst->lenneg, &pos->lp, sd->c+pos->pos+1, dst->pos+pos->pos, &dst->lp, 1);
-       else
-               route_path_add_item(ret, &sd->item, pos->lenpos-dst->lenpos, &pos->lp, sd->c+dst->pos+1, pos->pos-dst->pos, &dst->lp, -1);
-       if (dst->lenextra) 
-               route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
-       return ret;
-}
 
-/**
- * @brief Calculates of two coordinates' connection
- *
- * This function calculates the angle between coordinates, with north = 0
- * and east = 90.
- *
- * %FIXME This is a duplicate of road_angle() in navigation.c - combine them?
- *
- * @param c1 Coordinate 1
- * @param c2 Coordinate 2
- * @param dir Set to true if c1 is the prior, and c2 the later coordinate.
- * @return The angle of the coordinate's connection  
- */
-static int
-route_road_angle(struct coord *c1, struct coord *c2, int dir)
-{
-       int ret=transform_get_angle_delta(c1, c2, dir);
-       dbg(1, "road_angle(0x%x,0x%x - 0x%x,0x%x)=%d\n", c1->x, c1->y, c2->x, c2->y, ret);
-       return ret;
+       return this_->dst->c;
 }
 
 /**
- * @brief Checks if entering one segment from another is a "straight" road
- *
- * This checks if one can enter seg_to from seg_from by driving "straight" - i.e. 
- * if seg_to is the segment you can drive to from seg_from by steering less than
- * all to all other segments.
- *
- * This function returns true on failure, so we don't create maneuvers on every error.
+ * @brief Creates a new route path
+ * 
+ * This creates a new non-trivial route. It therefore needs the routing information created by route_graph_flood, so
+ * make sure to run route_graph_flood() after changing the destination before using this function.
  *
- * @param seg_from Segment we are driving from
- * @param seg_to Segment we are driving to
- * @return True if driving from seg_from to seg_to is "straight", false otherwise
+ * @param this The route graph to create the route from
+ * @param oldpath (Optional) old path which may contain parts of the new part - this speeds things up a bit. May be NULL.
+ * @param pos The starting position of the route
+ * @param dst The destination of the route
+ * @param preferences The routing preferences
+ * @return The new route path
  */
-static int
-route_check_straight(struct route_graph_segment *seg_from, struct route_graph_segment *seg_to)
-{
-       struct route_graph_segment *curr;
-       struct route_graph_point *conn;
-       int from_angle, to_angle, curr_angle, angle_diff; 
-       int ccnt;
-       struct coord ca[2048];
-
-       if ((seg_from->end == seg_to->start) || (seg_from->end == seg_to->end)) {
-               ccnt = get_item_seg_coords(&seg_from->item, ca, 2047, &seg_from->start->c, &seg_from->end->c);
-               from_angle = route_road_angle(&ca[ccnt-2], &ca[ccnt-1],1);
-
-               conn = seg_from->end;
-       } else if ((seg_from->start == seg_to->start) || (seg_from->start == seg_to->end)) {
-               ccnt = get_item_seg_coords(&seg_from->item, ca, 2, &seg_from->start->c, &seg_from->end->c);
-               from_angle = route_road_angle(&ca[1], &ca[0],1);
-
-               conn = seg_from->start;
-       } else {
-               // Not connected!
-               return 1;
-       }
+static struct route_path *
+route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, struct vehicleprofile *profile)
+{
+       struct route_graph_segment *first,*s=NULL;
+       struct route_graph_point *start;
+       struct route_info *posinfo, *dstinfo;
+       int segs=0;
+       int val1=INT_MAX,val2=INT_MAX;
+       int val;
+       struct route_path *ret;
 
+       if (! pos->street || ! dst->street)
+               return NULL;
 
-       if (seg_to->end == conn) {
-               ccnt = get_item_seg_coords(&seg_to->item, ca, 2047, &seg_to->start->c, &seg_to->end->c);
-               to_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2],1);
-       } else {
-               ccnt = get_item_seg_coords(&seg_to->item, ca, 2, &seg_to->start->c, &seg_to->end->c);
-               to_angle = route_road_angle(&ca[0], &ca[1],1);
-       }                       
-       
+       if (profile->mode == 2 || (profile->mode == 0 && pos->lenextra + dst->lenextra > transform_distance(map_projection(pos->street->item.map), &pos->c, &dst->c)))
+               return route_path_new_offroad(this, pos, dst);
        
-       angle_diff = from_angle - to_angle;
-       if (angle_diff < 0) {
-               angle_diff *= -1;
+       s=route_graph_get_segment(this, pos->street, NULL);
+       if (!s) {
+               dbg(0,"no segment for position found\n");
+               return NULL;
        }
-
-
-       curr = conn->start;
-       while (curr != NULL) {
-               if (curr==seg_to) {
-                       curr = curr->start_next;
-                       continue;
-               }
-               
-               ccnt = get_item_seg_coords(&curr->item, ca, 2, &curr->start->c, &curr->end->c);
-               curr_angle = route_road_angle(&ca[0], &ca[1], 1);
-
-               curr_angle = from_angle - curr_angle;
-
-               if (curr_angle < 0) {
-                       curr_angle *= -1;
-               }
-               
-
-               if (curr_angle < angle_diff) {
-                       return 0;
+       val=route_value_seg(profile, NULL, s, 1);
+       if (val != INT_MAX && s->end->value != INT_MAX) {
+               val=val*(100-pos->percent)/100;
+               val1=s->end->value+val;
+       }
+       val=route_value_seg(profile, NULL, s, -1);
+       if (val != INT_MAX && s->start->value != INT_MAX) {
+               val=val*pos->percent/100;
+               val2=s->start->value+val;
+       }
+       if (val1 == INT_MAX && val2 == INT_MAX) {
+               dbg(0,"no route found, pos blocked\n");
+               return NULL;
+       }
+       if (val1 == val2) {
+               val1=s->end->value;
+               val2=s->start->value;
+       }
+       if (val1 < val2) 
+               start=s->start;
+       else 
+               start=s->end;
+       ret=g_new0(struct route_path, 1);
+       ret->updated=1;
+       if (pos->lenextra) 
+               route_path_add_line(ret, &pos->c, &pos->lp, pos->lenextra);
+       ret->path_hash=item_hash_new();
+       dstinfo=NULL;
+       posinfo=pos;
+       first=s;
+       while (s && !dstinfo) { /* following start->seg, which indicates the least costly way to reach our destination */
+               segs++;
+#if 0
+               printf("start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
+#endif
+               if (s->start == start) {                
+                       if (item_is_equal(s->data.item, dst->street->item) && (s->end->seg == s || !posinfo))
+                               dstinfo=dst;
+                       if (!route_path_add_item_from_graph(ret, oldpath, s, 1, posinfo, dstinfo))
+                               ret->updated=0;
+                       start=s->end;
+               } else {
+                       if (item_is_equal(s->data.item, dst->street->item) && (s->start->seg == s || !posinfo))
+                               dstinfo=dst;
+                       if (!route_path_add_item_from_graph(ret, oldpath, s, -1, posinfo, dstinfo))
+                               ret->updated=0;
+                       start=s->start;
                }
-
-               curr = curr->start_next;
+               posinfo=NULL;
+               s=start->seg;
        }
+       if (dst->lenextra) 
+               route_path_add_line(ret, &dst->lp, &dst->c, dst->lenextra);
+       dbg(1, "%d segments\n", segs);
+       return ret;
+}
 
-       curr = conn->end;
-       while (curr != NULL) {
-               if (curr==seg_to) {
-                       curr = curr->end_next;
-                       continue;
-               }
+static int
+route_graph_build_next_map(struct route_graph *rg)
+{
+       do {
+               rg->m=mapset_next(rg->h, 2);
+               if (! rg->m)
+                       return 0;
+               map_rect_destroy(rg->mr);
+               rg->mr=map_rect_new(rg->m, rg->sel);
+       } while (!rg->mr);
                
-               ccnt = get_item_seg_coords(&curr->item, ca, 2047, &curr->start->c, &curr->end->c);
-               curr_angle = route_road_angle(&ca[ccnt-1], &ca[ccnt-2], 1);
-
-               curr_angle = from_angle - curr_angle;
+       return 1;
+}
 
-               if (curr_angle < 0) {
-                       curr_angle *= -1;
-               }
 
-               if (curr_angle < angle_diff) {
-                       return 0;
+static int
+is_turn_allowed(struct route_graph_point *p, struct route_graph_segment *from, struct route_graph_segment *to)
+{
+       struct route_graph_point *prev,*next;
+       struct route_graph_segment *tmp1,*tmp2;
+       if (from->start == p)
+               prev=from->end;
+       else
+               prev=from->start;
+       if (to->start == p)
+               next=to->end;
+       else
+               next=to->start;
+       tmp1=p->end;
+       while (tmp1) {
+               if (tmp1->start->c.x == prev->c.x && tmp1->start->c.y == prev->c.y &&
+                       (tmp1->data.item.type == type_street_turn_restriction_no ||
+                       tmp1->data.item.type == type_street_turn_restriction_only)) {
+                       tmp2=p->start;
+                       dbg(1,"found %s (0x%x,0x%x) (0x%x,0x%x)-(0x%x,0x%x) %p-%p\n",item_to_name(tmp1->data.item.type),tmp1->data.item.id_hi,tmp1->data.item.id_lo,tmp1->start->c.x,tmp1->start->c.y,tmp1->end->c.x,tmp1->end->c.y,tmp1->start,tmp1->end);
+                       while (tmp2) {
+                               dbg(1,"compare %s (0x%x,0x%x) (0x%x,0x%x)-(0x%x,0x%x) %p-%p\n",item_to_name(tmp2->data.item.type),tmp2->data.item.id_hi,tmp2->data.item.id_lo,tmp2->start->c.x,tmp2->start->c.y,tmp2->end->c.x,tmp2->end->c.y,tmp2->start,tmp2->end);
+                               if (item_is_equal(tmp1->data.item, tmp2->data.item)) 
+                                       break;
+                               tmp2=tmp2->start_next;
+                       }
+                       dbg(1,"tmp2=%p\n",tmp2);
+                       if (tmp2) {
+                               dbg(1,"%s tmp2->end=%p next=%p\n",item_to_name(tmp1->data.item.type),tmp2->end,next);
+                       }
+                       if (tmp1->data.item.type == type_street_turn_restriction_no && tmp2 && tmp2->end->c.x == next->c.x && tmp2->end->c.y == next->c.y) {
+                               dbg(1,"from 0x%x,0x%x over 0x%x,0x%x to 0x%x,0x%x not allowed (no)\n",prev->c.x,prev->c.y,p->c.x,p->c.y,next->c.x,next->c.y);
+                               return 0;
+                       }
+                       if (tmp1->data.item.type == type_street_turn_restriction_only && tmp2 && (tmp2->end->c.x != next->c.x || tmp2->end->c.y != next->c.y)) {
+                               dbg(1,"from 0x%x,0x%x over 0x%x,0x%x to 0x%x,0x%x not allowed (only)\n",prev->c.x,prev->c.y,p->c.x,p->c.y,next->c.x,next->c.y);
+                               return 0;
+                       }
                }
-
-               curr = curr->end_next;
+               tmp1=tmp1->end_next;
        }
-
+       dbg(1,"from 0x%x,0x%x over 0x%x,0x%x to 0x%x,0x%x allowed\n",prev->c.x,prev->c.y,p->c.x,p->c.y,next->c.x,next->c.y);
        return 1;
 }
 
-/**
- * @brief Creates a new route path
- * 
- * This creates a new non-trivial route. It therefore needs the routing information created by route_graph_flood, so
- * make shure to run route_graph_flood() after changing the destination before using this function.
- *
- * @param this The route graph to create the route from
- * @param oldpath (Optional) old path which may contain parts of the new part - this speeds things up a bit. May be NULL.
- * @param pos The starting position of the route
- * @param dst The destination of the route
- * @param speedlist The speedlist to use
- * @return The new route path
- */
-static struct route_path *
-route_path_new(struct route_graph *this, struct route_path *oldpath, struct route_info *pos, struct route_info *dst, int *speedlist)
+static void
+route_graph_clone_segment(struct route_graph *this, struct route_graph_segment *s, struct route_graph_point *start, struct route_graph_point *end, int flags)
 {
-       struct route_graph_point *start1=NULL,*start2=NULL,*start;
-       struct route_graph_segment *s=NULL;
-       struct route_graph_segment *lastseg = NULL;
-       int is_straight;
-       int len=0,segs=0;
-       int seg_len;
-#if 0
-       int time=0,hr,min,sec
-#endif
-       unsigned int val1=0xffffffff,val2=0xffffffff;
-       struct street_data *sd=pos->street;
-       struct route_path *ret;
+       int offset=0;
+       int maxspeed=0;
+       if (s->data.flags & AF_SPEED_LIMIT)
+               maxspeed=RSD_MAXSPEED(&s->data);
+       if (s->data.flags & AF_SEGMENTED) 
+               offset=RSD_OFFSET(&s->data);
+       dbg(1,"cloning segment from %p (0x%x,0x%x) to %p (0x%x,0x%x)\n",start,start->c.x,start->c.y, end, end->c.x, end->c.y);
+       route_graph_add_segment(this, start, end, s->data.len+1, &s->data.item, s->data.flags | flags, offset, maxspeed);
+}
 
-       if (item_is_equal(pos->street->item, dst->street->item)) { /* We probably don't have to leave this street and can use a trivial route */
-               if (!(sd->flags & AF_ONEWAY) && pos->lenneg >= dst->lenneg) {
-                       return route_path_new_trivial(this, pos, dst, -1);
+static void
+route_graph_process_restriction_segment(struct route_graph *this, struct route_graph_point *p, struct route_graph_segment *s, int dir)
+{
+       struct route_graph_segment *tmp;
+       struct route_graph_point *pn;
+       struct coord c=p->c;
+       int dx=0;
+       int dy=0;
+       c.x+=dx;
+       c.y+=dy;
+       dbg(1,"From %s %d,%d\n",item_to_name(s->data.item.type),dx,dy);
+       pn=route_graph_point_new(this, &c);
+       if (dir > 0) { /* going away */
+               dbg(1,"other 0x%x,0x%x\n",s->end->c.x,s->end->c.y);
+               if (s->data.flags & AF_ONEWAY) {
+                       dbg(1,"Not possible\n");
+                       return;
                }
-               if (!(sd->flags & AF_ONEWAYREV) && pos->lenpos >= dst->lenpos) {
-                       return route_path_new_trivial(this, pos, dst, 1);
+               route_graph_clone_segment(this, s, pn, s->end, AF_ONEWAYREV);
+       } else { /* coming in */
+               dbg(1,"other 0x%x,0x%x\n",s->start->c.x,s->start->c.y);
+               if (s->data.flags & AF_ONEWAYREV) {
+                       dbg(1,"Not possible\n");
+                       return;
                }
-       } 
-       if (! (sd->flags & AF_ONEWAY)) { /* Using the start of the current segment as one starting point */
-               start1=route_graph_get_point(this, &sd->c[0]);
-               if (! start1)
-                       return NULL;
-               val1=start1->value+route_value(speedlist, &sd->item, pos->lenneg);
-               dbg(1,"start1: %d(route)+%d=%d\n", start1->value, val1-start1->value, val1);
-       }
-       if (! (sd->flags & AF_ONEWAYREV)) { /* Using the start of the current segment as an alternative starting point */
-               start2=route_graph_get_point(this, &sd->c[sd->count-1]);
-               if (! start2)
-                       return NULL;
-               val2=start2->value+route_value(speedlist, &sd->item, pos->lenpos);
-               dbg(1,"start2: %d(route)+%d=%d\n", start2->value, val2-start2->value, val2);
+               route_graph_clone_segment(this, s, s->start, pn, AF_ONEWAY);
        }
-       dbg(1,"val1=%d val2=%d\n", val1, val2);
-       if (val1 == val2) {
-               val1=start1->start->start->value;
-               val2=start2->end->end->value;
-       }
-       ret=g_new0(struct route_path, 1);
-       if (pos->lenextra) 
-               route_path_add_item(ret, NULL, pos->lenextra, &pos->c, NULL, 0, &pos->lp, 1);
-       if (start1 && (val1 < val2)) {
-               start=start1;
-               route_path_add_item(ret, &sd->item, pos->lenneg, &pos->lp, sd->c, pos->pos+1, NULL, -1);
-       } else {
-               if (start2) {
-                       start=start2;
-                       route_path_add_item(ret, &sd->item, pos->lenpos, &pos->lp, sd->c+pos->pos+1, sd->count-pos->pos-1, NULL, 1);
-               } else {
-                       printf("no route found, pos blocked\n");
-                       return NULL;
+       tmp=p->start;
+       while (tmp) {
+               if (tmp != s && tmp->data.item.type != type_street_turn_restriction_no &&
+                       tmp->data.item.type != type_street_turn_restriction_only &&
+                       !(tmp->data.flags & AF_ONEWAYREV) && is_turn_allowed(p, s, tmp)) {
+                       route_graph_clone_segment(this, tmp, pn, tmp->end, AF_ONEWAY);
+                       dbg(1,"To start %s\n",item_to_name(tmp->data.item.type));
                }
+               tmp=tmp->start_next;
        }
-       ret->path_hash=item_hash_new();
-       while ((s=start->seg)) { /* following start->seg, which indicates the least costly way to reach our destination */
-               segs++;
-#if 0
-               printf("start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
-#endif
-               seg_len=s->len;
-               len+=seg_len;
-               
-               if (lastseg) {
-                       is_straight = route_check_straight(lastseg,s);
-               } else {
-                       is_straight = 0;
+       tmp=p->end;
+       while (tmp) {
+               if (tmp != s && tmp->data.item.type != type_street_turn_restriction_no &&
+                       tmp->data.item.type != type_street_turn_restriction_only &&
+                       !(tmp->data.flags & AF_ONEWAY) && is_turn_allowed(p, s, tmp)) {
+                       route_graph_clone_segment(this, tmp, tmp->start, pn, AF_ONEWAYREV);
+                       dbg(1,"To end %s\n",item_to_name(tmp->data.item.type));
                }
+               tmp=tmp->end_next;
+       }
+}
 
-               if (s->start == start) {                
-                       route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, 1, is_straight);
-                       start=s->end;
-               } else {
-                       route_path_add_item_from_graph(ret, oldpath, s, seg_len, s->offset, -1, is_straight);
-                       start=s->start;
-               }
+static void
+route_graph_process_restriction_point(struct route_graph *this, struct route_graph_point *p)
+{
+       struct route_graph_segment *tmp;
+       tmp=p->start;
+       dbg(1,"node 0x%x,0x%x\n",p->c.x,p->c.y);
+       while (tmp) {
+               if (tmp->data.item.type != type_street_turn_restriction_no &&
+                       tmp->data.item.type != type_street_turn_restriction_only)
+                       route_graph_process_restriction_segment(this, p, tmp, 1);
+               tmp=tmp->start_next;
+       }
+       tmp=p->end;
+       while (tmp) {
+               if (tmp->data.item.type != type_street_turn_restriction_no &&
+                       tmp->data.item.type != type_street_turn_restriction_only)
+                       route_graph_process_restriction_segment(this, p, tmp, -1);
+               tmp=tmp->end_next;
+       }
+       p->flags |= RP_TURN_RESTRICTION_RESOLVED;
+}
 
-               lastseg = s;
+static void
+route_graph_process_restrictions(struct route_graph *this)
+{
+       struct route_graph_point *curr;
+       int i;
+       dbg(1,"enter\n");
+       for (i = 0 ; i < HASH_SIZE ; i++) {
+               curr=this->hash[i];
+               while (curr) {
+                       if (curr->flags & RP_TURN_RESTRICTION) 
+                               route_graph_process_restriction_point(this, curr);
+                       curr=curr->hash_next;
+               }
        }
-       sd=dst->street;
-       dbg(1,"start->value=%d 0x%x,0x%x\n", start->value, start->c.x, start->c.y);
-       dbg(1,"dst sd->flags=%d sd->c[0]=0x%x,0x%x sd->c[sd->count-1]=0x%x,0x%x\n", sd->flags, sd->c[0].x,sd->c[0].y, sd->c[sd->count-1].x, sd->c[sd->count-1].y);
-       if (start->c.x == sd->c[0].x && start->c.y == sd->c[0].y) { /* Adding a final segment to reach the destination within the destination street */
-               route_path_add_item(ret, &sd->item, dst->lenneg, &dst->lp, sd->c, dst->pos+1, NULL, -1);
-       } else if (start->c.x == sd->c[sd->count-1].x && start->c.y == sd->c[sd->count-1].y) {
-               route_path_add_item(ret, &sd->item, dst->lenpos, &dst->lp, sd->c+dst->pos+1, sd->count-dst->pos-1, NULL, 1);
-       } else {
-               printf("no route found\n");
-               route_path_destroy(ret);
-               return NULL;
+}
+
+static void
+route_graph_build_done(struct route_graph *rg, int cancel)
+{
+       dbg(1,"cancel=%d\n",cancel);
+       if (rg->idle_ev)
+               event_remove_idle(rg->idle_ev);
+       if (rg->idle_cb)
+               callback_destroy(rg->idle_cb);
+       map_rect_destroy(rg->mr);
+        mapset_close(rg->h);
+       route_free_selection(rg->sel);
+       rg->idle_ev=NULL;
+       rg->idle_cb=NULL;
+       rg->mr=NULL;
+       rg->h=NULL;
+       rg->sel=NULL;
+       route_graph_process_restrictions(rg);
+       if (! cancel)
+               callback_call_0(rg->done_cb);
+       rg->busy=0;
+}
+
+static void
+route_graph_build_idle(struct route_graph *rg)
+{
+       int count=1000;
+       struct item *item;
+
+       while (count > 0) {
+               for (;;) {      
+                       item=map_rect_get_item(rg->mr);
+                       if (item)
+                               break;
+                       if (!route_graph_build_next_map(rg)) {
+                               route_graph_build_done(rg, 0);
+                               return;
+                       }
+               }
+               if (item->type == type_traffic_distortion)
+                       route_process_traffic_distortion(rg, item);
+               else if (item->type == type_street_turn_restriction_no || item->type == type_street_turn_restriction_only)
+                       route_process_turn_restriction(rg, item);
+               else
+                       route_process_street_graph(rg, item);
+               count--;
        }
-       if (dst->lenextra) 
-               route_path_add_item(ret, NULL, dst->lenextra, &dst->lp, NULL, 0, &dst->c, 1);
-       dbg(1, "%d segments\n", segs);
-       return ret;
 }
 
 /**
@@ -1598,41 +2212,37 @@ route_path_new(struct route_graph *this, struct route_path *oldpath, struct rout
  * @param ms The mapset to build the route graph from
  * @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.
  */
 static struct route_graph *
-route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2)
+route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2, struct callback *done_cb, int async)
 {
        struct route_graph *ret=g_new0(struct route_graph, 1);
-       struct map_selection *sel;
-       struct mapset_handle *h;
-       struct map_rect *mr;
-       struct map *m;
-       struct item *item;
 
-       if (!ret) {
-               printf("%s:Out of memory\n", __FUNCTION__);
-               return ret;
-       }
-       sel=route_calc_selection(c1, c2);
-       h=mapset_open(ms);
-       while ((m=mapset_next(h,1))) {
-               mr=map_rect_new(m, sel);
-               if (! mr)
-                       continue;
-               while ((item=map_rect_get_item(mr))) {
-                       if (item->type >= type_street_0 && item->type <= type_ferry) {
-                               route_process_street_graph(ret, item);
-                       }
+       dbg(1,"enter\n");
+
+       ret->sel=route_calc_selection(c1, c2);
+       ret->h=mapset_open(ms);
+       ret->done_cb=done_cb;
+       ret->busy=1;
+       if (route_graph_build_next_map(ret)) {
+               if (async) {
+                       ret->idle_cb=callback_new_1(callback_cast(route_graph_build_idle), ret);
+                       ret->idle_ev=event_add_idle(50, ret->idle_cb);
                }
-               map_rect_destroy(mr);
-        }
-        mapset_close(h);
-       route_free_selection(sel);
+       } else
+               route_graph_build_done(ret, 0);
 
        return ret;
 }
 
+static void
+route_graph_update_done(struct route *this, struct callback *cb)
+{
+       route_graph_flood(this->graph, this->dst, this->vehicleprofile, cb);
+}
+
 /**
  * @brief Updates the route graph
  *
@@ -1642,15 +2252,21 @@ route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2)
  * @param this The route to update the graph for
  */
 static void
-route_graph_update(struct route *this)
+route_graph_update(struct route *this, struct callback *cb, int async)
 {
+       struct attr route_status;
+
+       route_status.type=attr_route_status;
        route_graph_destroy(this->graph);
-       profile(1,"graph_free");
-       this->graph=route_graph_build(this->ms, &this->pos->c, &this->dst->c);
-       profile(1,"route_graph_build");
-       route_graph_flood(this->graph, this->dst, this->speedlist);
-       profile(1,"route_graph_flood");
-       this->version++;
+       callback_destroy(this->route_graph_done_cb);
+       this->route_graph_done_cb=callback_new_2(callback_cast(route_graph_update_done), this, cb);
+       route_status.u.num=route_status_building_graph;
+       route_set_attr(this, &route_status);
+       this->graph=route_graph_build(this->ms, &this->pos->c, &this->dst->c, this->route_graph_done_cb, async);
+       if (! async) {
+               while (this->graph->busy) 
+                       route_graph_build_idle(this->graph);
+       }
 }
 
 /**
@@ -1662,9 +2278,9 @@ route_graph_update(struct route *this)
 struct street_data *
 street_get_data (struct item *item)
 {
-       int count=0;
+       int count=0,*flags;
        struct street_data *ret = NULL, *ret1;
-       struct attr attr;
+       struct attr flags_attr, maxspeed_attr;
        const int step = 128;
        int c;
 
@@ -1679,19 +2295,28 @@ street_get_data (struct item *item)
                c = item_coord_get(item, &ret->c[count], step);
                count += c;
        } while (c && c == step);
-       if (!count) {
-               g_free(ret);
-               return NULL;
-       }
+
        ret1=g_realloc(ret, sizeof(struct street_data)+count*sizeof(struct coord));
        if (ret1)
                ret = ret1;
        ret->item=*item;
        ret->count=count;
-       if (item_attr_get(item, attr_flags, &attr)) 
-               ret->flags=attr.u.num;
-       else
-               ret->flags=0;
+       if (item_attr_get(item, attr_flags, &flags_attr)) 
+               ret->flags=flags_attr.u.num;
+       else {
+               flags=item_get_default_flags(item->type);
+               if (flags)
+                       ret->flags=*flags;
+               else
+                       ret->flags=0;
+       }
+
+       ret->maxspeed = -1;
+       if (ret->flags & AF_SPEED_LIMIT) {
+               if (item_attr_get(item, attr_maxspeed, &maxspeed_attr)) {
+                       ret->maxspeed = maxspeed_attr.u.num;
+               }
+       }
 
        return ret;
 }
@@ -1733,7 +2358,7 @@ street_data_free(struct street_data *sd)
  * @return The nearest street
  */
 static struct route_info *
-route_find_nearest_street(struct mapset *ms, struct pcoord *pc)
+route_find_nearest_street(struct vehicleprofile *vehicleprofile, struct mapset *ms, struct pcoord *pc)
 {
        struct route_info *ret=NULL;
        int max_dist=1000;
@@ -1748,53 +2373,61 @@ route_find_nearest_street(struct mapset *ms, struct pcoord *pc)
        struct coord c;
        struct coord_geo g;
 
-       c.x = pc->x;
-       c.y = pc->y;
-       /*
-        * This is not correct for two reasons:
-        * - You may need to go back first
-        * - Currently we allow mixing of mapsets
-        */
-       sel = route_rect(18, &c, &c, 0, max_dist);
+       ret=g_new0(struct route_info, 1);
+       mindist = INT_MAX;
+
        h=mapset_open(ms);
-       while ((m=mapset_next(h,1))) {
+       while ((m=mapset_next(h,2))) {
                c.x = pc->x;
                c.y = pc->y;
                if (map_projection(m) != pc->pro) {
                        transform_to_geo(pc->pro, &c, &g);
                        transform_from_geo(map_projection(m), &g, &c);
                }
+               sel = route_rect(18, &c, &c, 0, max_dist);
+               if (!sel)
+                       continue;
                mr=map_rect_new(m, sel);
-               if (! mr)
+               if (!mr) {
+                       map_selection_destroy(sel);
                        continue;
+               }
                while ((item=map_rect_get_item(mr))) {
-                       if (item->type >= type_street_0 && item->type <= type_ferry) {
+                       if (item_get_default_flags(item->type)) {
                                sd=street_get_data(item);
+                               if (!sd)
+                                       continue;
                                dist=transform_distance_polyline_sq(sd->c, sd->count, &c, &lp, &pos);
-                               if (!ret || dist < mindist) {
-                                       if (ret) {
+                               if (dist < mindist && (
+                                       (sd->flags & vehicleprofile->flags_forward_mask) == vehicleprofile->flags ||
+                                       (sd->flags & vehicleprofile->flags_reverse_mask) == vehicleprofile->flags)) {
+                                       mindist = dist;
+                                       if (ret->street) {
                                                street_data_free(ret->street);
-                                               g_free(ret);
-                                       }
-                                       ret=g_new(struct route_info, 1);
-                                       if (!ret) {
-                                               printf("%s:Out of memory\n", __FUNCTION__);
-                                               return ret;
                                        }
                                        ret->c=c;
                                        ret->lp=lp;
                                        ret->pos=pos;
-                                       mindist=dist;
                                        ret->street=sd;
                                        dbg(1,"dist=%d id 0x%x 0x%x pos=%d\n", dist, item->id_hi, item->id_lo, pos);
-                               } else 
+                               } else {
                                        street_data_free(sd);
+                               }
                        }
-               }  
+               }
+               map_selection_destroy(sel);
                map_rect_destroy(mr);
        }
        mapset_close(h);
-       map_selection_destroy(sel);
+
+       if (!ret->street || mindist > max_dist*max_dist) {
+               if (ret->street) {
+                       street_data_free(ret->street);
+                       dbg(1,"Much too far %d > %d\n", mindist, max_dist);
+               }
+               g_free(ret);
+               ret = NULL;
+       }
 
        return ret;
 }
@@ -1862,12 +2495,15 @@ struct map_rect_priv {
        int pos;
        struct map_priv *mpriv;
        struct item item;
-       int length;
        unsigned int last_coord;
+       struct route_path *path;
        struct route_path_segment *seg,*seg_next;
        struct route_graph_point *point;
        struct route_graph_segment *rseg;
        char *str;
+       int hash_bucket;
+       struct coord *coord_sel;        /**< Set this to a coordinate if you want to filter for just a single route graph point */
+       struct route_graph_point_iterator it;
 };
 
 static void
@@ -1890,6 +2526,8 @@ rm_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
        struct map_rect_priv *mr = priv_data;
        struct route_path_segment *seg=mr->seg;
        struct route *route=mr->mpriv->route;
+       if (mr->item.type != type_street_route)
+               return 0;
        attr->type=attr_type;
        switch (attr_type) {
                case attr_any:
@@ -1898,37 +2536,44 @@ rm_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
                                        return 1;
                        }
                        return 0;
+               case attr_maxspeed:
+                       mr->attr_next = attr_street_item;
+                       if (seg && seg->data->flags && AF_SPEED_LIMIT) {
+                               attr->u.num=RSD_MAXSPEED(seg->data);
+
+                       } else {
+                               return 0;
+                       }
+                       return 1;
                case attr_street_item:
-                       mr->attr_next=attr_route_follow_straight;
-                       if (seg && seg->item.map)
-                               attr->u.item=&seg->item;
+                       mr->attr_next=attr_direction;
+                       if (seg && seg->data->item.map)
+                               attr->u.item=&seg->data->item;
                        else
                                return 0;
                        return 1;
-               case attr_route_follow_straight:
-                       mr->attr_next=attr_direction;
-                       if (seg) {
-                               return attr_generic_get_attr(seg->attrs,NULL,attr_route_follow_straight,attr,NULL);
-                       }
-                       return 0;
                case attr_direction:
-                       mr->attr_next=attr_length;
+                       mr->attr_next=attr_route;
                        if (seg) 
                                attr->u.num=seg->direction;
                        else
                                return 0;
                        return 1;
+               case attr_route:
+                       mr->attr_next=attr_length;
+                       attr->u.route = mr->mpriv->route;
+                       return 1;
                case attr_length:
+                       mr->attr_next=attr_time;
                        if (seg)
-                               attr->u.num=seg->length;
+                               attr->u.num=seg->data->len;
                        else
-                               attr->u.num=mr->length;
-                       mr->attr_next=attr_time;
+                               return 0;
                        return 1;
                case attr_time:
                        mr->attr_next=attr_none;
                        if (seg)
-                               attr->u.num=route_time(route->speedlist, &seg->item, seg->length);
+                               attr->u.num=route_time_seg(route->vehicleprofile, seg->data, NULL);
                        else
                                return 0;
                        return 1;
@@ -1952,6 +2597,18 @@ rm_coord_get(void *priv_data, struct coord *c, int count)
        struct route *r = mr->mpriv->route;
        enum projection pro = route_projection(r);
 
+       if (pro == projection_none)
+               return 0;
+       if (mr->item.type == type_route_start || mr->item.type == type_route_start_reverse || mr->item.type == type_route_end) {
+               if (! count || mr->last_coord)
+                       return 0;
+               mr->last_coord=1;
+               if (mr->item.type == type_route_start || mr->item.type == type_route_start_reverse)
+                       c[0]=r->pos->c;
+               else
+                       c[0]=r->dst->c;
+               return 1;
+       }
        if (! seg)
                return 0;
        for (i=0; i < count; i++) {
@@ -1989,16 +2646,33 @@ rp_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
 {
        struct map_rect_priv *mr = priv_data;
        struct route_graph_point *p = mr->point;
-       if (mr->item.type != type_rg_point) 
-               return 0;
+       struct route_graph_segment *seg = mr->rseg;
+       struct route *route=mr->mpriv->route;
+
+       attr->type=attr_type;
        switch (attr_type) {
-       case attr_any:
+       case attr_any: // works only with rg_points for now
                while (mr->attr_next != attr_none) {
+                       dbg(0,"querying %s\n", attr_to_name(mr->attr_next));
                        if (rp_attr_get(priv_data, mr->attr_next, attr))
                                return 1;
                }
                return 0;
+       case attr_maxspeed:
+               mr->attr_next = attr_label;
+               if (mr->item.type != type_rg_segment) 
+                       return 0;
+               if (seg && (seg->data.flags & AF_SPEED_LIMIT)) {
+                       attr->type = attr_maxspeed;
+                       attr->u.num=RSD_MAXSPEED(&seg->data);
+                       return 1;
+               } else {
+                       return 0;
+               }
        case attr_label:
+               mr->attr_next=attr_street_item;
+               if (mr->item.type != type_rg_point) 
+                       return 0;
                attr->type = attr_label;
                if (mr->str)
                        g_free(mr->str);
@@ -2007,16 +2681,74 @@ rp_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
                else
                        mr->str=g_strdup("-");
                attr->u.str = mr->str;
-               mr->attr_next=attr_none;
+               return 1;
+       case attr_street_item:
+               mr->attr_next=attr_flags;
+               if (mr->item.type != type_rg_segment) 
+                       return 0;
+               if (seg && seg->data.item.map)
+                       attr->u.item=&seg->data.item;
+               else
+                       return 0;
+               return 1;
+       case attr_flags:
+               mr->attr_next = attr_direction;
+               if (mr->item.type != type_rg_segment)
+                       return 0;
+               if (seg) {
+                       attr->u.num = seg->data.flags;
+               } else {
+                       return 0;
+               }
+               return 1;
+       case attr_direction:
+               mr->attr_next = attr_debug;
+               // 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)
+               if (!mr->coord_sel || (mr->item.type != type_rg_segment))
+                       return 0;
+               if (seg->start == mr->point) {
+                       attr->u.num=1;
+               } else if (seg->end == mr->point) {
+                       attr->u.num=-1;
+               } else {
+                       return 0;
+               }
                return 1;
        case attr_debug:
-               attr->type = attr_debug;
+               mr->attr_next=attr_none;
                if (mr->str)
                        g_free(mr->str);
-               mr->str=g_strdup_printf("x=%d y=%d", p->c.x, p->c.y);
-               attr->u.str = mr->str;
-               mr->attr_next=attr_none;
-               return 1;
+               switch (mr->item.type) {
+               case type_rg_point:
+               {
+                       struct route_graph_segment *tmp;
+                       int start=0;
+                       int end=0;
+                       tmp=p->start;
+                       while (tmp) {
+                               start++;
+                               tmp=tmp->start_next;
+                       }
+                       tmp=p->end;
+                       while (tmp) {
+                               end++;
+                               tmp=tmp->end_next;
+                       }
+                       mr->str=g_strdup_printf("%d %d %p (0x%x,0x%x)", start, end, p, p->c.x, p->c.y);
+                       attr->u.str = mr->str;
+               }
+                       return 1;
+               case type_rg_segment:
+                       if (! seg)
+                               return 0;
+                       mr->str=g_strdup_printf("len %d time %d start %p end %p",seg->data.len, route_time_seg(route->vehicleprofile, &seg->data, NULL), seg->start, seg->end);
+                       attr->u.str = mr->str;
+                       return 1;
+               default:
+                       return 0;
+               }
+               return 0;
        default:
                mr->attr_next=attr_none;
                attr->type=attr_none;
@@ -2024,6 +2756,14 @@ rp_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr)
        }
 }
 
+/**
+ * @brief Returns the coordinates of a route graph item
+ *
+ * @param priv_data The route graph item's private data
+ * @param c Pointer where to store the coordinates
+ * @param count How many coordinates to get at a max?
+ * @return The number of coordinates retrieved
+ */
 static int
 rp_coord_get(void *priv_data, struct coord *c, int count)
 {
@@ -2034,6 +2774,8 @@ rp_coord_get(void *priv_data, struct coord *c, int count)
        struct route *r = mr->mpriv->route;
        enum projection pro = route_projection(r);
 
+       if (pro == projection_none)
+               return 0;
        for (i=0; i < count; i++) {
                if (mr->item.type == type_rg_point) {
                        if (mr->last_coord >= 1)
@@ -2079,6 +2821,12 @@ static struct item_methods methods_point_item = {
 };
 
 static void
+rp_destroy(struct map_priv *priv)
+{
+       g_free(priv);
+}
+
+static void
 rm_destroy(struct map_priv *priv)
 {
        g_free(priv);
@@ -2093,29 +2841,57 @@ rm_rect_new(struct map_priv *priv, struct map_selection *sel)
                return NULL;
        if (! route_get_dst(priv->route))
                return NULL;
+#if 0
        if (! priv->route->path2)
                return NULL;
+#endif
        mr=g_new0(struct map_rect_priv, 1);
        mr->mpriv = priv;
        mr->item.priv_data = mr;
-       mr->item.type = type_street_route;
+       mr->item.type = type_none;
        mr->item.meth = &methods_route_item;
-       mr->seg_next=priv->route->path2->path;
+       if (priv->route->path2) {
+               mr->path=priv->route->path2;
+               mr->seg_next=mr->path->path;
+               mr->path->in_use++;
+       } else
+               mr->seg_next=NULL;
        return mr;
 }
 
+/**
+ * @brief Opens a new map rectangle on the route graph's map
+ *
+ * This function opens a new map rectangle on the route graph's map.
+ * The "sel" parameter enables you to only search for a single route graph
+ * point on this map (or exactly: open a map rectangle that only contains
+ * this one point). To do this, pass here a single map selection, whose 
+ * c_rect has both coordinates set to the same point. Otherwise this parameter
+ * has no effect.
+ *
+ * @param priv The route graph map's private data
+ * @param sel Here it's possible to specify a point for which to search. Please read the function's description.
+ * @return A new map rect's private data
+ */
 static struct map_rect_priv * 
 rp_rect_new(struct map_priv *priv, struct map_selection *sel)
 {
        struct map_rect_priv * mr;
+
        dbg(1,"enter\n");
-       if (! priv->route->graph || ! priv->route->graph->route_points)
+       if (! priv->route->graph)
                return NULL;
        mr=g_new0(struct map_rect_priv, 1);
        mr->mpriv = priv;
        mr->item.priv_data = mr;
        mr->item.type = type_rg_point;
        mr->item.meth = &methods_point_item;
+       if (sel) {
+               if ((sel->u.c_rect.lu.x == sel->u.c_rect.rl.x) && (sel->u.c_rect.lu.y == sel->u.c_rect.rl.y)) {
+                       mr->coord_sel = g_malloc(sizeof(struct coord));
+                       *(mr->coord_sel) = sel->u.c_rect.lu;
+               }
+       }
        return mr;
 }
 
@@ -2124,6 +2900,15 @@ rm_rect_destroy(struct map_rect_priv *mr)
 {
        if (mr->str)
                g_free(mr->str);
+       if (mr->coord_sel) {
+               g_free(mr->coord_sel);
+       }
+       if (mr->path) {
+               mr->path->in_use--;
+               if (mr->path->update_required && !mr->path->in_use) 
+                       route_path_update_done(mr->mpriv->route, mr->path->update_required-1);
+       }
+
        g_free(mr);
 }
 
@@ -2135,10 +2920,31 @@ rp_get_item(struct map_rect_priv *mr)
        struct route_graph_segment *seg = mr->rseg;
 
        if (mr->item.type == type_rg_point) {
-               if (!p)
-                       p = r->graph->route_points;
-               else
-                       p = p->next;
+               if (mr->coord_sel) {
+                       // We are supposed to return only the point at one specified coordinate...
+                       if (!p) {
+                               p = route_graph_get_point_last(r->graph, mr->coord_sel);
+                               if (!p) {
+                                       mr->point = NULL; // This indicates that no point has been found
+                               } else {
+                                       mr->it = rp_iterator_new(p);
+                               }
+                       } else {
+                               p = NULL;
+                       }
+               } else {
+                       if (!p) {
+                               mr->hash_bucket=0;
+                               p = r->graph->hash[0];
+                       } else 
+                               p=p->hash_next;
+                       while (!p) {
+                               mr->hash_bucket++;
+                               if (mr->hash_bucket >= HASH_SIZE)
+                                       break;
+                               p = r->graph->hash[mr->hash_bucket];
+                       }
+               }
                if (p) {
                        mr->point = p;
                        mr->item.id_lo++;
@@ -2148,10 +2954,19 @@ rp_get_item(struct map_rect_priv *mr)
                } else
                        mr->item.type = type_rg_segment;
        }
-       if (!seg)
-               seg=r->graph->route_segments;
-       else
-               seg=seg->next;
+       
+       if (mr->coord_sel) {
+               if (!mr->point) { // This means that no point has been found
+                       return NULL;
+               }
+               seg = rp_iterator_next(&(mr->it));
+       } else {
+               if (!seg)
+                       seg=r->graph->route_segments;
+               else
+                       seg=seg->next;
+       }
+       
        if (seg) {
                mr->rseg = seg;
                mr->item.id_lo++;
@@ -2176,14 +2991,30 @@ rp_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo)
 static struct item *
 rm_get_item(struct map_rect_priv *mr)
 {
-       struct route *r = mr->mpriv->route;
-       struct route_path_segment *seg = mr->seg;
+       struct route *route=mr->mpriv->route;
        dbg(1,"enter\n", mr->pos);
 
-       mr->seg=mr->seg_next;
-       if (! mr->seg)
+       switch (mr->item.type) {
+       case type_none:
+               if (route->pos && route->pos->street_direction && route->pos->street_direction != route->pos->dir)
+                       mr->item.type=type_route_start_reverse;
+               else
+                       mr->item.type=type_route_start;
+               if (route->pos) 
+                       break;
+       default:
+               mr->item.type=type_street_route;
+               mr->seg=mr->seg_next;
+               if (mr->seg) {
+                       mr->seg_next=mr->seg->next;
+                       break;
+               }
+               mr->item.type=type_route_end;
+               if (mr->mpriv->route->dst)
+                       break;
+       case type_route_end:
                return NULL;
-       mr->seg_next=mr->seg->next;
+       }
        mr->last_coord = 0;
        mr->item.id_lo++;
        rm_attr_rewind(mr);
@@ -2215,7 +3046,7 @@ static struct map_methods route_meth = {
 static struct map_methods route_graph_meth = {
        projection_mg,
        "utf-8",
-       rm_destroy,
+       rp_destroy,
        rp_rect_new,
        rm_rect_destroy,
        rp_get_item,
@@ -2225,16 +3056,6 @@ static struct map_methods route_graph_meth = {
        NULL,
 };
 
-void 
-route_toggle_routegraph_display(struct route *route)
-{
-       if (route->flags & RF_SHOWGRAPH) {
-               route->flags &= ~RF_SHOWGRAPH;
-       } else {
-               route->flags |= RF_SHOWGRAPH;
-       }
-}
-
 static struct map_priv *
 route_map_new_helper(struct map_methods *meth, struct attr **attrs, int graph)
 {
@@ -2270,15 +3091,26 @@ static struct map *
 route_get_map_helper(struct route *this_, struct map **map, char *type, char *description)
 {
        if (! *map) 
-               *map=map_new((struct attr*[]){
+               *map=map_new(NULL, (struct attr*[]){
                                 &(struct attr){attr_type,{type}},
                                 &(struct attr){attr_route,.u.route=this_},
                                 &(struct attr){attr_data,{""}},
                                 &(struct attr){attr_description,{description}},
                                 NULL});
        return *map;
 }
 
+/**
+ * @brief Returns a new map containing the route path
+ *
+ * This function returns a new map containing the route path.
+ *
+ * @important Do not map_destroy() this!
+ *
+ * @param this_ The route to get the map of
+ * @return A new map containing the route path
+ */
 struct map *
 route_get_map(struct route *this_)
 {
@@ -2286,6 +3118,16 @@ route_get_map(struct route *this_)
 }
 
 
+/**
+ * @brief Returns a new map containing the route graph
+ *
+ * This function returns a new map containing the route graph.
+ *
+ * @important Do not map_destroy()  this!
+ *
+ * @param this_ The route to get the map of
+ * @return A new map containing the route graph
+ */
 struct map *
 route_get_graph_map(struct route *this_)
 {
@@ -2297,9 +3139,71 @@ route_set_projection(struct route *this_, enum projection pro)
 {
 }
 
+int
+route_set_attr(struct route *this_, struct attr *attr)
+{
+       int attr_updated=0;
+       switch (attr->type) {
+       case attr_route_status:
+               attr_updated = (this_->route_status != attr->u.num);
+               this_->route_status = attr->u.num;
+               break;
+       default:
+               return 0;
+       }
+       if (attr_updated)
+               callback_list_call_attr_2(this_->cbl2, attr->type, this_, attr);
+       return 1;
+}
+
+int
+route_add_attr(struct route *this_, struct attr *attr)
+{
+       switch (attr->type) {
+       case attr_callback:
+               dbg(1,"add\n");
+               callback_list_add(this_->cbl2, attr->u.callback);
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+int
+route_remove_attr(struct route *this_, struct attr *attr)
+{
+       switch (attr->type) {
+       case attr_callback:
+               callback_list_remove(this_->cbl2, attr->u.callback);
+               return 1;
+       default:
+               return 0;
+       }
+}
+
+int
+route_get_attr(struct route *this_, enum attr_type type, struct attr *attr, struct attr_iter *iter)
+{
+       int ret=1;
+       switch (type) {
+       case attr_map:
+               attr->u.map=route_get_map(this_);
+               ret=(attr->u.map != NULL);
+               break;
+       case attr_route_status:
+               attr->u.num=this_->route_status;
+               break;
+       default:
+               return 0;
+       }
+       attr->type=type;
+       return ret;
+}
+
 void
 route_init(void)
 {
        plugin_register_map_type("route", route_map_new);
        plugin_register_map_type("route_graph", route_graph_map_new);
 }
+