You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
spOSMroute/main/routing.c

996 lines
30 KiB

/* $Id: routing.c,v 1.4 2014/02/12 21:23:06 steffen Exp $ */
/***************************************************************************
* routing.c
*
* Copyright 2011 - Steffen Pohle
* steffen@gulpe.de
****************************************************************************/
#include <math.h>
#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;
};