/*************************************************************************** * map_way.c * * Copyright 2009 - Steffen Pohle * steffen@gulpe.de ****************************************************************************/ /* * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "map.h" #include "memoryleak.h" #include "system.h" #include "vector.h" /***************************************************** * * Way handling * */ /* * add the way without checking for it's size, but do an update */ int map_way_add_to_hash (struct map_hash *mh, struct map_way *mw) { int size; struct map_way *w; /* check if the hash pos and the waypos are valid */ if (mw->p_cnt > 0) if (map_geo2igeo (mw->p[0].lon) != mh->pos.ilon || map_geo2igeo (mw->p[0].lat) != mh->pos.ilat) { d_printf ("p[0]:%d,%d mhpos:%d,%d", __FUNCTION__, map_geo2igeo (mw->p[0].lon), map_geo2igeo (mw->p[0].lat), mh->pos.ilon, mh->pos.ilat); errorexit (-1); } /* check if the first element is already the one we want to update */ if (mh->ways && mh->ways->id == mw->id && mh->ways->subid == mw->subid) { mh->ways = mh->ways->next; mh->wayscnt--; } /* find possible update and go to the end */ if (mh->ways) { /* find last way */ w = mh->ways; while (w && w->next) { if (w->next->id == mw->id && w->next->subid == mw->subid) { /* found old way.. just delete .. */ w->next = w->next->next; mh->wayscnt--; } if (w->next) w = w->next; } w->next = (struct map_way*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); w = w->next; } else { /* complete new ways */ mh->ways = (struct map_way*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); w = (struct map_way*) map_hash_getfree_aligned (mh, POINTERALIGNMENT); } /* copy the way data to the free entry * calc size and set free entry to it's new place */ size = map_way_getsize (mw); map_way_copy (w, mw); w->next = NULL; mh->free = mh->free + size; mh->wayscnt++; SETFLAG(mh->status, MS_changed); return 1; }; /****************************************************************************** * Add/Update way information * - load/ get hash table * - calculate size in bytes for this entry * - check if pointer in free is enought for this new entry * if not: move old memory block out of the way and put a new data block inside. * - add new way */ int map_way_add (struct map_way *way, int loadflags) { struct map_hash *mh = NULL; int size; if (way->p == NULL || way->p_cnt == 0) return 0; size = map_way_getsize (way); mh = map_hash_get (way->p[0].lon, way->p[0].lat, loadflags); if (mh == NULL) { mh = map_hash_alloc (size + MAP_HASH_DEFAULTSIZE); mh->pos.ilon = map_geo2igeo (way->p[0].lon); mh->pos.ilat = map_geo2igeo (way->p[0].lat); map_hash_add (mh); } else if (size >= map_hash_getfree_size (mh)) { mh = map_hash_realloc (mh, mh->datasize + size + MAP_HASH_DEFAULTSIZE); } return map_way_add_to_hash (mh, way); }; /* * will copy all the data from one way to another, this function will not * check if there are conflicts with the memory at all. Also the next field * will be keeped untouched. */ void map_way_copy (struct map_way *dest, struct map_way *src) { int i; strncpy (dest->name, src->name, MAP_W_NAMELEN); strncpy (dest->ref, src->ref, MAP_W_NAMELEN); dest->id = src->id; dest->subid = src->subid; dest->type = src->type; dest->flags = src->flags; dest->p_cnt = src->p_cnt; dest->n_cnt = src->n_cnt; dest->p = (struct map_pos*) (dest->data); dest->n = (struct map_waynode*) (dest->data+(sizeof (struct map_pos)*dest->p_cnt)); for (i = 0; (i < dest->p_cnt || i < dest->n_cnt); i++) { if (i < dest->p_cnt) dest->p[i] = src->p[i]; if (i < dest->n_cnt) dest->n[i] = src->n[i]; } }; struct map_way *map_way_find (struct map_hash *mh, unsigned long long int id, unsigned short int subid) { struct map_way *mw; if (mh == NULL) return NULL; mw = mh->ways; while (mw) { if (mw->id == id && subid == mw->subid) return mw; mw = mw->next; } d_printf ("%s: could not find way %lld:%d ipos:%d,%d", __FUNCTION__, id, subid, mh->pos.ilon, mh->pos.ilat); return NULL; }; int map_way_getsize (struct map_way *way) { return (sizeof (struct map_way) + way->n_cnt * sizeof (struct map_waynode) + way->p_cnt * sizeof (struct map_pos)); }; /************************************************************ * find closest way to the givin position * idh: distance to check (igeo distance) * if name is not NULL and namelen above zero the name of * the road will be copied into name */ int map_way_findclosest (struct map_pos *pos, struct map_pos *waypos, int idh, char *name, int namelen, unsigned long long int *closest_id, unsigned short int *closest_sid) { struct map_hash *mh; struct map_hashpos ipos; struct map_way *mw; float dist_closest = 40000.0, f; ipos.ilon = map_geo2igeo (pos->lon); ipos.ilat = map_geo2igeo (pos->lat); mh = map_hash_geti (ipos.ilon, ipos.ilat, MHLOAD_RELOAD); if (mh == NULL) return 0; mw = mh->ways; while (mw) { f = map_way_getdistance (mw, pos, waypos); if (dist_closest > f) { dist_closest = f; if (name != NULL && namelen > 0) { if (mw->name != NULL && mw->name[0] != 0) strncpy (name, mw->name, namelen); else if (mw->ref != NULL && mw->ref[0] != 0) strncpy (name, mw->ref, namelen); } if (closest_id != NULL) *closest_id = mw->id; if (closest_sid != NULL) *closest_sid = mw->subid; } mw = mw->next; } return 1; }; /* * return the closest distance to the way. If waypos is set also return the * point of the way. */ float map_way_getdistance (struct map_way *mw, struct map_pos *pos, struct map_pos *waypos) { int i, j; float f, dist_closest; fPoint v1, v2, v3, v4; fPoint p1, p2, p3, p4; if (!mw || mw->p_cnt == 0) return (-1.0); /* check first point.. */ p3.x = map_lon2km (0.0, pos->lat); p3.y = map_lat2km (0.0); p2.x = map_lon2km (pos->lon - mw->p[0].lon, mw->p[0].lat); p2.y = map_lat2km (pos->lat - mw->p[0].lat); v2 = vec_sub (p3, p2); dist_closest = sqrt (v2.x * v2.x + v2.y * v2.y); if (waypos) { waypos->lat = mw->p[0].lat; waypos->lon = mw->p[0].lon; } /* check the other nodes, also the way between */ for (i = 1; i < (mw->p_cnt + mw->n_cnt); i++) { /* mw->p... must be converted to km first. */ if (i >= mw->p_cnt) { /* check nodes */ j = i - mw->p_cnt; p1.x = map_lon2km (pos->lon - mw->p[mw->n[j].pnr].lon, mw->p[mw->n[j].pnr].lat); p1.y = map_lat2km (pos->lat - mw->p[mw->n[j].pnr].lat); p2.x = map_lon2km (pos->lon - mw->n[j].d.lon, mw->n[j].d.lat); p2.y = map_lat2km (pos->lat - mw->n[j].d.lat); } else { /* check waysegments */ p2.x = map_lon2km (pos->lon - mw->p[i].lon, mw->p[i].lat); p2.y = map_lat2km (pos->lat - mw->p[i].lat); p1.x = map_lon2km (pos->lon - mw->p[i-1].lon, mw->p[i-1].lat); p1.y = map_lat2km (pos->lat - mw->p[i-1].lat); } v1 = vec_sub (p1, p2); v2 = vec_sub (p3, p2); v3 = vec_normale (v1, v2); /* need to check the range f the new vec.. */ 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); } /* if we are out or range just check the distance */ else { f = sqrt (v2.x * v2.x + v2.y * v2.y); v3 = v2; } if (f < dist_closest) { dist_closest = f; if (waypos) { p4 = vec_add (v3, p2); waypos->lat = pos->lat - map_km2lat (p4.y); waypos->lon = pos->lon - map_km2lon (p4.x, waypos->lat); } } } return dist_closest; }; /*************************************************************************** * distance calculation */ float map_way_getlenght (struct map_way *mw, int start, int end) { float ret = 0.0; int i; if (start == -1 || end == -1) { start = 0; end = mw->p_cnt; } if (start > end) { i = end; end = start; start = i; } for (i = start + 1; (i < mw->p_cnt && i <= end); i++) { ret += map_getdistance (mw->p[i-1], mw->p[i]); } return ret; }; /*************************************************************************** * Check References if some are identical (seperation with ';') */ int map_way_checkref (char *ref1, char *ref2) { char ref1_cpy[MAP_W_REFS*MAP_W_NAMELEN]; char ref2_cpy[MAP_W_REFS*MAP_W_NAMELEN]; int res = 0, i, j; char *next = NULL; char *cur = NULL; if (ref1 == NULL || ref2 == NULL) return 0; if (ref1[0] == 0 || ref2[0] == 0) return 0; /* make a copy of ref1 and ref2 but filter out all unneeded spaces */ for (i = 0, j = 0; i < strlen (ref1); i++) if (ref1[i] != ' ') ref1_cpy[j++] = ref1[i]; ref1_cpy[j] = 0; for (i = 0, j = 0; i < strlen (ref2); i++) if (ref2[i] != ' ') ref2_cpy[j++] = ref2[i]; ref2_cpy[j] = 0; cur = ref1_cpy; do { next = strchr (cur, ';'); if (next != NULL) { next[0] = 0; next++; } if (strstr (ref2_cpy, cur) != NULL) res++; } while ((cur = next) != NULL); return res; };