#include "fib.h"
#include "event.h"
#include "callback.h"
+#include "vehicleprofile.h"
+#include "roadprofile.h"
struct map_priv {
* 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.*/
* 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
};
/**
+ * @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 */
+};
+
+/**
* @brief A segment in the route path
*
* This is a segment in the route path.
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 */
};
/**
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 Routing preferences
- *
- * This struct holds all information about route preferences (fastest, shortest, etc)
- */
-
-struct route_preferences {
- int mode; /**< 0 = Auto, 1 = On-Road, 2 = Off-Road */
- int flags_forward_mask; /**< Flags mask for moving in positive direction */
- int flags_reverse_mask; /**< Flags mask for moving in reverse direction */
- int flags; /**< Required flags to move through a segment */
- int maxspeed_handling; /**< 0 = Always, 1 = Only if lower, 2 = Never */
- int speedlist[route_item_last-route_item_first+1]; /**< The speedlist for this route */
-};
-
/**
* @brief A complete route
*
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 *cbl; /**< Callback list to call when route changes */
+ 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" */
- struct route_preferences preferences; /**< Routing preferences */
+ struct vehicleprofile *vehicleprofile; /**< Routing preferences */
+ int route_status; /**< Route Status */
};
/**
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 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_point *route_points; /**< Pointer to the first route_graph_point in the linked list of all points */
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 */
struct route_graph_segment *next; /**< The next segment to be returned */
};
-static struct route_info * route_find_nearest_street(struct mapset *ms, struct pcoord *c);
+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, struct callback *cb);
+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 route_preferences *pref);
+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, int cancel);
+static void route_path_update(struct route *this, int cancel, int async);
/**
* @brief Returns the projection used for this route
} else {
this->destination_distance = 50; // Default value
}
- this->cbl=callback_list_new();
- this->preferences.flags_forward_mask=AF_ONEWAYREV|AF_CAR;
- this->preferences.flags_reverse_mask=AF_ONEWAY|AF_CAR;
- this->preferences.flags=AF_CAR;
+ this->cbl2=callback_list_new();
return this;
}
if (direction && !(seg->data.flags & AF_ONEWAYREV)) {
return 0;
}
+ if (seg->data.flags & AF_ROUNDABOUT_VALID)
+ return 0;
if (!origin) {
origin = seg;
}
/**
+ * @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
}
/**
- * @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->preferences.speedlist;
-}
-
-/**
* @brief Checks if the path is calculated for the route passed
*
* @param this The route to check
}
/**
- * @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->preferences.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
{
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 (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);
+
}
/**
route_path_update_done(struct route *this, int new_graph)
{
struct route_path *oldpath=this->path2;
- int val;
+ 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->preferences);
+ this->path2=route_path_new(this->graph, oldpath, this->pos, this->dst, this->vehicleprofile);
route_path_destroy(oldpath);
if (this->path2) {
- if (new_graph)
- val=4;
+ if (!new_graph && this->path2->updated)
+ route_status.u.num=route_status_path_done_incremental;
else
- val=2+!this->path2->updated;
+ route_status.u.num=route_status_path_done_new;
} else
- val=1;
- callback_list_call_attr_1(this->cbl, attr_route, (void *)val);
+ route_status.u.num=route_status_not_found;
+ route_set_attr(this, &route_status);
}
/**
* @param this The route to update
*/
static void
-route_path_update(struct route *this, int cancel)
+route_path_update(struct route *this, int cancel, int async)
{
dbg(1,"enter %d\n", cancel);
if (! this->pos || ! this->dst) {
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, 1);
+ 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);
+ route_graph_update(this, this->route_graph_flood_done_cb, async);
}
}
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);
- route_path_update(this, 0);
+ route_path_update(this, 0, 1);
}
/**
* @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 pcoord *c;
+ struct coord *c;
struct route_info *ret;
struct street_data *sd;
if (this->pos)
route_info_free(this->pos);
this->pos=NULL;
- ret->c.x = c->x;
- ret->c.y = c->y;
- ret->lp.x=c->x;
- ret->lp.y=c->y;
+ ret->c=*c;
+ ret->lp=*c;
ret->pos=tracking_get_segment_pos(tracking);
+ 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, c->pro);
+ 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, 0);
+ route_path_update(this, 0, 1);
dbg(2,"ret\n");
}
* @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);
- } else
- callback_list_call_attr_1(this->cbl, attr_route, (void *)0);
+ } 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, 1);
+ route_path_update(this, 1, async);
profile(0,"end");
}
*
* @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
*
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;
}
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));
}
/**
}
+static int
+route_graph_segment_is_duplicate(struct route_graph_point *start, struct item *item, int flags, int offset)
+{
+ struct route_graph_segment *s;
+ s=start->start;
+ while (s) {
+ 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;
+ }
+ return 0;
+}
+
/**
* @brief Inserts a new segment into the route graph
*
{
struct route_graph_segment *s;
int size;
- s=start->start;
- while (s) {
- if (item_is_equal(*item, s->data.item)) {
- if (flags & AF_SEGMENTED) {
- if (RSD_OFFSET(&s->data) == offset) {
- return;
- }
- } else
- return;
- }
- s=s->start_next;
- }
size = sizeof(struct route_graph_segment)-sizeof(struct route_segment_data)+route_segment_data_size(flags);
s = g_malloc0(size);
* 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
struct route_path_segment *segment;
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);
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, extra=0, ret=1;
+ 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)\n", rgs->data.item.id_hi, rgs->data.item.id_lo);
+ 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->data.item);
- if (ccnt) {
+ 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)
- goto linkold;
+ if (segment) {
+ ret=1;
+ if (!pos)
+ goto linkold;
+ }
}
}
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;
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);
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);
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;
+ }
/* 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 */
route_check_roundabout(rgs, 13, (dir < 1), NULL);
}
- ret=0;
memcpy(segment->data, &rgs->data, seg_dat_size);
-
linkold:
- segment->data->len=rgs->data.len;
+ segment->data->len=len;
segment->next=NULL;
- item_hash_insert(this->path_hash, &rgs->data.item, (void *)ccnt);
+ item_hash_insert(this->path_hash, &rgs->data.item, segment);
route_path_add_segment(this, segment);
* This function returns the time needed to drive len meters on
* the item passed in item in tenth of seconds.
*
- * @param preferences The routing preferences
+ * @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
*/
static int
-route_time_seg(struct route_preferences *preferences, struct route_segment_data *over)
-{
- int pspeed=preferences->speedlist[over->item.type-route_item_first];
- int speed=pspeed;
- if (preferences->maxspeed_handling != 2 && (over->flags & AF_SPEED_LIMIT)) {
- speed=RSD_MAXSPEED(over);
- if (preferences->maxspeed_handling == 1 && speed > pspeed)
- speed=pspeed;
- } else
- speed=preferences->speedlist[over->item.type-route_item_first];
+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 (!speed)
- return INT_MAX;
- return over->len*36/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 0;
}
/**
* @brief Returns the "costs" of driving from point from over segment over in direction dir
*
- * @param preferences The routing preferences
+ * @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
*/
static int
-route_value_seg(struct route_preferences *preferences, struct route_graph_point *from, struct route_segment_data *over, int dir)
+route_value_seg(struct vehicleprofile *profile, struct route_graph_point *from, struct route_graph_segment *over, int dir)
{
#if 0
- dbg(0,"flags 0x%x mask 0x%x flags 0x%x\n", over->flags, dir >= 0 ? preferences->flags_forward_mask : preferences->flags_reverse_mask, preferences->flags);
+ 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->flags & (dir >= 0 ? preferences->flags_forward_mask : preferences->flags_reverse_mask)) != preferences->flags)
+ 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;
- return route_time_seg(preferences, over);
+ 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);
+ }
+}
+
+/**
+ * @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;
+
}
/**
int segmented = 0;
int offset = 1;
int maxspeed = -1;
-
+
if (item_coord_get(item, &l, 1)) {
+ 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[item->type-route_item_first];
+ flags = *default_flags;
if (flags & AF_SPEED_LIMIT) {
}
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, maxspeed);
+ 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;
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, maxspeed);
+ 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;
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, maxspeed);
+ 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)
-{
- 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;
-}
-
static struct route_graph_segment *
-route_graph_get_segment(struct route_graph *graph, struct street_data *sd)
+route_graph_get_segment(struct route_graph *graph, struct street_data *sd, struct route_graph_segment *last)
{
- struct route_graph_point *start=route_graph_get_point(graph, &sd->c[0]);
+ struct route_graph_point *start=NULL;
struct route_graph_segment *s;
- s=start->start;
- while (s) {
- if (item_is_equal(sd->item, s->data.item))
- return s;
- s=s->start_next;
+ 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;
}
* at this algorithm.
*/
static void
-route_graph_flood(struct route_graph *this, struct route_info *dst, struct route_preferences *preferences, struct callback *cb)
+route_graph_flood(struct route_graph *this, struct route_info *dst, struct vehicleprofile *profile, struct callback *cb)
{
struct route_graph_point *p_min;
- struct route_graph_segment *s;
+ struct route_graph_segment *s=NULL;
int min,new,old,val;
struct fibheap *heap; /* This heap will hold all points with "temporarily" calculated costs */
- heap = fh_makeheap();
- fh_setcmp(heap, compare);
-
+ heap = fh_makekeyheap();
- s=route_graph_get_segment(this, dst->street);
- if (!s) {
- dbg(0,"no segment for destination found\n");
- return;
- }
- val=route_value_seg(preferences, NULL, &s->data, 1);
- if (val != INT_MAX) {
- val=val*(100-dst->percent)/100;
- s->end->seg=s;
- s->end->value=val;
- s->end->el=fh_insert(heap, s->end);
- }
- val=route_value_seg(preferences, NULL, &s->data, -1);
- if (val != INT_MAX) {
- val=val*dst->percent/100;
- s->start->seg=s;
- s->start->value=val;
- s->start->el=fh_insert(heap, s->start);
+ 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);
+ }
}
for (;;) {
p_min=fh_extractmin(heap); /* Starting Dijkstra by selecting the point with the minimum costs on the heap */
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_seg(preferences, p_min, &s->data, -1);
+ val=route_value_seg(profile, p_min, s, -1);
if (val != INT_MAX) {
new=min+val;
if (debug_route)
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);
+ 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_replacedata(heap, s->end->el, s->end);
+ fh_replacekey(heap, s->end->el, new);
}
}
if (debug_route)
}
s=p_min->end;
while (s) { /* Doing the same as above with the segments leading towards our point */
- val=route_value_seg(preferences, p_min, &s->data, 1);
+ val=route_value_seg(profile, p_min, s, 1);
if (val != INT_MAX) {
new=min+val;
if (debug_route)
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);
+ 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_replacedata(heap, s->start->el, s->start);
+ fh_replacekey(heap, s->start->el, new);
}
}
if (debug_route)
* @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.
+ * make sure 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.
* @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, struct route_preferences *preferences)
+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;
if (! pos->street || ! dst->street)
return NULL;
- if (preferences->mode == 2 || (preferences->mode == 0 && pos->lenextra + dst->lenextra + pos->lenpos-dst->lenpos > transform_distance(map_projection(pos->street->item.map), &pos->c, &dst->c)))
+ 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);
- s=route_graph_get_segment(this, pos->street);
+ s=route_graph_get_segment(this, pos->street, NULL);
if (!s) {
dbg(0,"no segment for position found\n");
return NULL;
}
- val=route_value_seg(preferences, NULL, &s->data, -1);
- if (val != INT_MAX) {
+ 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(preferences, NULL, &s->data, 1);
- if (val != INT_MAX) {
+ 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;
}
route_graph_build_next_map(struct route_graph *rg)
{
do {
- rg->m=mapset_next(rg->h, 1);
+ rg->m=mapset_next(rg->h, 2);
if (! rg->m)
return 0;
map_rect_destroy(rg->mr);
return 1;
}
+
+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;
+ }
+ }
+ 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;
+}
+
+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)
+{
+ 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);
+}
+
+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;
+ }
+ 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;
+ }
+ route_graph_clone_segment(this, s, s->start, pn, AF_ONEWAY);
+ }
+ 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;
+ }
+ 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;
+ }
+}
+
+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;
+}
+
+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;
+ }
+ }
+}
+
static void
route_graph_build_done(struct route_graph *rg, int cancel)
{
dbg(1,"cancel=%d\n",cancel);
- event_remove_idle(rg->idle_ev);
- callback_destroy(rg->idle_cb);
+ 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->mr=NULL;
rg->h=NULL;
rg->sel=NULL;
+ route_graph_process_restrictions(rg);
if (! cancel)
callback_call_0(rg->done_cb);
rg->busy=0;
return;
}
}
- if (item->type >= route_item_first && item->type <= route_item_last)
+ 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--;
}
* @return The new route graph.
*/
static struct route_graph *
-route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2, struct callback *done_cb)
+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);
ret->done_cb=done_cb;
ret->busy=1;
if (route_graph_build_next_map(ret)) {
- ret->idle_cb=callback_new_1(callback_cast(route_graph_build_idle), ret);
- ret->idle_ev=event_add_idle(50, ret->idle_cb);
+ 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);
+ }
} else
route_graph_build_done(ret, 0);
static void
route_graph_update_done(struct route *this, struct callback *cb)
{
- route_graph_flood(this->graph, this->dst, &this->preferences, cb);
+ route_graph_flood(this->graph, this->dst, this->vehicleprofile, cb);
}
/**
* @param this The route to update the graph for
*/
static void
-route_graph_update(struct route *this, struct callback *cb)
+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);
callback_destroy(this->route_graph_done_cb);
this->route_graph_done_cb=callback_new_2(callback_cast(route_graph_update_done), this, cb);
- callback_list_call_attr_1(this->cbl, attr_route, (void *)0);
- this->graph=route_graph_build(this->ms, &this->pos->c, &this->dst->c, this->route_graph_done_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);
+ }
}
/**
struct street_data *
street_get_data (struct item *item)
{
- int count=0;
+ int count=0,*flags;
struct street_data *ret = NULL, *ret1;
struct attr flags_attr, maxspeed_attr;
const int step = 128;
ret->count=count;
if (item_attr_get(item, attr_flags, &flags_attr))
ret->flags=flags_attr.u.num;
- else
- ret->flags=0;
+ 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) {
* @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;
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) {
continue;
}
while ((item=map_rect_get_item(mr))) {
- if (item->type >= route_item_first && item->type <= route_item_last) {
+ 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 (dist < mindist) {
+ 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);
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;
};
attr->u.route = mr->mpriv->route;
return 1;
case attr_length:
+ mr->attr_next=attr_time;
if (seg)
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_seg(&route->preferences, seg->data);
- } else
+ if (seg)
+ attr->u.num=route_time_seg(route->vehicleprofile, seg->data, NULL);
+ else
return 0;
return 1;
case attr_label:
if (pro == projection_none)
return 0;
- if (mr->item.type == type_route_start || mr->item.type == type_route_end) {
+ 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)
+ 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;
struct map_rect_priv *mr = priv_data;
struct route_graph_point *p = mr->point;
struct route_graph_segment *seg = mr->rseg;
+ struct route *route=mr->mpriv->route;
+
+ attr->type=attr_type;
switch (attr_type) {
case attr_any: // works only with rg_points for now
- if (mr->item.type != type_rg_point)
- return 0;
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_label:
+ mr->attr_next=attr_street_item;
if (mr->item.type != type_rg_point)
return 0;
attr->type = attr_label;
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;
- mr->attr_next=attr_none;
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;
- mr->attr_next = attr_none;
if (seg) {
attr->u.num = seg->data.flags;
} else {
}
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 1;
case attr_debug:
- if (mr->item.type != type_rg_point)
- return 0;
- 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;
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;
if (mr->coord_sel) {
// We are supposed to return only the point at one specified coordinate...
if (!p) {
- p = r->graph->hash[HASHCOORD(mr->coord_sel)];
- while ((p) && ((p->c.x != mr->coord_sel->x) || (p->c.y != mr->coord_sel->y))) {
- p = p->hash_next;
- }
- if ((!p) || !((p->c.x == mr->coord_sel->x) && (p->c.y == mr->coord_sel->y))) {
+ 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);
p = NULL;
}
} else {
- if (!p)
- p = r->graph->route_points;
- else
- p = p->next;
+ 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;
static struct item *
rm_get_item(struct map_rect_priv *mr)
{
+ struct route *route=mr->mpriv->route;
dbg(1,"enter\n", mr->pos);
switch (mr->item.type) {
case type_none:
- mr->item.type=type_route_start;
- if (mr->mpriv->route->pos)
+ 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;
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)
{
{
}
-void
-route_add_callback(struct route *this_, struct callback *cb)
+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)
{
- callback_list_add(this_->cbl, cb);
+ switch (attr->type) {
+ case attr_callback:
+ dbg(1,"add\n");
+ callback_list_add(this_->cbl2, attr->u.callback);
+ return 1;
+ default:
+ return 0;
+ }
}
-void
-route_remove_callback(struct route *this_, struct callback *cb)
+int
+route_remove_attr(struct route *this_, struct attr *attr)
{
- callback_list_remove(this_->cbl, cb);
+ 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);
}
+