/*************************************************************************** * routing.c * * Copyright 2011 - Steffen Pohle * steffen@gulpe.de ****************************************************************************/ #include #include "osmroute.h" #include "gps.h" #include "routing.h" #include "system.h" #include "memoryleak.h" #include "map.h" #include "vector.h" struct rtdata *route = NULL; void route_free (struct rtdata *rt); struct rtdata *route_alloc (struct rtdata *rt, int max, int stmax); void route_calc (struct rtdata *r); void route_onway (struct rtdata *r); int route_checkway (struct rtdata *r, struct rtway *rtw); int route_calc_way (struct rtdata *r, struct rtway *rtw, struct map_way *mw, struct rtway *rtwnew, struct map_way *mwnew); int route_optway (struct rtdata *r, struct rtway *rtw); int route_optrefsconnectways (struct rtdata *r, struct rtrefway from, struct rtrefway to, struct rtref *ref); void route_optrefs (struct rtdata *r, struct rtref *ref); struct rtwaylist *route_getstack (struct rtdata *r, int waytype); int rtl_find (struct rtwaylist *rtl, struct rtwayid *id); int rtl_realloc (struct rtwaylist *rtl, int max); int rtl_fifo_push (struct rtwaylist *rtl, struct rtway *rtw); int rtl_lifo_push (struct rtwaylist *rtl, struct rtway *rtw); int rtl_pop (struct rtwaylist *rtl, struct rtway *rtw); int rtl_addsorted (struct rtwaylist *rtl, struct rtway *rtw); void rtl_debug (struct rtwaylist *rtl); void rtl_delete (struct rtwaylist *rtl, int nr); void rtrlrefs_alloc (struct rtreflist *rtrl, int cnt); void rtrl_addway (struct rtdata *r, struct rtreflist *rtrl, struct map_way *mw); void rtrl_addwayname (struct rtdata *r, struct rtreflist *rtrl, struct map_way *mw, char *name); void rtrefways_realloc (struct rtref *rtref, int cnt); void rtrl_recalculate (struct rtdata *r, struct map_way *mw, struct rtwayid from); /**************************************************************************** * references and names ways */ void rtrlrefs_alloc (struct rtreflist *rtrl, int cnt) { int i; if (rtrl == NULL) return; if (cnt == 0) { /* free all data */ for (i = 0; i < rtrl->cnt && rtrl->refs != NULL; i++) { if (rtrl->refs[i].ways) ml_free (rtrl->refs[i].ways); rtrl->refs[i].ways = NULL; } if (rtrl->refs) ml_free (rtrl->refs); rtrl->refs = NULL; rtrl->max = 0; rtrl->cnt = 0; } else if (cnt <= rtrl->max) return; else { /* allocate more memory */ rtrl->refs = (struct rtref *) ml_realloc (rtrl->refs, cnt * sizeof (struct rtref)); for (i = rtrl->cnt; i < cnt; i++) { /* clear reset data */ rtrl->refs[i].refname[0] = 0; rtrl->refs[i].cnt = 0; rtrl->refs[i].max = 0; rtrl->refs[i].ways = NULL; rtrl->refs[i].lastnr = 0; } rtrl->max = cnt; } }; /* add the giving way to the stack list, before check for double entry and * set the priority to 0 */ void rtrl_recalculate (struct rtdata *r, struct map_way *mw, struct rtwayid from) { int nr, i; struct rtwaylist *stack; struct rtwayid wid; struct rtway rtw; if (mw == NULL) { d_printf ("%s:%d %s: mw == NULL abort", __FILE__, __LINE__, __FUNCTION__); return; } wid.id = mw->id; wid.sid = mw->subid; wid.type = mw->type; /* check if this way is already calculated.. */ stack = &r->ways; if ((nr = rtl_find (stack, &wid)) >= 0) { d_printf ("%s:%d mw[%lld:%d] is already calculated.", __FILE__, __LINE__, wid.id, wid.sid); return; } /* find this way inside the stacks to set the priority to 0.0 */ stack = route_getstack (r, wid.type); if ((nr = rtl_find (stack, &wid)) >= 0) { rtw = stack->array[nr]; rtl_delete (stack, nr); rtw.priority = 0.0; rtw.cycle2 = r->cycle; } /* rtw has to be created from the begining */ else { /* search from inside n */ for (i = mw->n_cnt-1; (i >= 0 && (from.id != mw->n[i].d_id || from.sid != mw->n[i].d_subid)); i--); rtw.way = wid; rtw.pos = mw->p[0]; if (i >= 0) rtw.pnr = mw->n[i].pnr; else rtw.pnr = -1; rtw.dist2dest = -1.0; rtw.dist2pos = -1.0; rtw.step = -1; /* indicate we know nothing.. just need this on top of the list.. * so it will be ignored as long as there is nothing known .. */ rtw.priority = 0.0; rtw.cycle1 = r->cycle; rtw.cycle2 = r->cycle; rtw.deltadist = 0.0; } rtl_addsorted (stack, &rtw); }; /* add reference to the list of references, also recheck if we have two not * connected references, abort at 1.5times distance */ #define RTRL_MAXWAYS 512 void rtrl_addwayname (struct rtdata *r, struct rtreflist *rtrl, struct map_way *mw, char *name) { int ir; // index refnames int nr; // segment number int i, n; struct rtref *ref; // pointer to reference data // static struct rtwayid _rtrl_wlist [RTRL_MAXWAYS]; // only create this once, saves time.. int _rtrl_wlist_cnt = 0; // re-init with zero elements d_printf (" rtrl_addwayname '%s' id:%lld:%d mw->ref:%s", name, mw->id, mw->subid, mw->ref); for (ir = rtrl->cnt; (ir >= 0 && strcmp (name, rtrl->refs[ir].refname) != 0); ir--); if (ir < 0) { /* nothing found add new reference */ if (rtrl->cnt >= rtrl->max || rtrl->refs) rtrlrefs_alloc (rtrl, rtrl->max + RT_ALLOCREFS); ref = &rtrl->refs[rtrl->cnt]; strncpy (ref->refname, name, MAP_W_NAMELEN); rtrl->cnt++; } else { ref = &rtrl->refs[ir]; } /* add to ref the right way.. * first check if we have one big segment or if we enter the road again */ for (nr = -1, i = 0; i < ref->cnt; i++) { /* check way, if found return to caller */ if (mw->id == ref->ways[i].way.id && mw->subid == ref->ways[i].way.sid) return; /* check nodes */ for (n = 0; n < mw->n_cnt; n++) { if (mw->n[n].d_id == ref->ways[i].way.id && mw->n[n].d_subid == ref->ways[i].way.sid) nr = ref->ways[i].nr; } } /* nothing found? */ if (nr < 0) { float dist = -1.0; float f; /* find closest way to current position */ d_printf (" searching way to position. cnt:%d, ref:'%s'", ref->cnt, ref->refname); for (nr = -1, i = 0; i < ref->cnt; i++) { /* search shortest distance.. */ f = map_way_getdistance (mw, &ref->ways[i].pos, NULL); if (dist < 0.0 || f < dist) { dist = f; nr = i; } } /* add ways to the stacks... * as long as recalc waydist < 1.5times dist * and (mwleft || right) != &ref->ways[nr] */ if (nr >= 0) { /* go to the left and to the right until 1.5time dist */ struct map_hash *mhtmp = NULL; struct map_way *mwtmp = NULL; struct rtwayid fromdir[2]; /* 0.. left, 1.. right */ struct map_way *mwdir[2] = {NULL, NULL}; // int pnrdir[2] = {-1, -1}; /* pnr: where we entered the way */ int dir; d_printf (" found closest way nr:%d way:%lld:%d dist:%f", nr, ref->ways[nr].way.id, ref->ways[nr].way.sid, dist); /* * start checking: prepare the variables mh/mw left and right */ fromdir[0].id = fromdir[1].id = ref->ways[nr].way.id; fromdir[0].sid = fromdir[1].sid = ref->ways[nr].way.sid; mhtmp = map_hash_get (ref->ways[nr].pos.lon, ref->ways[nr].pos.lat, MHLOAD_RELOAD); mwtmp = map_way_find (mhtmp, ref->ways[nr].way.id, ref->ways[nr].way.sid); if (mwtmp == NULL) { d_printf ("%s:%d %s: could not find way: %lld:%d", __FILE__, __LINE__, __FUNCTION__, ref->ways[nr].way.id, ref->ways[nr].way.sid); return; } for (i = 0; i < mwtmp->n_cnt; i++) { struct map_hash *mhtmp1 = NULL; struct map_way *mwtmp1 = NULL; mhtmp1 = map_hash_get (mwtmp->n[i].d.lon, mwtmp->n[i].d.lat, MHLOAD_RELOAD); mwtmp1 = map_way_find (mhtmp1, mwtmp->n[i].d_id, mwtmp->n[i].d_subid); if (!mwtmp1) { d_printf ("%s:%d %s: could not find way: %lld:%d pos:%f,%f", __FILE__, __LINE__, __FUNCTION__, mwtmp->n[i].d_id, mwtmp->n[i].d_subid); return; } d_printf ("check name[%s] == [%s]", name, mwtmp1->ref); if (map_way_checkref (mwtmp1->ref, name)) { /* found way */ if (mwdir[0] == NULL) { mwdir[0]= mwtmp1; // pnrdir[0] = mwtmp->n[i].d_pnr; } else if (mwdir[1] == NULL) { mwdir[1]= mwtmp1; // pnrdir[1] = mwtmp->n[i].d_pnr; } else { d_printf ("%s:%d %s: why there are three connecting referneces? ignoring way:%lld:%d", __FILE__, __LINE__, __FUNCTION__, mw->n[i].d_id, mw->n[i].d_subid); } } } while ((mwdir[0] != NULL || mwdir[1] != NULL) && _rtrl_wlist_cnt++ < RTRL_MAXWAYS) { struct map_hash *mhtmp1 = NULL; struct map_way *mwtmp1 = NULL; for (dir = 0; dir < 2; dir++) if (mwdir[dir]) { d_printf (" mwdir[%d]: %lld:%d fromdir:%lld:%d", dir, mwdir[dir]->id, mwdir[dir]->subid, fromdir[dir].id, fromdir[dir].sid); for (i = 0; i < mwdir[dir]->n_cnt; i++) { mhtmp1 = map_hash_get (mwdir[dir]->n[i].d.lon, mwdir[dir]->n[i].d.lat, MHLOAD_RELOAD); mwtmp1 = map_way_find (mhtmp1, mwdir[dir]->n[i].d_id, mwdir[dir]->n[i].d_subid); if (!mwtmp1) { d_printf ("%s:%d %s: could not find way: %lld:%d pos:%f,%f", __FILE__, __LINE__, __FUNCTION__, mwdir[dir]->n[i].d_id, mwdir[dir]->n[i].d_subid); return; } if (map_way_checkref (mwtmp1->ref, name) && (mwtmp1->id != fromdir[dir].id || mwtmp1->subid != fromdir[dir].sid)) break; } if (i < mwdir[dir]->n_cnt) { /* found next way.. */ if (map_way_getdistance (mwtmp1, &ref->ways[nr].pos, NULL) * 1.5 < dist) { fromdir[dir].id = mwdir[dir]->id; fromdir[dir].sid = mwdir[dir]->subid; // pnrdir[dir] = mwdir[dir]->n[i].d_pnr; mwdir[dir] = mwtmp1; } else mwdir[dir] = NULL; } else mwdir[dir] = NULL; } } /* add to stack list */ for (dir = 0; dir < 2; dir++) if (mwdir[dir]) rtrl_recalculate (r, mwdir[dir], fromdir[dir]); } else d_printf (" found nothing.."); /* no connection way found... need to add new segment.. */ ref->lastnr++; nr = ref->lastnr; } /* save data */ if (ref->cnt+1 >= ref->max) rtrefways_realloc (ref, ref->max+RT_ALLOCREFS); ref->ways[ref->cnt].way.id = mw->id; ref->ways[ref->cnt].way.sid = mw->subid; ref->ways[ref->cnt].way.type = mw->type; ref->ways[ref->cnt].pos = mw->p[0]; ref->ways[ref->cnt].nr = nr; ref->cnt++; d_printf (" cnt:%d lastnr:%d nr:%d", ref->cnt, ref->lastnr, nr); }; void rtrl_addway (struct rtdata *r, struct rtreflist *rtrl, struct map_way *mw) { int i, j; char n[MAP_W_NAMELEN]; /* add name to refrence list * adding streetnames is not a good idea, exist at different locations */ // if (strlen (mw->name) > 0) rtrl_addwayname (rtrl, mw, mw->name); /* add references to reference list */ for (n[0] = 0, j = 0, i = 0; i < strlen (mw->ref); i++) { if (j >= MAP_W_NAMELEN-1) { d_printf ("%s:%d (%s) something went very wrong", __FILE__, __LINE__, __FUNCTION__); break; } if (mw->ref[i] == ';') { rtrl_addwayname (r, rtrl, mw, n); j = 0; n[0] = 0; } else if (mw->ref[i] != ' ' ) { n[j++] = mw->ref[i]; n[j] = 0; } } if (strlen (n) > 0) rtrl_addwayname (r, rtrl, mw, n); }; void rtrefways_realloc (struct rtref *rtref, int cnt) { int i; if (cnt == 0) { /* free data */ if (rtref->ways != NULL) ml_free (rtref->ways); rtref->ways = NULL; rtref->cnt = 0; rtref->max = 0; } else if (cnt < rtref->max) return; else { rtref->ways = (struct rtrefway *) ml_realloc (rtref->ways, cnt * sizeof (struct rtrefway)); for (i = rtref->max-1; i >= cnt; i--) { rtref->ways[i].way.id = 0; rtref->ways[i].way.sid = 0; rtref->ways[i].nr = -1; rtref->ways[i].pos.lon = 0.0; rtref->ways[i].pos.lat = 0.0; } rtref->max = cnt; } }; /**************************************************************************** * routing memory management */ void rtl_debug (struct rtwaylist *rtl) { int i; d_printf ("debug rtwaylist:"); d_printf ("================"); for (i = 0; i < rtl->cnt; i++) { d_printf (" %-4d: %lld:%d", i, rtl->array[i].way.id, rtl->array[i].way.sid); } }; /* * alloc or realloc data from memory */ struct rtdata *route_alloc (struct rtdata *rt, int max, int stmax) { struct rtdata *r = rt; d_printf ("route alloc: %p max:%d ig:%d sel:%d st:%d", rt, max, stmax); /* new route */ if (r == NULL) { d_printf ("route alloc: new alloc"); r = (struct rtdata *) ml_malloc (sizeof (struct rtdata)); r->pos.lon = 0.0; r->pos.lat = 0.0; r->cycle = 0; r->ways.array = NULL; r->ways.cnt = 0; r->ways.max = 0; r->stack1.array = NULL; r->stack1.cnt = 0; r->stack1.max = 0; r->stack2.array = NULL; r->stack2.cnt = 0; r->stack2.max = 0; r->stack3.array = NULL; r->stack3.cnt = 0; r->stack3.max = 0; r->route.array = NULL; r->route.cnt = 0; r->route.max = 0; r->state = ROUTING_NONE; r->reflist.cnt = 0; r->reflist.refs = NULL; r->reflist.max = 0; } rtrlrefs_alloc (&r->reflist, RT_ALLOCREFS); rtl_realloc (&r->ways, max); rtl_realloc (&r->stack1, stmax); rtl_realloc (&r->stack2, stmax); rtl_realloc (&r->stack3, stmax); r->stack1.array[0].priority = 0.0; r->stack2.array[0].priority = 0.0; r->stack3.array[0].priority = 0.0; r->ways.array[0].priority = 0.0; return r; }; /**************************************************************************** * routing data functions */ /* * find the given element inside the givven array */ int rtl_find (struct rtwaylist *rtl, struct rtwayid *id) { int i; for (i = rtl->cnt-1; i >= 0; i--) { if (rtl->array[i].way.id == id->id && rtl->array[i].way.sid == id->sid) break; } return i; }; /* * alloc or free memory */ int rtl_realloc (struct rtwaylist *rtl, int max) { void *ptr; d_printf ("realloc: %p, size:%d neu:%d", rtl->array, rtl->max, max); ptr = ml_realloc (rtl->array, sizeof (struct rtway) * max); if (ptr == NULL && max > 0) { d_printf ("%s:%d (%s) ptr == %p", __FILE__, __LINE__, __FUNCTION__, ptr); errorexit (-1); } rtl->array = ptr; rtl->max = max; if (rtl->max < rtl->cnt) rtl->cnt = max; return 1; }; /* * first in and first out push.. element will be put on the first place */ int rtl_fifo_push (struct rtwaylist *stack, struct rtway *rtw) { if ((stack->cnt+1) >= stack->max) rtl_realloc (stack, stack->max+RT_ALLOCSTACK); memmove (&stack->array[1], &stack->array[0], sizeof (struct rtway) * stack->cnt); stack->array[0] = *rtw; stack->cnt++; return 1; }; /* * first in and first out push.. element will be put on the first place */ int rtl_lifo_push (struct rtwaylist *stack, struct rtway *rtw) { if ((stack->cnt+1) >= stack->max) rtl_realloc (stack, stack->max+RT_ALLOCSTACK); stack->array[stack->cnt] = *rtw; stack->cnt++; return 1; }; /* * last element will be removed from list. */ int rtl_pop (struct rtwaylist *stack, struct rtway *rtw) { if (stack->cnt > 0) { stack->cnt--; *rtw = stack->array[stack->cnt]; return 1; } d_printf ("ERROR: rtl_pop() cnt==0"); return 0; }; /* * add element to the list. In sorted order. */ int rtl_addsorted (struct rtwaylist *rtl, struct rtway *rtw) { int i = 0; if (!rtl) return 0; // d_printf (" rtl_addsorted: %lld:%d", rtw->way.id, rtw->way.sid); if ((rtl->cnt+1) >= rtl->max) rtl_realloc (rtl, rtl->max+RT_ALLOCSTACK); i = 0; for (i = 0; i < rtl->cnt; i++) { if (rtl->array[i].priority < rtw->priority) break; } if (i < rtl->cnt) memmove (&rtl->array[i+1], &rtl->array[i], sizeof (struct rtway) * (rtl->cnt-i)); rtl->array[i] = *rtw; rtl->cnt++; return 1; }; /* * delete entry from the list */ void rtl_delete (struct rtwaylist *rtl, int nr) { if (nr < rtl->cnt-1 && nr >= 0 && rtl->cnt > 0) { rtl->cnt--; if (nr < rtl->cnt) memmove (&rtl->array[nr], &rtl->array[nr+1], sizeof (struct rtway) * (rtl->cnt-nr)); } }; /**************************************************************************** * routing function itself */ /* * free route data from memory */ void route_free (struct rtdata *rt) { if (rt == NULL) return; d_printf ("route free: %p", rt); rtrlrefs_alloc (&rt->reflist, 0); rtl_realloc (&rt->ways, 0); rtl_realloc (&rt->stack1, 0); rtl_realloc (&rt->stack2, 0); rtl_realloc (&rt->stack3, 0); rtl_realloc (&rt->route, 0); ml_free (rt); }; int route_calc_way (struct rtdata *r, struct rtway *rtw, struct map_way *mw, struct rtway *rtwnew, struct map_way *mwnew) { float deltadist = 0.0; fPoint v1, v2, v3, v4; float f, ideal = 0.0; int i, step, deltastep; r->cycle++; rtwnew->cycle1 = r->cycle; rtwnew->cycle2 = -1; /* * check the distance to the ideal line, also look for the closest distacne */ v1.x = r->pos_dest.lon; v1.y = r->pos_dest.lat; for (i = 0; i < mwnew->n_cnt; i++) { v2.x = map_lon2km (r->dest.lon - mwnew->p[mwnew->n[i].pnr].lon, mwnew->p[mwnew->n[i].pnr].lat); v2.y = map_lat2km (r->dest.lat - mwnew->p[mwnew->n[i].pnr].lat); v3 = vec_normale (v1, v2); /* check if the normale vector is on the v1 vector, * if not we just get the distance */ if (((v3.x <= 0.0 && v1.x <= 0.0) || (v3.x >= 0.0 && v1.x >= 0.0) || (v3.y <= 0.0 && v1.y <= 0.0) || (v3.y >= 0.0 && v1.y >= 0.0)) && fabs(v3.x) <= fabs(v1.x) && fabs(v3.y) <= fabs(v1.y)) { v4 = vec_sub (v3, v2); f = sqrt (v4.x * v4.x + v4.y * v4.y); } else f = sqrt (v2.x * v2.x + v2.y * v2.y); /* check ideal */ if (f < ideal || i == 0) ideal = f; ideal = fabsf (ideal); f = map_getdistance (mwnew->p[mwnew->n[i].pnr], r->pos); /* check distance */ if (f < r->closest_distance || r->closest_distance < 0.0) { // for debugging and status information r->closest_distance = f; r->closest_lon = mwnew->p[0].lon; r->closest_lat = mwnew->p[0].lat; } if (f < rtwnew->dist2pos || i == 0) { rtwnew->dist2pos = f; } } /* * calculate the delta between distance on this way since start (deltaway) * calculate delta step and calculate delta distance to dest. (deltadist) */ deltadist = rtwnew->dist2pos - rtw->dist2pos; rtwnew->deltadist = deltadist; deltastep = rtwnew->step - rtw->step; if (deltastep) { step = rtw->step; } else { step = rtw->step-1; } /* * calclating priority */ // until now the best way to calculate.. // rtwnew->priority = (powf (1.0 + 4.0 * ideal, 2.0) + powf (1.0 + rtwnew->dist2pos, 2.0) + rtwnew->dist2dest) * (1.0 + step/5.0); rtwnew->priority = (powf (1.0 + 4.0 * ideal, 2.0) + powf (1.0 + rtwnew->dist2pos, 2.0) + rtwnew->dist2dest) * (1.0 + step/5.0); if (isinf(rtwnew->priority) || isnan(rtwnew->priority)) { rtwnew->priority = fabsf (rtw->priority)*0.9; } /* * only a way no connection nodes.. check this route right away */ if ((mwnew->n_cnt <= 2 && mwnew->p_cnt < 2) || deltadist == 0.0 || (mwnew->flags & MWAY_F_junction)) { rtwnew->priority = 0.0; } return 1; }; int route_checkway (struct rtdata *r, struct rtway *rtw) { struct map_hash *mh = map_hash_get (rtw->pos.lon, rtw->pos.lat, MHLOAD_RELOAD); struct map_way *mw = map_way_find (mh, rtw->way.id, rtw->way.sid); struct map_hash *mhto; struct map_way *mwto; struct rtway rtwnew, *rtwtmp; struct rtwaylist *rtltmp; int i, j, nr, w; // d_printf ("route_checkway: rtw:%lld:%d step:%d dist2pos:%g priority:%g", rtw->way.id, rtw->way.sid, rtw->step, rtw->dist2pos, rtw->priority); r->cycle++; rtw->cycle2 = r->cycle; if (mw == NULL) { d_printf ("%s: could not find the way with id: %lld:%d at %f,%f", __FUNCTION__, rtw->way.id, rtw->way.sid, rtw->pos.lon, rtw->pos.lat); return 0; } /* ignore the following ways */ if (mw->type == MWAY_railway) return 0; if (mw->type == MWAY_unknown_railway) return 0; if (mw->type == MWAY_cycleway) return 0; if (mw->type == MWAY_footway) return 0; if (mw->type == MWAY_service) return 0; // d_printf (" way %lld:%d pnr:%d name:%s ref:%s flags:%d", mw->id, mw->subid, rtw->pnr, mw->name, mw->ref, mw->flags); /* check all dnodes and add them to the list if they aren't already inside */ if ((mw->flags & (MWAY_F_oneway + MWAY_F_roundabout)) == MWAY_F_oneway) { nr = rtw->pnr; } else { nr = 0; } /* add to reference list */ rtrl_addway (r, &r->reflist, mw); for (i = 0; i < mw->n_cnt; i++) if (mw->id != mw->n[i].d_id || mw->subid != mw->n[i].d_subid) { rtwnew.way.id = mw->n[i].d_id; rtwnew.way.sid = mw->n[i].d_subid; rtwnew.pos = mw->n[i].d; rtwnew.pnr = mw->n[i].d_pnr; mhto = map_hash_get (rtwnew.pos.lon, rtwnew.pos.lat, MHLOAD_RELOAD); mwto = map_way_find (mhto, rtwnew.way.id, rtwnew.way.sid); if (mwto == NULL) { continue; } if (((mw->flags & (MWAY_F_oneway+MWAY_F_roundabout)) == MWAY_F_oneway) && ((mw->id != mwto->id && mw->n[i].pnr > nr) || (mw->id == mwto->id && mw->subid < mwto->subid))) { continue; // prevent us from going backwards on oneways } if (mwto->id == mw->id && mwto->subid == mw->subid) { continue; } /* increase step */ j = map_way_checkref (mwto->ref, mw->ref); if (rtwnew.way.id == rtw->way.id || j > 0) rtwnew.step = rtw->step; else rtwnew.step = rtw->step + 1; /* calc distance */ rtwnew.dist2dest = rtw->dist2dest; rtwnew.dist2dest += map_way_getlenght (mw, rtw->pnr, mw->n[i].pnr); route_calc_way (r, rtw, mw, &rtwnew, mwto); rtwtmp = NULL; rtltmp = NULL; if ((w = rtl_find(&r->ways, &rtwnew.way)) >= 0) { rtwtmp = &r->ways.array[w]; rtltmp = &r->ways; } else { rtltmp = route_getstack(r, mwto->type); if ((w = rtl_find(rtltmp, &rtwnew.way)) >= 0) rtwtmp = &rtltmp->array[w]; } /* make sure we are not rechecking ways with only one p_cnt * (will happen if the last point is inside a different hash) */ if (rtwtmp && rtltmp == &r->ways && mw->p_cnt == 1) continue; if (rtwtmp) { /* we found the element */ // d_printf (" add_sorted overwrite: %lld:%d", rtwtmp->way.id, rtwtmp->way.sid); // d_printf (" dist2dest:rtwtmp:%f > rtwnew:%f (%d) prio:rtwtmp:%f > rtwnew:%f (%d)", // rtwtmp->dist2dest, rtwnew.dist2dest, rtwtmp->priority, rtwnew.priority, // rtwtmp->dist2dest > rtwnew.dist2dest , rtwtmp->priority > rtwnew.priority); // d_printf (" step:rtwtmp:%d , rtwnew:%d rtw->pnr:%d mw->n_cnt:%d p_cnt:%d", rtwtmp->step, // rtwnew.step, rtw->pnr, mw->n_cnt, mw->p_cnt); if (rtwtmp->step < rtwnew.step) rtwnew.step = rtwtmp->step; if (rtwtmp->dist2dest > rtwnew.dist2dest || rtwtmp->priority > rtwnew.priority) { rtl_delete (rtltmp, w); // delete old data rtl_addsorted (route_getstack(r, mwto->type), &rtwnew); } } else rtl_addsorted (route_getstack(r, mwto->type), &rtwnew); } if (mw->id == r->pos_way_id && mw->subid == r->pos_way_sid) { d_printf ("** routing: way found go to the next step"); rtl_lifo_push (&r->route, rtw); rtl_debug (&r->route); r->state = ROUTING_OPTIMIZE; } return 1; }; /* * read data from stack */ #define FACTOR_HI 2.0 #define FACTOR_IA 3.0 #define FACTOR_HA FACTOR_HI*FACTOR_IA int route_popstack (struct rtdata *r, struct rtway *rtw) { int selstack = 0; int i; int res = 0; /* check if we have some need to calculate routes.. i.e. just ways without connections */ if (r->stack1.cnt > 0 && r->stack1.array[route->stack1.cnt-1].priority == 0.0) res = rtl_pop (&r->stack1, rtw); else if (r->stack2.cnt > 0 && r->stack2.array[route->stack2.cnt-1].priority == 0.0) res = rtl_pop (&r->stack2, rtw); else if (r->stack3.cnt > 0 && r->stack3.array[route->stack3.cnt-1].priority == 0.0) res = rtl_pop (&r->stack3, rtw); /* check if we are on the way inside the stack */ if (res <= 0) for (i = 0; i < r->stack1.cnt; i++) if (r->stack1.array[i].way.id == r->pos_way_id && r->stack1.array[i].way.sid == r->pos_way_sid) { *rtw = r->stack1.array[i]; res = 1; rtl_delete (&r->stack1, i); break; } if (res <= 0) for (i = 0; i < r->stack2.cnt; i++) if (r->stack2.array[i].way.id == r->pos_way_id && r->stack2.array[i].way.sid == r->pos_way_sid) { *rtw = r->stack2.array[i]; res = 1; rtl_delete (&r->stack2, i); break; } if (res <= 0) for (i = 0; i < r->stack3.cnt; i++) if (r->stack3.array[i].way.id == r->pos_way_id && r->stack3.array[i].way.sid == r->pos_way_sid) { *rtw = r->stack3.array[i]; res = 1; rtl_delete (&r->stack3, i); break; } if (res <= 0) { if (r->stack1.cnt > 0) { selstack = 1; if (r->stack2.cnt > 0 && r->stack1.array[route->stack1.cnt-1].priority/FACTOR_HI > r->stack2.array[route->stack2.cnt-1].priority) selstack = 2; if (r->stack3.cnt > 0 && r->stack2.cnt == 0 && r->stack1.array[route->stack1.cnt-1].priority/FACTOR_HA > r->stack3.array[route->stack3.cnt-1].priority) selstack = 3; if (r->stack3.cnt > 0 && r->stack2.cnt > 0 && r->stack2.array[route->stack2.cnt-1].priority/FACTOR_IA > r->stack3.array[route->stack3.cnt-1].priority) selstack = 3; } if (selstack == 0 && r->stack2.cnt > 0) { selstack = 2; if (r->stack3.cnt > 0 && r->stack2.array[route->stack2.cnt-1].priority/2.0 > r->stack3.array[route->stack3.cnt-1].priority) selstack = 3; } if (selstack == 0 && r->stack3.cnt > 0) { selstack = 3; } if (selstack == 1) res = rtl_pop (&r->stack1, rtw); else if (selstack == 2) res = rtl_pop (&r->stack2, rtw); else if (selstack == 3) res = rtl_pop (&r->stack3, rtw); } // if (res >= 0) { // d_printf ("route_popstack: %lld:%d", rtw->way.id, rtw->way.sid); // } return res; }; /* * calculating the route.. * 1. reading unchecked ways from stack1 (motor/highway), stack2 (tertiary) * or stack3 (residential/unknown ways). * 2. check these ways and add connected unknown ways to the stack */ void route_calc (struct rtdata *r) { struct rtway rtw; int res; if ((res = route_popstack (r, &rtw)) == 1) { d_printf ("route_calc: rtw: %lld:%d", rtw.way.id, rtw.way.sid); if (route_checkway (r, &rtw)) rtl_fifo_push (&r->ways, &rtw); } else if (r->state == ROUTING_INIT) { d_printf ("route_calc: processing from destination way"); rtw.way.id = r->dest_way_id; rtw.way.sid = r->dest_way_sid; rtw.way.type = MWAY_unknown; r->start_way_id = drawgps_on_way_id; r->start_way_sid = drawgps_on_way_sid; rtw.pos = r->dest; rtw.step = 0; rtw.pnr = 0; d_printf ("route_calc %s:%d FIX ME: nr must be set to the closest node.. ", __FILE__, __LINE__); if (drawgps_on_way_id != 0) { rtl_lifo_push (&r->stack3, &rtw); r->state = ROUTING_CALC; } } else { d_printf ("something went very wrong. cannot find ways which are connected to this area. (state:%d res:%d)", r->state, res); r->state = ROUTING_ABORT; } }; /* return pointer to current way stack, depending on the type of way */ struct rtwaylist *route_getstack (struct rtdata *r, int waytype) { if (!r) return NULL; if (waytype == MWAY_highway) return &r->stack1; if (waytype == MWAY_tertiary) return &r->stack2; else return &r->stack3; }; void route_onway (struct rtdata *r) { static int _once = 1; if (_once) d_printf ("route_onway: we are on the way... "); _once = 0; }; /* optimize the route and create the route from current position */ void route_optimize (struct rtdata *r) { if (r->state == ROUTING_OPTIMIZE) r->state = ROUTING_ONWAY; }; int route_optway (struct rtdata *r, struct rtway *rtw) { return 0; }; /*************************************************************************** * start stop and loop functions for routing */ void route_start (struct map_pos dest) { static int _called = 0; struct map_pos pos; struct gps_data *gpsdata; int i, calcto; if (_called) return; _called = 1; if (route != NULL) { route_free (route); route = NULL; } route = route_alloc (NULL, RT_ALLOC, RT_ALLOCSTACK); d_printf ("*********************************************"); d_printf ("route_start to: %f,%f", dest.lon, dest.lat); route->state = ROUTING_NONE; route->dest = dest; /* find closest way */ i = map_way_findclosest (&route->dest, &route->dest_way_pos, 0, route->dest_way_name, MAP_W_NAMELEN, &route->dest_way_id, &route->dest_way_sid); d_printf (" wayid: %lld:%d", route->dest_way_id, route->dest_way_sid); d_printf (" name: %s", route->dest_way_name); route->closest_distance = -1.0; route->closest_lon = dest.lon; route->closest_lat = dest.lat; route->state = ROUTING_INIT; do { if (gps_isrunning ()) { gpsdata = gps_getposition (); if (gpsdata != NULL && gpsdata->valid) { pos.lon = gpsdata->lon; pos.lat = gpsdata->lat; route->pos_dest.lon = map_lon2km (route->dest.lon - pos.lon, pos.lat); route->pos_dest.lat = map_lat2km (route->dest.lat - pos.lat); route->pos_way_id = drawgps_on_way_id; route->pos_way_sid = drawgps_on_way_sid; route->pos = pos; route->distance = sqrtf (route->pos_dest.lon * route->pos_dest.lon + route->pos_dest.lat * route->pos_dest.lat); route->angle = (180.0 / M_PI) * atan2f(route->pos_dest.lon, route->pos_dest.lat); if (route->angle < 0.0) route->angle += 360.0; if (route->angle > 360.0) route->angle -= 360.0; if (route->state == ROUTING_INIT) { route->start = pos; route_calc (route); route->state = ROUTING_CALC; } else if (route->state == ROUTING_INIT) for (i = 0; i < route->ways.cnt; i++) if (route->ways.array[i].way.id == route->pos_way_id && route->ways.array[i].way.sid == route->pos_way_sid) { d_printf ("** routing: pos found inside ways go to the next step"); route->state = ROUTING_OPTIMIZE; } } if (route->state == ROUTING_CALC) { route_calc (route); } else if (route->state == ROUTING_OPTIMIZE) { route_optimize (route); } else if (route->state == ROUTING_ONWAY) { route_onway (route); } } if (app.status == APPSTATUS_quit) route_stop (); if (route->state == ROUTING_CALC) { if ((++calcto) % 200 == 0) main_wnd_update (); } else main_wnd_update (); } while (route && route->state != ROUTING_NONE && route->state != ROUTING_ABORT); d_printf ("*********************************************"); d_printf ("route_start: finished or aborted"); _called = 0; return; }; void route_stop () { d_printf ("*********************************************"); d_printf ("route_stop"); if (route) route->state = ROUTING_ABORT; };