diff options
Diffstat (limited to 'navit/route.c')
-rw-r--r-- | navit/route.c | 1780 |
1 files changed, 1780 insertions, 0 deletions
diff --git a/navit/route.c b/navit/route.c new file mode 100644 index 000000000..f8082b98d --- /dev/null +++ b/navit/route.c @@ -0,0 +1,1780 @@ +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if 0 +#include <math.h> +#include <assert.h> +#include <unistd.h> +#include <sys/time.h> +#endif +#include <glib.h> +#include "config.h" +#include "debug.h" +#include "profile.h" +#include "coord.h" +#include "projection.h" +#include "map.h" +#include "mapset.h" +#include "item.h" +#include "route.h" +#include "track.h" +#include "point.h" +#include "graphics.h" +#include "transform.h" +#include "plugin.h" +#include "fib.h" + + +struct map_priv { + struct route *route; +}; + +int debug_route=0; + +struct route_graph_point { + struct route_graph_point *next; + struct route_graph_point *hash_next; + struct route_graph_segment *start; + struct route_graph_segment *end; + struct route_graph_segment *seg; + struct fibheap_el *el; + int value; + struct coord c; +}; + +struct route_graph_segment { + struct route_graph_segment *next; + struct route_graph_segment *start_next; + struct route_graph_segment *end_next; + struct route_graph_point *start; + struct route_graph_point *end; + struct item item; + int flags; + int len; + int offset; +}; + +struct route_path_segment { + struct route_path_segment *next; + struct item item; + unsigned int offset; +#if 0 + int time; +#endif + int length; + int dir; + unsigned ncoords; + struct coord c[0]; +}; + +struct route_info { + struct coord c; + struct coord lp; + int pos; + + int dist; + int dir; + + struct street_data *street; +}; + +struct route_path { + struct route_path_segment *path; + struct route_path_segment *path_last; + /* XXX: path_hash is not necessery now */ + struct item_hash *path_hash; +}; + +#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) + +struct route { + int version; + struct mapset *ms; + unsigned flags; + struct route_info *pos; + struct route_info *dst; + + struct route_graph *graph; + struct route_path *path2; + struct map *map; + struct map *graph_map; + int speedlist[route_item_last-route_item_first+1]; +}; + +struct route_graph { + struct route_graph_point *route_points; + struct route_graph_segment *route_segments; +#define HASH_SIZE 8192 + struct route_graph_point *hash[HASH_SIZE]; +}; + +#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); +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_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 enum projection route_projection(struct route *route) +{ + struct street_data *street; + street = route->pos ? route->pos->street : route->dst->street; + return map_projection(street->item.map); +} + +static void +route_path_destroy(struct route_path *this) +{ + struct route_path_segment *c,*n; + if (! this) + return; + if (this->path_hash) { + item_hash_destroy(this->path_hash); + this->path_hash=NULL; + } + c=this->path; + while (c) { + n=c->next; + g_free(c); + c=n; + } + g_free(this); +} + +struct route * +route_new(struct attr **attrs) +{ + struct route *this=g_new0(struct route, 1); + if (!this) { + printf("%s:Out of memory\n", __FUNCTION__); + return NULL; + } + return this; +} + +void +route_set_mapset(struct route *this, struct mapset *ms) +{ + this->ms=ms; +} + +struct mapset * +route_get_mapset(struct route *this) +{ + return this->ms; +} + +struct route_info * +route_get_pos(struct route *this) +{ + return this->pos; +} + +struct route_info * +route_get_dst(struct route *this) +{ + return this->dst; +} + +int * +route_get_speedlist(struct route *this) +{ + return this->speedlist; +} + +int +route_get_path_set(struct route *this) +{ + return this->path2 != NULL; +} + +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; +} + +int +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); +} + +static void +route_path_update(struct route *this) +{ + struct route_path *oldpath = NULL; + if (! this->pos || ! this->dst) { + route_path_destroy(this->path2); + this->path2 = NULL; + return; + } + /* the graph is destroyed when setting the destination */ + if (this->graph && this->pos && this->dst && this->path2) { + // we can try to update + oldpath = 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); + } +} + +void +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); + dbg(1,"this->pos=%p\n", this->pos); + if (! this->pos) + return; + if (this->dst) + route_path_update(this); +} + +void +route_set_position_from_tracking(struct route *this, struct tracking *tracking) +{ + struct coord *c; + struct route_info *ret; + + dbg(2,"enter\n"); + c=tracking_get_pos(tracking); + ret=g_new0(struct route_info, 1); + if (!ret) { + printf("%s:Out of memory\n", __FUNCTION__); + return; + } + if (this->pos) + route_info_free(this->pos); + this->pos=NULL; + ret->c=*c; + ret->lp=*c; + ret->pos=tracking_get_segment_pos(tracking); + ret->dist=0; + ret->dir=0; + ret->street=street_data_dup(tracking_get_street_data(tracking)); + 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); + dbg(2,"ret\n"); +} + +/* Used for debuging of route_rect, what routing sees */ +struct map_selection *route_selection; + +struct map_selection * +route_rect(int order, struct coord *c1, struct coord *c2, int rel, int abs) +{ + int dx,dy,sx=1,sy=1,d,m; + struct map_selection *sel=g_new(struct map_selection, 1); + if (!sel) { + printf("%s:Out of memory\n", __FUNCTION__); + return sel; + } + sel->order[layer_town]=0; + sel->order[layer_poly]=0; + sel->order[layer_street]=order; + dbg(1,"%p %p\n", c1, c2); + dx=c1->x-c2->x; + dy=c1->y-c2->y; + if (dx < 0) { + sx=-1; + sel->u.c_rect.lu.x=c1->x; + sel->u.c_rect.rl.x=c2->x; + } else { + sel->u.c_rect.lu.x=c2->x; + sel->u.c_rect.rl.x=c1->x; + } + if (dy < 0) { + sy=-1; + sel->u.c_rect.lu.y=c2->y; + sel->u.c_rect.rl.y=c1->y; + } else { + sel->u.c_rect.lu.y=c1->y; + sel->u.c_rect.rl.y=c2->y; + } + if (dx*sx > dy*sy) + d=dx*sx; + else + d=dy*sy; + 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; + sel->u.c_rect.rl.y-=m; + sel->next=NULL; + return sel; +} + +static struct map_selection * +route_calc_selection(struct coord *c1, struct coord *c2) +{ + struct map_selection *ret,*sel; + sel=route_rect(4, c1, c2, 25, 0); + ret=sel; + sel->next=route_rect(8, c1, c1, 0, 40000); + sel=sel->next; + sel->next=route_rect(18, c1, c1, 0, 10000); + sel=sel->next; + sel->next=route_rect(8, c2, c2, 0, 40000); + sel=sel->next; + sel->next=route_rect(18, c2, c2, 0, 10000); + /* route_selection=ret; */ + return ret; +} + +static void +route_free_selection(struct map_selection *sel) +{ + struct map_selection *next; + while (sel) { + next=sel->next; + g_free(sel); + sel=next; + } +} + + + +void +route_set_destination(struct route *this, struct pcoord *dst) +{ + 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); + profile(1,"find_nearest_street"); + route_graph_destroy(this->graph); + this->graph=NULL; + route_path_update(this); + profile(0,"end"); +} + +static struct route_graph_point * +route_graph_get_point(struct route_graph *this, struct coord *c) +{ + struct route_graph_point *p; + int hashval=HASHCOORD(c); + p=this->hash[hashval]; + while (p) { + if (p->c.x == c->x && p->c.y == c->y) + return p; + p=p->hash_next; + } + return NULL; +} + + +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; + } + return p; +} + + +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; + } + this->route_points=NULL; + memset(this->hash, 0, sizeof(this->hash)); +} + +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) +{ + struct route_graph_segment *s; + s = g_new0(struct route_graph_segment, 1); + if (!s) { + printf("%s:Out of memory\n", __FUNCTION__); + return; + } + s->start=start; + s->start_next=start->start; + start->start=s; + s->end=end; + s->end_next=end->end; + end->end=s; + g_assert(len >= 0); + s->len=len; + s->item=*item; + s->flags=flags; + s->offset = offset; + s->next=this->route_segments; + this->route_segments=s; + if (debug_route) + printf("l (0x%x,0x%x)-(0x%x,0x%x)\n", start->c.x, start->c.y, end->c.x, end->c.y); +} + +static int get_item_seg_coords(struct item *i, struct coord *c, int max, + struct route_graph_segment *rgs) +{ + struct map_rect *mr; + struct item *item; + int rc = 0, fs = 0, p = 0; + struct coord c1; + mr=map_rect_new(i->map, NULL); + if (!mr) + return 0; + item = map_rect_get_item_byid(mr, i->id_hi, i->id_lo); + if (item) { + do { + rc = item_coord_get(item, &c1, 1); + if (rc) { + if (!fs) { + if (c1.x == rgs->start->c.x && + c1.y == rgs->start->c.y) + fs = 1; + } + if (fs) { + c[p++] = c1; + if (c1.x == rgs->end->c.x && + c1.y == rgs->end->c.y) + break; + } + } + } while (rc); + } + map_rect_destroy(mr); + return p; +} + +static struct route_path_segment * +route_extract_segment_from_path(struct route_path *path, struct item *item, + int offset) +{ + 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; + } + } + sp = s; + s = s->next; + } + if (s) + item_hash_remove(path->path_hash, item); + return s; +} + +static void +route_path_add_item(struct route_path *this, struct route_path *oldpath, + struct route_graph_segment *rgs, int len, int offset, int dir) +{ + struct route_path_segment *segment; + int ccnt = 0; + struct coord ca[2048]; + + 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; + } + } + + ccnt = get_item_seg_coords(&rgs->item, ca, 2047, rgs); + segment= g_malloc0(sizeof(*segment) + sizeof(struct coord) * ccnt); + if (!segment) { + printf("%s:Out of memory\n", __FUNCTION__); + return; + } + memcpy(segment->c, ca, ccnt * sizeof(struct coord)); + segment->ncoords = ccnt; + segment->item=rgs->item; + segment->offset = offset; +linkold: + segment->length=len; + segment->dir=dir; + segment->next=NULL; + item_hash_insert(this->path_hash, &rgs->item, (void *)offset); + if (!this->path) + this->path=segment; + if (this->path_last) + this->path_last->next=segment; + this->path_last=segment; +} + +struct route_path_handle { + struct route_path_segment *s; +}; + +struct route_path_handle * +route_path_open(struct route *this) +{ + struct route_path_handle *ret; + + if (! this->path2 || ! this->path2->path) + return NULL; + + ret=g_new(struct route_path_handle, 1); + if (!ret) { + printf("%s:Out of memory\n", __FUNCTION__); + return ret; + } + ret->s=this->path2->path; + return ret; +} + +struct route_path_segment * +route_path_get_segment(struct route_path_handle *h) +{ + struct route_path_segment *ret=h->s; + + if (ret) + h->s=ret->next; + + return ret; +} + +static struct coord * +route_path_segment_get_helper(struct route_path_segment *s, int dir) +{ + if (s->dir == dir) + return &s->c[0]; + else + return &s->c[s->ncoords-1]; +} + +struct coord * +route_path_segment_get_start(struct route_path_segment *s) +{ + return route_path_segment_get_helper(s, 1); +} + +struct coord * +route_path_segment_get_end(struct route_path_segment *s) +{ + return route_path_segment_get_helper(s, -1); +} + +struct item * +route_path_segment_get_item(struct route_path_segment *s) +{ + return &s->item; +} + +void +route_path_close(struct route_path_handle *h) +{ + g_free(h); +} + +static void +route_graph_free_segments(struct route_graph *this) +{ + struct route_graph_segment *curr,*next; + curr=this->route_segments; + while (curr) { + next=curr->next; + g_free(curr); + curr=next; + } + this->route_segments=NULL; +} + +static void +route_graph_destroy(struct route_graph *this) +{ + if (this) { + route_graph_free_points(this); + route_graph_free_segments(this); + g_free(this); + } +} + +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]", item->type, route_item_first, route_item_last); + return len*36; + } + return len*36/speedlist[item->type-route_item_first]; +} + + +static int +route_value(int *speedlist, struct item *item, int len) +{ + int ret; + if (len < 0) { + printf("len=%d\n", len); + } + g_assert(len >= 0); + ret=route_time(speedlist, item, len); + dbg(1, "route_value(0x%x, %d)=%d\n", item->type, len, ret); + return ret; +} + +static void +route_process_street_graph(struct route_graph *this, struct item *item) +{ +#ifdef AVOID_FLOAT + int len=0; +#else + double len=0; +#endif + struct route_graph_point *s_pnt,*e_pnt; + struct coord c,l; + struct attr attr; + int flags = 0; + int segmented = 0; + int offset = 1; + + if (item_coord_get(item, &l, 1)) { + if (item_attr_get(item, attr_flags, &attr)) { + flags = attr.u.num; + if (flags & AF_SEGMENTED) + segmented = 1; + } + s_pnt=route_graph_add_point(this,&l); + if (!segmented) { + while (item_coord_get(item, &c, 1)) { + len+=transform_distance(map_projection(item->map), &l, &c); + l=c; + } + e_pnt=route_graph_add_point(this,&l); + g_assert(len >= 0); + route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset); + } else { + int isseg,rc; + int sc = 0; + do { + isseg = item_coord_is_segment(item); + rc = item_coord_get(item, &c, 1); + if (rc) { + len+=transform_distance(map_projection(item->map), &l, &c); + 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); + offset++; + s_pnt=route_graph_add_point(this,&l); + len = 0; + } + } + } while(rc); + e_pnt=route_graph_add_point(this,&l); + g_assert(len >= 0); + sc++; + route_graph_add_segment(this, s_pnt, e_pnt, len, item, flags, offset); + } + } +} + +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; +} + +int +route_info_length(struct route_info *pos, struct route_info *dst, int dir) +{ + struct route_info_handle *h; + struct coord *c,*l; + int ret=0; + struct street_data *street; + + dbg(2,"enter pos=%p dst=%p dir=%d\n", pos, dst, dir); + h=route_info_open(pos, dst, dir); + if (! h) { + dbg(2,"ret=-1\n"); + return -1; + } + street = pos ? pos->street : dst->street; + l=route_info_get(h); + while ((c=route_info_get(h))) { + dbg(3,"c=%p\n", c); + ret+=transform_distance(map_projection(street->item.map), c, l); + l=c; + } + dbg(2,"ret=%d\n", ret); + return ret; +} + +static void +route_graph_flood(struct route_graph *this, struct route_info *dst, int *speedlist) +{ + struct route_graph_point *p_min,*end=NULL; + struct route_graph_segment *s; + int min,new,old,val; + struct fibheap *heap; + struct street_data *sd=dst->street; + + heap = fh_makeheap(); + fh_setcmp(heap, compare); + + if (! (sd->flags & AF_ONEWAYREV)) { + end=route_graph_get_point(this, &sd->c[0]); + g_assert(end != 0); + end->value=route_value(speedlist, &sd->item, route_info_length(NULL, dst, -1)); + end->el=fh_insert(heap, end); + } + + if (! (sd->flags & AF_ONEWAY)) { + end=route_graph_get_point(this, &sd->c[sd->count-1]); + g_assert(end != 0); + end->value=route_value(speedlist, &sd->item, route_info_length(NULL, dst, 1)); + end->el=fh_insert(heap, end); + } + + dbg(1,"0x%x,0x%x\n", end->c.x, end->c.y); + for (;;) { + p_min=fh_extractmin(heap); + if (! p_min) + break; + min=p_min->value; + if (debug_route) + printf("extract p=%p free el=%p min=%d, 0x%x, 0x%x\n", p_min, p_min->el, min, p_min->c.x, p_min->c.y); + p_min->el=NULL; + s=p_min->start; + while (s) { + 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)) { + 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); + } + } + if (debug_route) + printf("\n"); + s=s->start_next; + } + s=p_min->end; + while (s) { + 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); + } + } + if (debug_route) + printf("\n"); + s=s->end_next; + } + } + fh_deleteheap(heap); +} + +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) +{ + struct route_graph_point *start1=NULL,*start2=NULL,*start; + struct route_graph_segment *s=NULL; + int len=0,segs=0; + int ilen,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; + + if (! (sd->flags & AF_ONEWAY)) { + start1=route_graph_get_point(this, &sd->c[0]); + if (! start1) + return NULL; + val1=start1->value+route_value(speedlist, &sd->item, route_info_length(pos, NULL, -1)); + dbg(1,"start1: %d(route)+%d=%d\n", start1->value, val1-start1->value, val1); + } + if (! (sd->flags & AF_ONEWAYREV)) { + start2=route_graph_get_point(this, &sd->c[sd->count-1]); + if (! start2) + return NULL; + val2=start2->value+route_value(speedlist, &sd->item, route_info_length(pos, NULL, 1)); + dbg(1,"start2: %d(route)+%d=%d\n", start2->value, val2-start2->value, val2); + } + dbg(1,"val1=%d val2=%d\n", val1, val2); + if (val1 == val2) { + val1=start1->start->start->value; + val2=start2->end->end->value; + } + if (start1 && (val1 < val2)) { + start=start1; + pos->dir=-1; + } else { + if (start2) { + start=start2; + pos->dir=1; + } else { + printf("no route found, pos blocked\n"); + return NULL; + } + } + ret=g_new0(struct route_path, 1); + if (!ret) { + printf("%s:Out of memory\n", __FUNCTION__); + return ret; + } + ret->path_hash=item_hash_new(); + dbg(1,"dir=%d\n", pos->dir); + while ((s=start->seg)) { + 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 (s->start == start) { + route_path_add_item(ret, oldpath, s, seg_len, s->offset, 1); + start=s->end; + } else { + route_path_add_item(ret, oldpath, s, seg_len, s->offset, -1); + start=s->start; + } + } + 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) + dst->dir=-1; + else if (start->c.x == sd->c[sd->count-1].x && start->c.y == sd->c[sd->count-1].y) + dst->dir=1; + else { + printf("no route found\n"); + route_path_destroy(ret); + return NULL; + } + ilen=route_info_length(pos, NULL, 0); + len+=ilen; + + ilen=route_info_length(NULL, dst, 0); + len+=ilen; + + dbg(1, "%d segments\n", segs); + return ret; +} + +static struct route_graph * +route_graph_build(struct mapset *ms, struct coord *c1, struct coord *c2) +{ + 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); + } + } + map_rect_destroy(mr); + } + mapset_close(h); + route_free_selection(sel); + + return ret; +} + +static void +route_graph_update(struct route *this) +{ + 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++; +} + +struct street_data * +street_get_data (struct item *item) +{ + int maxcount=2000; + struct coord c[maxcount]; + int count=0; + struct street_data *ret; + struct attr attr; + + while (count < maxcount) { + if (!item_coord_get(item, &c[count], 1)) + break; + count++; + } + if (count >= maxcount) { + dbg(0, "count=%d maxcount=%d id_hi=0x%x id_lo=0x%x\n", count, maxcount, item->id_hi, item->id_lo); + if (item_attr_get(item, attr_debug, &attr)) + dbg(0,"debug='%s'\n", attr.u.str); + } + g_assert(count < maxcount); + ret=g_malloc(sizeof(struct street_data)+count*sizeof(struct coord)); + ret->item=*item; + ret->count=count; + if (item_attr_get(item, attr_flags, &attr)) + ret->flags=attr.u.num; + else + ret->flags=0; + memcpy(ret->c, c, count*sizeof(struct coord)); + + return ret; +} + +struct street_data * +street_data_dup(struct street_data *orig) +{ + struct street_data *ret; + int size=sizeof(struct street_data)+orig->count*sizeof(struct coord); + + ret=g_malloc(size); + memcpy(ret, orig, size); + + return ret; +} + +void +street_data_free(struct street_data *sd) +{ + g_free(sd); +} + +static struct route_info * +route_find_nearest_street(struct mapset *ms, struct pcoord *pc) +{ + struct route_info *ret=NULL; + int max_dist=1000; + struct map_selection *sel; + int dist,pos; + struct mapset_handle *h; + struct map *m; + struct map_rect *mr; + struct item *item; + struct coord lp; + struct street_data *sd; + 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); + h=mapset_open(ms); + while ((m=mapset_next(h,1))) { + 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); + } + 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) { + sd=street_get_data(item); + dist=transform_distance_polyline_sq(sd->c, sd->count, &c, &lp, &pos); + if (!ret || dist < ret->dist) { + if (ret) { + 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; + ret->dist=dist; + ret->dir=0; + ret->street=sd; + dbg(1,"dist=%d id 0x%x 0x%x pos=%d\n", dist, item->id_hi, item->id_lo, pos); + } else + street_data_free(sd); + } + } + map_rect_destroy(mr); + } + mapset_close(h); + map_selection_destroy(sel); + + return ret; +} + +void +route_info_free(struct route_info *inf) +{ + if (inf->street) + street_data_free(inf->street); + g_free(inf); +} + + +#include "point.h" + +struct street_data * +route_info_street(struct route_info *rinf) +{ + return rinf->street; +} + +struct coord * +route_info_point(struct route_info *rinf, int point) +{ + struct street_data *sd=rinf->street; + int dir; + + switch(point) { + case -1: + case 2: + dir=(point == 2) ? rinf->dir : -rinf->dir; + if (dir > 0) + return &sd->c[sd->count-1]; + else + return &sd->c[0]; + case 0: + return &rinf->c; + case 1: + return &rinf->lp; + } + return NULL; + +} + +struct route_info_handle { + struct route_info *start; + struct route_info *curr; + struct route_info *end; + struct coord *last; + int count; + int iter; + int pos; + int endpos; + int dir; +}; + +struct route_info_handle * +route_info_open(struct route_info *start, struct route_info *end, int dir) +{ + struct route_info_handle *ret=g_new0(struct route_info_handle, 1); + struct route_info *curr; + dbg(2,"enter start=%p end=%p dir=%d\n", start, end, dir); + if (!ret) { + printf("%s:Out of memory\n", __FUNCTION__); + return ret; + } + ret->start=start; + ret->end=end; + if (start) + curr=start; + else + curr=end; + ret->endpos=-2; + if (start && end) { + if (start->street->item.map != end->street->item.map || start->street->item.id_hi != end->street->item.id_hi || start->street->item.id_lo != end->street->item.id_lo) { + dbg(1,"return NULL\n"); + return NULL; + } + printf("trivial start=%d end=%d start dir %d end dir %d\n", start->pos, end->pos, start->dir, end->dir); + if (start->pos == end->pos) { + printf("fixme\n"); + start->dir=0; + end->dir=0; + } + if (start->pos > end->pos) { + printf("fixme\n"); + start->dir=-1; + end->dir=1; + } + if (start->pos < end->pos) { + printf("fixme\n"); + start->dir=1; + end->dir=-1; + } + printf("trivial now start=%d end=%d start dir %d end dir %d\n", start->pos, end->pos, start->dir, end->dir); + ret->endpos=end->pos; + } + + if (!dir) + dir=curr->dir; + dbg(2,"dir=%d\n", dir); + ret->dir=dir; + ret->curr=curr; + ret->pos=curr->pos; + if (dir > 0) { + ret->pos++; + ret->endpos++; + } + dbg(2,"ret=%p\n",ret); + return ret; +} + +struct coord * +route_info_get(struct route_info_handle *h) +{ + struct coord *new; + for (;;) { + new=NULL; + dbg(1,"iter=%d\n", h->iter); + switch(h->iter) { + case 0: + if (h->start) { + new=&h->start->c; + h->iter++; + break; + } else { + h->iter=2; + continue; + } + case 1: + new=&h->start->lp; + h->iter++; + break; + case 2: + dbg(1,"h->pos=%d\n", h->pos); + if (h->dir && h->pos >= 0 && h->pos < h->curr->street->count && (h->end == NULL || h->endpos!=h->pos)) { + new=&h->curr->street->c[h->pos]; + h->pos+=h->dir; + } else { + h->iter++; + continue; + } + break; + case 3: + if (h->end) { + new=&h->end->lp; + h->iter++; + break; + } + break; + case 4: + new=&h->end->c; + h->iter++; + break; + + } + if (new) { + dbg(1,"new=%p (0x%x,0x%x) last=%p\n", new, new->x, new->y, h->last); + if (h->last && new->x == h->last->x && new->y == h->last->y) + continue; + h->last=new; + return new; + } + return NULL; + } +} + +void +route_info_close(struct route_info_handle *h) +{ + g_free(h); +} + + +#if 0 +struct route_crossings * +route_crossings_get(struct route *this, struct coord *c) +{ + struct route_point *pnt; + struct route_segment *seg; + int crossings=0; + struct route_crossings *ret; + + pnt=route_graph_get_point(this, c); + seg=pnt->start; + while (seg) { + printf("start: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo); + crossings++; + seg=seg->start_next; + } + seg=pnt->end; + while (seg) { + printf("end: 0x%x 0x%x\n", seg->item.id_hi, seg->item.id_lo); + crossings++; + seg=seg->end_next; + } + ret=g_malloc(sizeof(struct route_crossings)+crossings*sizeof(struct route_crossing)); + ret->count=crossings; + return ret; +} +#endif + + +struct map_rect_priv { + struct route_info_handle *ri; + enum attr_type attr_next; + int pos_next; + int pos; + struct map_priv *mpriv; + struct item item; + struct item *sitem; + int length; + unsigned int last_coord; + struct route_path_segment *seg; + struct route_graph_point *point; + struct route_graph_segment *rseg; + char *str; +}; + +static void +rm_coord_rewind(void *priv_data) +{ + struct map_rect_priv *mr = priv_data; + mr->last_coord = 0; +} + +static void +rm_attr_rewind(void *priv_data) +{ + struct map_rect_priv *mr = priv_data; + mr->attr_next = attr_street_item; +} + +static int +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; + attr->type=attr_type; + switch (attr_type) { + case attr_any: + while (mr->attr_next != attr_none) { + if (rm_attr_get(priv_data, mr->attr_next, attr)) + return 1; + } + return 0; + case attr_street_item: + if (seg) + attr->u.item=&seg->item; + else + attr->u.item=mr->sitem; + mr->attr_next=attr_length; + return 1; + case attr_length: + if (seg) + attr->u.num=seg->length; + else + attr->u.num=mr->length; + mr->attr_next=attr_time; + return 1; + case attr_time: + if (seg) + attr->u.num=route_time(route->speedlist, &seg->item, seg->length); + else + attr->u.num=route_time(route->speedlist, mr->sitem, mr->length); + mr->attr_next=attr_none; + return 1; + default: + attr->type=attr_none; + return 0; + } + return 0; +} + +static int +rm_coord_get(void *priv_data, struct coord *c, int count) +{ + struct map_rect_priv *mr = priv_data; + struct route_path_segment *seg = mr->seg; + struct coord *c1; + int rc = 0,i; + dbg(1,"pos=%d seg=%p\n", mr->pos, seg); + switch (mr->pos) { + case -1: + for (i=0; i < count; i++) { + if ((c1=route_info_get(mr->ri))) { + c[i]=*c1; + rc++; + } + } + break; + case 0: + for (i=0; i < count; i++) { + if (mr->last_coord >= seg->ncoords) + break; + if (i >= seg->ncoords) + break; + if (seg->dir < 0) + c[i] = seg->c[seg->ncoords-++mr->last_coord]; + else + c[i] = seg->c[mr->last_coord++]; + rc++; + } + break; + case 1: + for (i=0; i < count; i++) { + if ((c1=route_info_get(mr->ri))) { + c[i]=*c1; + rc++; + } + } + break; + default: + rc=0; + } + dbg(1,"return %d\n",rc); + return rc; +} + +static struct item_methods methods_route_item = { + rm_coord_rewind, + rm_coord_get, + rm_attr_rewind, + rm_attr_get, +}; + +static void +rp_attr_rewind(void *priv_data) +{ + struct map_rect_priv *mr = priv_data; + mr->attr_next = attr_label; +} + +static int +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; + switch (attr_type) { + case attr_any: + while (mr->attr_next != attr_none) { + if (rm_attr_get(priv_data, mr->attr_next, attr)) + return 1; + } + case attr_label: + attr->type = attr_label; + if (mr->str) + g_free(mr->str); + if (p->value != INT_MAX) + mr->str=g_strdup_printf("%d", p->value); + else + mr->str=g_strdup("-"); + attr->u.str = mr->str; + mr->attr_next=attr_none; + return 1; + case attr_debug: + attr->type = attr_debug; + 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; + default: + return 0; + } +} + +static int +rp_coord_get(void *priv_data, struct coord *c, int count) +{ + struct map_rect_priv *mr = priv_data; + struct route_graph_point *p = mr->point; + struct route_graph_segment *seg = mr->rseg; + int rc = 0,i; + for (i=0; i < count; i++) { + if (mr->item.type == type_rg_point) { + if (mr->last_coord >= 1) + break; + c[i] = p->c; + } else { + if (mr->last_coord >= 2) + break; + if (mr->last_coord) + c[i] = seg->end->c; + else + c[i] = seg->start->c; + } + mr->last_coord++; + rc++; + } + return rc; +} + +static struct item_methods methods_point_item = { + rm_coord_rewind, + rp_coord_get, + rp_attr_rewind, + rp_attr_get, +}; + +static void +rm_destroy(struct map_priv *priv) +{ + g_free(priv); +} + +static struct map_rect_priv * +rm_rect_new(struct map_priv *priv, struct map_selection *sel) +{ + struct map_rect_priv * mr; + dbg(1,"enter\n"); + if (! route_get_pos(priv->route)) + return NULL; + if (! route_get_dst(priv->route)) + return NULL; + if (! priv->route->path2) + return NULL; + mr=g_new0(struct map_rect_priv, 1); + mr->mpriv = priv; + mr->ri=route_info_open(route_get_pos(priv->route), route_get_dst(priv->route), 0); + mr->pos_next=1; + mr->sitem=&(route_get_pos(priv->route)->street->item); + mr->item.priv_data = mr; + mr->item.type = type_street_route; + mr->item.meth = &methods_route_item; + if (mr->ri) { + mr->length=route_info_length(route_get_pos(priv->route), route_get_dst(priv->route), 0); + } else { + mr->ri=route_info_open(route_get_pos(priv->route), NULL, 0); + mr->length=route_info_length(route_get_pos(priv->route), NULL, 0); + mr->pos_next=-1; + } + return mr; +} + +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) + 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; + return mr; +} + +static void +rm_rect_destroy(struct map_rect_priv *mr) +{ + if (mr->ri) + route_info_close(mr->ri); + if (mr->str) + g_free(mr->str); + g_free(mr); +} + +static struct item * +rp_get_item(struct map_rect_priv *mr) +{ + struct route *r = mr->mpriv->route; + struct route_graph_point *p = mr->point; + 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 (p) { + mr->point = p; + mr->item.id_lo++; + rm_coord_rewind(mr); + rp_attr_rewind(mr); + return &mr->item; + } else + mr->item.type = type_rg_segment; + } + if (!seg) + seg=r->graph->route_segments; + else + seg=seg->next; + if (seg) { + mr->rseg = seg; + mr->item.id_lo++; + rm_coord_rewind(mr); + rp_attr_rewind(mr); + return &mr->item; + } + return NULL; + +} + +static struct item * +rp_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo) +{ + struct item *ret=NULL; + while (id_lo-- > 0) + ret=rp_get_item(mr); + return ret; +} + + +static struct item * +rm_get_item(struct map_rect_priv *mr) +{ + struct route *r = mr->mpriv->route; + struct route_path_segment *seg = mr->seg; + dbg(1,"enter\n", mr->pos); + + mr->pos=mr->pos_next; + switch(mr->pos) { + case -1: + mr->pos_next=0; + break; + case 0: + if (!seg) + seg = r->path2->path; + else + seg = seg->next; + if (seg) { + mr->sitem = &seg->item; + break; + } + mr->pos=1; + route_info_close(mr->ri); + mr->ri=route_info_open(NULL, route_get_dst(r), 0); + mr->sitem=&(route_get_dst(r)->street->item); + mr->length=route_info_length(NULL, route_get_dst(r), 0); + case 1: + mr->pos_next=2; + break; + case 2: + return NULL; + } + mr->seg = seg; + mr->last_coord = 0; + mr->item.id_lo++; + rm_attr_rewind(mr); + return &mr->item; +} + +static struct item * +rm_get_item_byid(struct map_rect_priv *mr, int id_hi, int id_lo) +{ + struct item *ret=NULL; + while (id_lo-- > 0) + ret=rm_get_item(mr); + return ret; +} + +static struct map_methods route_meth = { + projection_mg, + NULL, + rm_destroy, + rm_rect_new, + rm_rect_destroy, + rm_get_item, + rm_get_item_byid, + NULL, + NULL, + NULL, +}; + +static struct map_methods route_graph_meth = { + projection_mg, + NULL, + rm_destroy, + rp_rect_new, + rm_rect_destroy, + rp_get_item, + rp_get_item_byid, + NULL, + NULL, + 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) +{ + struct map_priv *ret; + struct attr *route_attr; + + route_attr=attr_search(attrs, NULL, attr_route); + if (! route_attr) + return NULL; + ret=g_new0(struct map_priv, 1); + if (graph) + *meth=route_graph_meth; + else + *meth=route_meth; + ret->route=route_attr->u.route; + + return ret; +} + +static struct map_priv * +route_map_new(struct map_methods *meth, struct attr **attrs) +{ + return route_map_new_helper(meth, attrs, 0); +} + +static struct map_priv * +route_graph_map_new(struct map_methods *meth, struct attr **attrs) +{ + return route_map_new_helper(meth, attrs, 1); +} + +static struct map * +route_get_map_helper(struct route *this_, struct map **map, char *type) +{ + struct attr route_attr; + struct attr data_attr; + struct attr *attrs_route[]={&route_attr, &data_attr, NULL}; + route_attr.type=attr_route; + route_attr.u.route=this_; + data_attr.type=attr_data; + data_attr.u.str=""; + + if (! *map) + *map=map_new(type,attrs_route); + return *map; +} + +struct map * +route_get_map(struct route *this_) +{ + return route_get_map_helper(this_, &this_->map, "route"); +} + + +struct map * +route_get_graph_map(struct route *this_) +{ + return route_get_map_helper(this_, &this_->graph_map, "route_graph"); +} + +void +route_set_projection(struct route *this_, enum projection pro) +{ +} + +void +route_init(void) +{ + plugin_register_map_type("route", route_map_new); + plugin_register_map_type("route_graph", route_graph_map_new); +} |