/*************************************************************************** * map_osmload.c * * 2009-08-16 * 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. */ /*************************************************** * * read the xml file provided by OpenStreetMap * */ #define _FILE_OFFSET_BITS 64 #include "osmroute.h" #include "map.h" #include "system.h" #include "memoryleak.h" #include "vector.h" #include #include #include #include #include #include #include #include #include #include #include #include struct osm_nodehash { unsigned long long int id; /* node id */ long long int pos; /* position inside the node file */ }; struct osm_waynode { unsigned long long int wid; /* way id */ unsigned short int wsubid; /* way sub id */ unsigned short int wpnr; /* point number inside the way node */ long long int next; /* position of the next way node */ }; struct osm_node { unsigned long long int id; /* node id */ float lon; /* geo data of the node */ float lat; unsigned short int waynodecnt; /* number of waynodes */ long long int waynode; /* position of the first waynode */ }; #define OSM_NODEDETAIL_NONE 0 #define OSM_NODEDETAIL_PLACE 1 #define OSM_NODEDETAIL_POI 2 struct osm_nodedetail { unsigned long long int id; int type; /* OSM_NODEDETAIL_PLACE, OSM_NODEDETAIL_POI */ int elements; int size; int allocsize; char *data; }; struct osm_way { unsigned long long int wid; int type; char name[MAP_W_NAMELEN]; char ref[MAP_W_NAMELEN]; int flags; int ncnt; int nmax; unsigned long long int *nid; char data[]; }; struct s_osm_hashnodes { short int hid; // number of the hid, -1 == unused int hash_cnt; // current numbers inside int hash_fd; // file descriptor int hash_alloc; struct osm_nodehash *hash; // memory to hash char fnhash[LEN_FILENAME]; long long int nodes_end; // current end position inside the file int nodes_fd; // file descriptor char fnnodes[LEN_FILENAME]; }; struct s_osm_xmlcallback { FILE *f; BZFILE *bzf; long long int filesize; long long int filepos; }; #define OSM_HASHNODES 16 static struct s_osm_hashnodes _hashnodes[OSM_HASHNODES]; static struct s_osm_hashnodes *hashnodes[OSM_HASHNODES]; struct s_osmmway { int pmax; int size; struct map_way *mway; }; struct s_osmmarea { int pmax; struct map_area *marea; }; struct s_osmdata { struct s_osmmarea area; struct s_osmmway way; struct osm_way *oway; } osm; static struct osm_waynode *osm_wnode = NULL; static int osm_wnodecnt = 0; static struct map_waynode *osm_mwnode = NULL; static int osm_mwnodecnt = 0; /* for statistic only */ static short int osm_hidmax = -1; // highest hid number unsigned long long int osm_cur_wayid; struct map_pos osm_load_from_web_cur; struct map_pos osm_load_from_web_start; struct map_pos osm_load_from_web_end; unsigned long long int osm_nodes_cnt; unsigned long long int osm_area_cnt; unsigned long long int osm_ways_cnt; float osm_file_pos; void osm_delete_tmpdir (); void osm_init (); void osm_free (); char *osm_getfname_hid (char *fn, int size, short int hid, char *ext); char *osm_getfname_id (char *fn, int size, unsigned long long int id, char *ext); #define osm_hash_getid(__id) ((short int)(__id>>21)) struct s_osm_hashnodes *osm_hashnodes_load (short int hid, int loadhash); void osm_hashnodes_free (struct s_osm_hashnodes *hnode); #define osm_node_save(_node) _osm_node_save (_node, 0) #define osm_node_append(_node) _osm_node_save (_node, 1) int _osm_node_save (struct osm_node node, int append); int osm_node_load (struct osm_node *node, unsigned long long int id); int osm_hash_read (struct s_osm_hashnodes *hnodes, struct osm_nodehash *hash, int pos); struct s_osm_hashnodes *osm_hash_get (unsigned long long int id, struct osm_nodehash *ret); int osm_linehashsplit (struct map_pos p1, struct map_pos p2, struct map_pos *np); struct osm_way *osm_way_alloc (int wmax); void osm_way_copy (struct osm_way *d, struct osm_way *s); void osm_way_save (struct osm_way *oway, struct s_osmmway *mway); void osm_mway_new (int max); /* realloc temp osm_way struct */ void osm_waynode_add (struct osm_node *node, long long int nodepos, unsigned long long int id, unsigned short int subid, unsigned short int pnr); void osm_waynodes_check (); void osm_waynodes_checknode (struct s_osm_hashnodes *nhash, struct osm_node *node); void osm_marea_new (struct s_osmmarea *a, int max); void osm_area_save (struct osm_way *oway, struct s_osmmarea *marea); int osm_area_split_add (struct s_osmmarea *marea); void osm_nodedetail_save (struct osm_nodedetail *onoded, struct osm_node *node); /************************************************************************** * create a filename out of the node id.. */ char *osm_getfname_id (char *fn, int size, unsigned long long int id, char *ext) { if (fn == NULL) return NULL; if (id == 0) return NULL; snprintf (fn, size, "%s/nodes-%d%s", cfg.temppath, osm_hash_getid(id), ext); return fn; }; char *osm_getfname_hid (char *fn, int size, short int hid, char *ext) { if (fn == NULL) return NULL; if (hid == -1) return NULL; snprintf (fn, size, "%s/nodes-%d%s", cfg.temppath, hid, ext); return fn; }; /************************************************************************** * do all preparations for loading a osm file */ void osm_delete_tmpdir (char *path) { DIR *dir; struct dirent *de; struct stat fstat; char fn[LEN_FILENAME]; char fndir[LEN_FILENAME]; static int _osm_recursive = 0; if (_osm_recursive > 16) { // max number of calls.. d_printf ("%s:%d too many subdirs abort deleting (%s).\n", __FILE__, __LINE__, path); return; } _osm_recursive++; /* read the directory */ dir = opendir(path); while (dir != NULL && (de = readdir(dir)) != NULL) { snprintf (fndir, LEN_FILENAME, "%s/%s", path, de->d_name); /* directory? delete this dir */ sprintf (fn, "%s/%s", path, de->d_name); stat (fn, &fstat); if (S_ISDIR (fstat.st_mode) && strcmp (de->d_name, ".") && strcmp (de->d_name, "..")) { osm_delete_tmpdir (fndir); rmdir (fndir); } /* file? delete file */ else if (S_ISREG (fstat.st_mode)) { unlink (fndir); } } closedir (dir); _osm_recursive--; }; void osm_init () { int i; osm_delete_tmpdir (cfg.temppath); /* take care of the hash */ for (i = 0; i < OSM_HASHNODES; i++) { _hashnodes[i].hid = -1; _hashnodes[i].hash = NULL; _hashnodes[i].hash_alloc = 0; _hashnodes[i].hash_cnt = 0; _hashnodes[i].hash_fd = 0; _hashnodes[i].nodes_end = 0; _hashnodes[i].nodes_fd = 0; hashnodes[i] = &_hashnodes[i]; } /* prepare osm_td data */ if (osm.way.mway) ml_free (osm.way.mway); osm.way.mway = NULL; osm.way.pmax = 0; osm.way.size = 0; if (osm.area.marea) ml_free (osm.area.marea); osm.area.marea = NULL; osm.area.pmax = 0; if (osm.oway) ml_free (osm.oway); osm.oway = osm_way_alloc (32); osm_nodes_cnt = 0; osm_area_cnt = 0; osm_ways_cnt = 0; osm_hidmax = -1; #ifdef _LINUX_ mkdir (cfg.temppath, 0755); #else mkdir (cfg.temppath); #endif }; void osm_free () { int i; /* take care of the hash files */ do { for (i = 0; i < OSM_HASHNODES; i++) if (hashnodes[i]->hid != -1) { osm_hashnodes_free (hashnodes[i]); break; } } while (i < OSM_HASHNODES); if (osm.way.mway) ml_free (osm.way.mway); osm.way.mway = NULL; osm.way.pmax = 0; osm.way.size = 0; if (osm.area.marea) ml_free (osm.area.marea); osm.area.marea = NULL; osm.area.pmax = 0; if (osm.oway) ml_free (osm.oway); osm.oway = NULL; if (osm_wnode != NULL) ml_free (osm_wnode); osm_wnode = NULL; osm_wnodecnt = 0; if (osm_mwnode != NULL) ml_free (osm_mwnode); osm_mwnode = NULL; osm_mwnodecnt = 0; // osm_delete_tmpdir (TMPDIR); }; /*********************************************************************** * nodehash filemanagment */ /* * load the needed nodes and nodehash file into the memory * free unused memory if needed */ struct s_osm_hashnodes *osm_hashnodes_load (short int hid, int loadhash) { struct stat fstathash, fstatnodes; struct s_osm_hashnodes *hnodes = NULL; int i, j, t; /* searching for the current hash inside the memory, * when finished: j - first free entry, t - last unused */ for (j = -1, t = -1, i = 0 ; i < OSM_HASHNODES; i++) { if (hashnodes[i]->hid == hid) { /* found hashnodes, select it and put it to the first entry */ hnodes = hashnodes[i]; if (i > 0) for(j = i; j > 0; j--) hashnodes[j] = hashnodes[j-1]; hashnodes[0] = hnodes; break; } else if (j == -1 && hashnodes[i]->hid == -1) j = i; else if (hashnodes[i]->hid != -1) t = i; } if (hnodes == NULL) { /* give us the first entry */ if (t+1 == OSM_HASHNODES) osm_hashnodes_free (hashnodes[t]); // delete last one hnodes = hashnodes[OSM_HASHNODES-1]; for(i = OSM_HASHNODES-1; i > 0; i--) hashnodes[i] = hashnodes[i-1]; hashnodes[0] = hnodes; /* create the filenames for the files */ osm_getfname_hid (hnodes->fnhash, LEN_FILENAME, hid, ".hashnode"); osm_getfname_hid (hnodes->fnnodes, LEN_FILENAME, hid, ".nodes"); /* check how much memory we will need to laod the data */ if (stat (hnodes->fnhash, &fstathash) != 0) fstathash.st_size = 0; if (stat (hnodes->fnnodes, &fstatnodes) != 0) fstatnodes.st_size = 0; /* load the needed data */ hnodes->hid = hid; hnodes->hash = NULL; if ((hnodes->hash_fd = open (hnodes->fnhash, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR)) < 0) d_printf ("%s:%d open file '%s' failed. error:%s", __FILE__, __LINE__, hnodes->fnhash, strerror (errno)); hnodes->hash_cnt = fstathash.st_size / sizeof (struct osm_nodehash); if ((hnodes->nodes_fd = open (hnodes->fnnodes, O_RDWR | O_CREAT, S_IWUSR | S_IRUSR)) < 0) d_printf ("%s:%d open file '%s' failed. error:%s", __FILE__, __LINE__, hnodes->fnnodes, strerror (errno)); hnodes->nodes_end = fstatnodes.st_size; } /* * do we need to load the full hash data? */ if (loadhash && hnodes->hash == NULL) { hnodes->hash_alloc = 5000 + hnodes->hash_cnt; hnodes->hash = (struct osm_nodehash*) ml_malloc (hnodes->hash_alloc * sizeof (struct osm_nodehash)); lseek (hnodes->hash_fd, 0, SEEK_SET); if (read (hnodes->hash_fd, hnodes->hash, hnodes->hash_cnt * sizeof (struct osm_nodehash)) < sizeof (struct osm_nodehash) * hnodes->hash_cnt) { d_printf ("%s:%d could not read data from file:%s", __FILE__, __LINE__, hnodes->fnhash); errorexit (-1); } } if (hid > osm_hidmax) osm_hidmax = hid; return hnodes; }; /* * all data will be saved immediately so we need only to close the file */ void osm_hashnodes_free (struct s_osm_hashnodes *hnode) { if (hnode->hid == -1) return; if ((hnode - _hashnodes) >= OSM_HASHNODES || (hnode - _hashnodes) < 0) { d_printf ("%s:%d something went very wrong: %d, max (OSM_HASHNODES): %d\n", __FILE__, __LINE__, (hnode - _hashnodes), OSM_HASHNODES); errorexit (-1); } /* free all data */ if (hnode->hash && hnode->hash_alloc > 0) { lseek (hnode->hash_fd, 0, SEEK_SET); if (write (hnode->hash_fd, hnode->hash, hnode->hash_cnt*sizeof(struct osm_nodehash)) < hnode->hash_cnt*sizeof(struct osm_nodehash)) { d_printf ("%s:%d could not save all needed data.", __FILE__, __LINE__); } ml_free (hnode->hash); hnode->hash_alloc = 0; hnode->hash = NULL; } else if (hnode->hash) { ml_free (hnode->hash); hnode->hash_alloc = 0; hnode->hash = NULL; } hnode->hash_cnt = 0; if (hnode->hash_fd > 0) { close (hnode->hash_fd); hnode->hash_fd = 0; } hnode->nodes_end = 0; if (hnode->nodes_fd > 0) { close (hnode->nodes_fd); hnode->nodes_fd = 0; } hnode->hid = -1; }; /* * read hash node from position */ int osm_hash_read (struct s_osm_hashnodes *hnodes, struct osm_nodehash *hash, int pos) { if (hnodes->hash_alloc > 0 && hnodes->hash) { memcpy (hash, hnodes->hash+pos, sizeof(struct osm_nodehash)); } else { lseek (hnodes->hash_fd, pos * sizeof (struct osm_nodehash), SEEK_SET); if (read (hnodes->hash_fd, hash, sizeof (struct osm_nodehash)) < sizeof (struct osm_nodehash)) { d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, hnodes->fnhash, pos); return 0; } } return 1; }; /* * returns the nodehash entry to the givin node */ struct s_osm_hashnodes *osm_hash_get (unsigned long long int id, struct osm_nodehash *ret) { short int hid = osm_hash_getid (id); struct s_osm_hashnodes *hnodes = NULL; struct osm_nodehash hash; long long int left, pos, lpos1, lpos2; int i; unsigned long long int lid; ret->id = 0; ret->pos = 0; /* prepare for looking inside the hash */ hnodes = osm_hashnodes_load (hid, 0); left = hnodes->hash_cnt/2; pos = left; lpos2 = -2; lpos1 = -1; while (left > 0 && lpos1 != pos && lpos2 != pos && lpos1 != lpos2) { lpos1 = lpos2; lpos2 = pos; if (!osm_hash_read (hnodes, &hash, pos)) { d_printf ("%s:%d osm_hash_get id:%lld hnodes.hid:%d hnodes.cnt:%d hnodes.fnnode:%s", __FILE__, __LINE__, id, hnodes->hid, hnodes->hash_cnt, hnodes->fnnodes); return NULL; } if (hash.id == id) { *ret = hash; return hnodes; } else if (hash.id < id) { /* hid is larger than half.hid */ left = left / 2 + left % 2; pos = pos+left; if (pos >= hnodes->hash_cnt) pos = hnodes->hash_cnt-1; } else { /* hid is smaler than half.hid */ left = left / 2 + left % 2; pos = pos-left; if (pos < 0) pos = 0; } } if (!osm_hash_read (hnodes, &hash, pos)) { d_printf ("%s:%d osm_hash_get id:%lld hnodes.hid:%d hnodes.cnt:%d hnodes.fnnode:%s", __FILE__, __LINE__, id, hnodes->hid, hnodes->hash_cnt, hnodes->fnnodes); return NULL; } if (hash.id == id) { *ret = hash; return hnodes; } else for (lpos1 = 0; lpos1 < left+1; lpos1++) { if (pos-lpos1 >= 0) { if (!osm_hash_read (hnodes, &hash, pos-lpos1)) { d_printf ("%s:%d osm_hash_get id:%lld hnodes.hid:%d hnodes.cnt:%d hnodes.fnnode:%s", __FILE__, __LINE__, id, hnodes->hid, hnodes->hash_cnt, hnodes->fnnodes); return NULL; } if (hash.id == id) { *ret = hash; return hnodes; } } if (pos+lpos1 < hnodes->hash_cnt) { if (!osm_hash_read (hnodes, &hash, pos+lpos1)) { d_printf ("%s:%d osm_hash_get id:%lld hnodes.hid:%d hnodes.cnt:%d hnodes.fnnode:%s", __FILE__, __LINE__, id, hnodes->hid, hnodes->hash_cnt, hnodes->fnnodes); return NULL; } if (hash.id == id) { *ret = hash; return hnodes; } } } d_printf ("node %lld not found over fast way. hid:%d", id, hnodes->hid); for (i = 0; i < OSM_HASHNODES; i++) { d_printf ("%s hid:%d hash_alloc:%d hash_cnt:%d", __FUNCTION__, hashnodes[i]->hid, hashnodes[i]->hash_alloc, hashnodes[i]->hash_cnt); } for (lid = 0, left = 0, pos = 1; (left < hnodes->hash_cnt); left++) { osm_hash_read (hnodes, &hash, left); if (hash.id == id) { d_printf (" node found over slow way: %lld nr:%d", id, left); *ret = hash; return hnodes; } if (left>0 && pos) if (hash.id <= lid && hnodes->hash) { d_printf ("nodes are not sorted %lld <= %lld. hid:%d", hnodes->hash[left].id, hnodes->hash[left-1].id, hnodes->hid); pos = 0; } lid = hash.id; } return NULL; }; /* * add the new hash entry to the hash table, we will not check for double * entrys, this have to be done by the caller. */ int osm_hash_add (struct s_osm_hashnodes *hnodes, struct osm_nodehash hash) { int i; struct osm_nodehash thash; if (hnodes->hash == NULL || hnodes->hash_alloc == 0) hnodes = osm_hashnodes_load (hnodes->hid, 1); if (hnodes->hash_alloc <= hnodes->hash_cnt) { hnodes->hash_alloc += 5000; hnodes->hash = ml_realloc (hnodes->hash, hnodes->hash_alloc * sizeof (struct osm_nodehash)); } /* check for the right place */ i = hnodes->hash_cnt; if (i > 0) thash = hnodes->hash[i-1]; while (i > 0 && thash.id > hash.id) { hnodes->hash[i] = thash; i--; if (i > 0) thash = hnodes->hash[i-1]; } hnodes->hash[i] = hash; hnodes->hash_cnt++; return 1; }; /*********************************************************************** * loading / saving of a node also adding the new pos to the hash file */ int _osm_node_save (struct osm_node node, int append) { struct s_osm_hashnodes *hnodes = NULL; struct osm_nodehash hash; /* search if we have to update the node */ hash.id = -1; hash.pos = -1; if (!append) /* update --> hash and hnodes == set */ hnodes = osm_hash_get (node.id, &hash); /* append? check if we have enought memory also setup the hash entry */ if (hnodes == NULL) { /* append */ hnodes = osm_hashnodes_load (osm_hash_getid (node.id), 1); hash.pos = hnodes->nodes_end; hash.id = node.id; hnodes->nodes_end += sizeof (struct osm_node); osm_hash_add (hnodes, hash); } lseek (hnodes->nodes_fd, hash.pos, SEEK_SET); if (write (hnodes->nodes_fd, &node, sizeof (struct osm_node)) < sizeof (struct osm_node)) { d_printf ("%s:%d could not write data to file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, hash.pos); errorexit (-1); } return 1; }; int osm_node_load (struct osm_node *node, unsigned long long int id) { struct s_osm_hashnodes *hnodes = NULL; struct osm_nodehash hash; hnodes = osm_hash_get (id, &hash); if (hnodes == NULL) return -1; if (lseek (hnodes->nodes_fd, hash.pos, SEEK_SET) < 0) d_printf ("%s:%d lseek failed. fd:%d error:%s", __FILE__, __LINE__, hnodes->nodes_fd, strerror (errno)); if (read (hnodes->nodes_fd, node, sizeof (struct osm_node)) < sizeof (struct osm_node)) { d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, hash.pos); errorexit (-1); } return hash.pos; }; /****************************************************************************** * waynodes handling */ /* * save the waynode data inside the hash file to read all needed data later on * and check the waynodes inside the map files. */ void osm_waynode_add (struct osm_node *node, long long int nodepos, unsigned long long int id, unsigned short int subid, unsigned short int pnr) { struct s_osm_hashnodes *hnodes = NULL; struct osm_nodehash hash; struct osm_waynode wn; long long int pos, wpos; if (node == NULL) return; hnodes = osm_hash_get (node->id, &hash); if (hnodes == NULL) return; pos = hnodes->nodes_end; hnodes->nodes_end += sizeof (struct osm_waynode); /* save waynode at the end of the file */ wn.wid = id; wn.wsubid = subid; wn.wpnr = pnr; wn.next = 0; // d_printf ("wn id:%lld subid:%d pnr: %hd",wn.wid, wn.wsubid, wn.wpnr); lseek (hnodes->nodes_fd, pos, SEEK_SET); if (write (hnodes->nodes_fd, &wn, sizeof (struct osm_waynode)) < sizeof (struct osm_waynode)) { d_printf ("%s:%d could not write waynode data to file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, pos); errorexit (-1); } if (node->waynode == 0) { /* save node with new waypos */ node->waynode = pos; } else { /* search for the last waynode entry */ wpos = node->waynode; do { lseek (hnodes->nodes_fd, wpos, SEEK_SET); if (read (hnodes->nodes_fd, &wn, sizeof (struct osm_waynode)) < sizeof (struct osm_waynode)) { d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, hash.pos); errorexit (-1); } wpos = wn.next; } while (wn.next != 0); wn.next = pos; pos = 0 - (long long int)sizeof (struct osm_waynode); lseek (hnodes->nodes_fd, pos, SEEK_CUR); if (write (hnodes->nodes_fd, &wn, sizeof (struct osm_waynode)) < sizeof (struct osm_waynode)) { d_printf ("%s:%d could not write data to file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, hash.pos); errorexit (-1); } } /* write node data */ node->waynodecnt++; lseek (hnodes->nodes_fd, nodepos, SEEK_SET); if (write (hnodes->nodes_fd, node, sizeof (struct osm_node)) < sizeof (struct osm_node)) { d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, hnodes->fnnodes, hash.pos); errorexit (-1); } return; }; void osm_waynodes_check () { int hid, i; struct s_osm_hashnodes *ohash; struct osm_node node; char text[256]; d_printf ("osm_waynodes_check started"); for (hid = 0; hid < osm_hidmax; hid++) { sprintf (text, _("checking for waynodes in hid %d"), hid); app_status (-1, text, 0.0); ohash = osm_hashnodes_load (hid, 1); for (i = 0; i < ohash->hash_cnt; i++) { if ((i%1024) == 0) main_wnd_loop (i, ohash->hash_cnt); /* read node */ lseek (ohash->nodes_fd, ohash->hash[i].pos, SEEK_SET); if (read (ohash->nodes_fd, &node, sizeof (struct osm_node)) < sizeof (struct osm_node)) { d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, ohash->fnnodes, ohash->hash[i].pos); errorexit (-1); } osm_waynodes_checknode (ohash, &node); } } d_printf ("osm_waynodes_check finished"); }; void osm_waynodes_checknode (struct s_osm_hashnodes *ohash, struct osm_node *node) { struct map_way *way; struct map_hash *mh; int wncnt, ncur, nto, i, waysize; /* check and allocate enought memory */ if (osm_wnodecnt < node->waynodecnt || osm_wnode == NULL) { osm_wnodecnt = node->waynodecnt + 4; if (osm_wnode) osm_wnode = ml_realloc (osm_wnode, sizeof (struct osm_waynode) * osm_wnodecnt); else osm_wnode = ml_malloc (sizeof (struct osm_waynode) * osm_wnodecnt); } if (node->waynode == 0 && node->waynodecnt == 0) return; else if (node->waynode == 0 || node->waynodecnt == 0) { d_printf ("%s:%d osm_waynodes_checknode error something isn't right waynode:%lld waynodecnt:%d", __FILE__, __LINE__, node->waynode, node->waynodecnt); return; } if (node->waynodecnt == 1) return; /* read all waynodes */ lseek (ohash->nodes_fd, node->waynode, SEEK_SET); wncnt = 0; do { /* read waynode */ if (read (ohash->nodes_fd, &osm_wnode[wncnt], sizeof (struct osm_waynode)) < sizeof (struct osm_waynode)) { d_printf ("%s:%d could not read data from file:%s pos:%d", __FILE__, __LINE__, ohash->fnnodes, osm_wnode[wncnt].next); errorexit (-1); } lseek (ohash->nodes_fd, osm_wnode[wncnt].next, SEEK_SET); wncnt++; } while (osm_wnode[wncnt-1].next != 0 && wncnt < node->waynodecnt); /* * walk trough all waynodes */ for (ncur = 0; ncur < wncnt; ncur++) { /* * prepare current way */ if ((mh = map_hash_get (node->lon, node->lat, MHLOAD_RELOAD)) == NULL) continue; if ((way = map_way_find (mh, osm_wnode[ncur].wid, osm_wnode[ncur].wsubid)) == NULL) continue; waysize = map_way_getsize (way) + POINTERALIGNMENT; /* check for enought memory */ if (osm_mwnodecnt < way->n_cnt+wncnt) { osm_mwnodecnt = way->n_cnt+wncnt + 4; if (osm_mwnode) osm_mwnode = ml_realloc (osm_mwnode, sizeof (struct map_waynode) * osm_mwnodecnt); else osm_mwnode = ml_malloc (sizeof (struct map_waynode) * osm_mwnodecnt); } if (osm.way.size < waysize) { osm.way.size = waysize + 256; if (osm.way.mway) osm.way.mway = ml_realloc (osm.way.mway, osm.way.size); else osm.way.mway = ml_malloc (osm.way.size); } /* copy way to osm_mway and reset pointer to the nodes*/ map_way_copy (osm.way.mway, way); osm.way.mway->next = NULL; osm.way.mway->n = osm_mwnode; osm.way.mway->n_cnt = way->n_cnt; /* copy nodes */ for (i = 0; i < way->n_cnt; i++) osm.way.mway->n[i] = way->n[i]; /* * now update or add the new nodes */ for (nto = 0; nto < wncnt; nto++) { if (nto == ncur) continue; /* from and to identical. */ for (i = 0; i < osm.way.mway->n_cnt; i++) { /* check if we know this node already */ if (osm.way.mway->n[i].d_id == osm_wnode[nto].wid && osm.way.mway->n[i].d_subid == osm_wnode[nto].wsubid && osm.way.mway->n[i].d_pnr == osm_wnode[nto].wpnr) break; } if (i == osm.way.mway->n_cnt && i < osm_mwnodecnt) { /* unknown waynode add */ osm.way.mway->n[i].d_pnr = osm_wnode[nto].wpnr; osm.way.mway->n[i].d_id = osm_wnode[nto].wid; osm.way.mway->n[i].d_subid = osm_wnode[nto].wsubid; osm.way.mway->n[i].d.lon = node->lon; osm.way.mway->n[i].d.lat = node->lat; osm.way.mway->n[i].pnr = osm_wnode[ncur].wpnr; osm.way.mway->n[i].flags = 0; osm.way.mway->n_cnt++; } else if (i == osm.way.mway->n_cnt && i >= osm_mwnodecnt) { d_printf ("%s:%d osm_waynodes_checknode: something went very wrong. (i == osm_mway->n_cnt && i >= osm_mwnodecnt)", __FILE__, __LINE__); errorexit (1); } } /* replace current node */ if (way->n_cnt != osm.way.mway->n_cnt) { map_way_add (osm.way.mway, MHLOAD_RELOAD); } } }; /**************************************************************************** * split the line into peaces, is the line intersects with more then one * hash segment the function will return 2 as indicator of another * intersection. */ int osm_linehashsplit (struct map_pos p1, struct map_pos p2, struct map_pos *np) { return 0; // for now just return 0 and get the other stuff running first. }; /*************************************************************************** * osm_way handling .. allocating memory and converting it into map_way */ struct osm_way *osm_way_alloc (int wmax) { struct osm_way *w = NULL; w = (struct osm_way*) ml_malloc (sizeof (struct osm_way) + wmax * sizeof (unsigned long long int)); w->nmax = wmax; w->ncnt = 0; w->nid = (unsigned long long int*) &w->data[0]; w->name[0] = 0; w->ref[0] = 0; w->type = MWAY_unknown; w->flags = 0; return w; }; void osm_way_copy (struct osm_way *d, struct osm_way *s) { int i; if (d == NULL || s == NULL) { d_printf ("%s:%d d or s is NULL \n", __FILE__, __LINE__); errorexit (-1); } d->wid = s->wid; d->type = s->type; strncpy (d->name, s->name, MAP_W_NAMELEN); strncpy (d->ref, s->ref, MAP_W_NAMELEN); for (i = 0; i < s->ncnt; i++) if (i < d->nmax) d->nid[i] = s->nid[i]; d->ncnt = s->ncnt; d->flags = s->flags; }; void osm_mway_pmax_new (struct s_osmmway *w, int max) { int newsize = sizeof (struct map_way) + 2 * sizeof (struct map_waynode) + max * sizeof (struct map_pos); if (w->mway == NULL || newsize > w->size) { w->mway = ml_realloc (w->mway, newsize); w->size = newsize; } w->pmax = max; w->mway->name[0] = 0; w->mway->ref[0] = 0; w->mway->n_cnt = 0; w->mway->p_cnt = 0; w->mway->n = (struct map_waynode*) &w->mway->data[0]; w->mway->p = (struct map_pos*) &w->mway->data[2 * sizeof (struct map_waynode)]; w->mway->id = 0; w->mway->subid = 0; w->mway->next = 0; w->mway->flags = 0; }; /******************************************************************** * convert the osm way into the map_way type and save it into the * hash data block. I case the way goes over more hash segments the * way will be slit into peaces */ void osm_way_save (struct osm_way *oway, struct s_osmmway *way) { int p; long long int nodepos; unsigned long long int id; struct osm_node node; struct map_pos curpos, lastpos; osm_mway_pmax_new (way, oway->ncnt); way->mway->id = oway->wid; way->mway->type = oway->type; way->mway->flags = oway->flags; strncpy (way->mway->name, oway->name, MAP_W_NAMELEN); strncpy (way->mway->ref, oway->ref, MAP_W_NAMELEN); for (p = 0; p < oway->ncnt; p++) { /* find the node */ id = oway->nid[p]; if ((nodepos = osm_node_load (&node, id)) == -1) return; /* check if we are still in the same AREA.. */ curpos.lon = node.lon; curpos.lat = node.lat; if (p > 0 && (map_geo2igeo (lastpos.lon) != map_geo2igeo (curpos.lon) || map_geo2igeo (lastpos.lat) != map_geo2igeo (curpos.lat))) { /* * save the known part of the way.. * and create a new part of the way */ way->mway->n[way->mway->n_cnt].d_id = way->mway->id; way->mway->n[way->mway->n_cnt].d_subid = way->mway->subid+1; way->mway->n[way->mway->n_cnt].d_pnr = 0; way->mway->n[way->mway->n_cnt].pnr = way->mway->p_cnt-1; way->mway->n[way->mway->n_cnt].d = curpos; way->mway->n[way->mway->n_cnt].flags = 0; way->mway->n_cnt++; map_way_add (way->mway, MHLOAD_RELOAD); /* prepare a new way with subid + 1 */ way->mway->n_cnt = 1; way->mway->n[0].d_subid = way->mway->subid; way->mway->n[0].d_id = way->mway->id; way->mway->n[0].d = lastpos; way->mway->n[0].d_pnr = way->mway->p_cnt-1; way->mway->n[0].pnr = 0; way->mway->n[0].flags = 0; way->mway->p_cnt = 0; way->mway->subid++; } /* * add the new node to the way.. also add the way to the nodehash.. */ way->mway->p[way->mway->p_cnt].lon = node.lon; way->mway->p[way->mway->p_cnt].lat = node.lat; if (way->mway->type < MWAY_MAX) osm_waynode_add (&node, nodepos, way->mway->id, way->mway->subid, way->mway->p_cnt); else { d_printf ("%s:%d osm_way_save: osm_mway->type >= MWAY_MAX which should not happen, since it should call osm_area_save", __FILE__, __LINE__); exit (1); } way->mway->p_cnt++; /* save last position */ lastpos = curpos; osm_cur_wayid = oway->wid; main_wnd_loop(p, -2); } map_way_add (way->mway, MHLOAD_RELOAD); return; }; /****************************************************************************** * all code to save an area */ void osm_marea_new (struct s_osmmarea *a, int max) { if (a->marea == NULL || max > a->pmax) { a->marea = ml_realloc (a->marea, sizeof (struct map_area) + max * sizeof (struct map_pos)); a->pmax = max; } a->marea->id = 0; a->marea->subid = 0; a->marea->type = MAREA_unknown; a->marea->p = (struct map_pos*) a->marea->data; a->marea->p_cnt = 0; }; /******************************************************************** * convert the osm "way" into the map_area type and save it into the * hash data block. I case the way goes over more hash segments the * way will be slit into peaces * * splitting into peaces does not work yet, also taking care of the * polygons, no angles over 180°. * * CALL with NULL will free all unneeded memory */ void osm_area_save (struct osm_way *oway, struct s_osmmarea *area ) { int ndfirst, nd; // first node, current node int outfirstnd; // first outside node, current outside node static char *nodestat = NULL; // array to save all some node data static int nodestat_alloc = 0; // size of the struct struct map_pos pos, p1; // current hash, pos struct osm_node curnode, node; // current node, node int sid = 0; /* check if we just need to free all data */ if (oway == NULL) { if (nodestat != NULL) free (nodestat); nodestat = NULL; nodestat_alloc = 0; return; } /* basic check and allocate enought memory (if needed) */ if (oway->type == MAREA_ignore) return; else if (oway->type == MAREA_campsite) { struct map_poi poi; poi.lon = 0.0; poi.lat = 0.0; poi.name = oway->name; poi.additional = NULL; poi.type = MAP_POI_campsite; poi.next = NULL; poi.id = 1; for (nd = 0; nd < oway->ncnt; nd++) { if (osm_node_load (&node, oway->nid[nd]) == -1) { d_printf ("%s:%d osm_area_save count not find node number: %lld", __FILE__, __LINE__, oway->nid[nd]); return; } poi.lon += node.lon; poi.lat += node.lat; } poi.lon = poi.lon / (float) nd; poi.lat = poi.lat / (float) nd; map_poi_add (&poi, MHLOAD_RELOAD); return; } if (oway->ncnt < 2) { return; // a polygon needs at last 3 nodes } osm_marea_new (area, oway->ncnt); /* allocate data for nodestat, and reset data */ if (nodestat_alloc < oway->ncnt) { nodestat = ml_malloc (oway->ncnt); nodestat_alloc = oway->ncnt; } memset (nodestat, 0x0, nodestat_alloc); /* * find the first complete hash segment and it's end */ do { /* find first unused node, also the center of the area */ for (ndfirst = 0; ndfirst < oway->ncnt && nodestat[ndfirst] != 0; ndfirst++); /* * found an unused node so save this segment */ if (ndfirst < oway->ncnt) { if (osm_node_load (&curnode, oway->nid[ndfirst]) == -1) { d_printf ("%s:%d osm_area_save count not find node number: %lld", __FILE__, __LINE__, oway->nid[ndfirst]); return; } nodestat[ndfirst] = 1; /* save first node */ area->marea->id = oway->wid; area->marea->subid = sid; area->marea->type = oway->type; area->marea->p_cnt = 1; area->marea->p = (struct map_pos *) area->marea->data; area->marea->p[0].lon = curnode.lon; area->marea->p[0].lat = curnode.lat; /* find all nodes which are inside this segment * do preparations after this save the area */ nd = ndfirst; outfirstnd = -1; pos.lon = curnode.lon; pos.lat = curnode.lat; if (++nd >= oway->ncnt) nd = 0; /* count +1, check for overrun */ while (nd != ndfirst) { if (osm_node_load (&node, oway->nid[nd]) == -1) { d_printf ("%s:%d osm_area_save count not find node number: %lld", __FILE__, __LINE__, oway->nid[nd]); return; } pos.lon = node.lon; pos.lat = node.lat; if (outfirstnd >= 0) { /* we are still outside, find the next inside pos */ d_printf ("%s:%d FIX ME", __FILE__, __LINE__); exit (-1); } else { /* we are inside the current node * check and split in two if needed */ if (osm_linehashsplit (area->marea->p[area->marea->p_cnt-1], pos, &p1) > 0) { /* node is outside the area, the border is saved at p1 */ area->marea->p_cnt++; outfirstnd = nd; } else { /* node is inside the area */ area->marea->p[area->marea->p_cnt].lon = node.lon; area->marea->p[area->marea->p_cnt].lat = node.lat; area->marea->p_cnt++; nodestat[nd] = 1; } } if (++nd >= oway->ncnt) nd = 0; /* count +1, check for overrun */ } osm_area_split_add (area); } } while (ndfirst < oway->ncnt); return; }; /* * convert area into a polygon without angles above 180° * it saves time late in drawing on slow devices. * only needed because of GL_TRIANGLE_STRIP and return * last subid saved. */ struct s_osmareapnt { int pnr; fPoint km; float angle; float sel_dist; float sel_angle; }; #define MAX_SUBID 250 int osm_area_split_add (struct s_osmmarea *marea) { /* allocate enought memory */ struct map_area *a = NULL; struct s_osmareapnt *pt = ml_malloc (sizeof (struct s_osmareapnt) * marea->marea->p_cnt); int i, st, pt_c, c; int _debug = 0, rotated = 0; float angle_sum; // if (marea->marea->id == 22963835) _debug = 1; // else return 1; // d_printf ("marea: %lld cnt:%d", marea->marea->id, marea->marea->p_cnt); // map_area_add (marea->marea, MHLOAD_RELOAD); // return 1; if (_debug) d_printf ("area:%lld:%d", marea->marea->id, marea->marea->subid); a = ml_malloc (map_area_getsize (marea->marea)); map_area_copy (a, marea->marea); /* calculate all klon, klat and prepare start struct, also * ignore double entrys */ for (pt_c = 0, i = 0; i < marea->marea->p_cnt; i++) { if (i == 0) st = marea->marea->p_cnt-1; else st = i-1; if (marea->marea->p[i].lon == marea->marea->p[st].lon && marea->marea->p[i].lat == marea->marea->p[st].lat) continue; pt[pt_c].pnr = i; pt[pt_c].angle = -1.0; pt[pt_c].km.x = map_lon2km (marea->marea->p[i].lon, marea->marea->p[i].lat); pt[pt_c].km.y = map_lat2km (marea->marea->p[i].lat); if (_debug) d_printf ("pt[%-3d].pnr:%d km.x:%f km.y:%f", pt_c, pt[pt_c].pnr, pt[pt_c].km.x, pt[pt_c].km.y); pt_c++; } while (pt[0].pnr >= 0 && pt_c > 2 && a->subid < MAX_SUBID) { /* st - will keep first pt to start checking polygon * c - count how many angles are above 180° */ if (_debug) d_printf ("**************** subid:%d pt_c:%d", a->subid, pt_c); for (angle_sum = 0.0, st = -1, c = 0, i = 0; i < pt_c; i++) { if (i == pt_c-1) pt[i].angle = point_angle (pt[i-1].km, pt[i].km, pt[0].km); else if (i == 0) pt[i].angle = point_angle (pt[pt_c-1].km, pt[i].km, pt[i+1].km); else pt[i].angle = point_angle (pt[i-1].km, pt[i].km, pt[i+1].km); if (pt[i].angle > M_PI) { /* only select first pt */ if (st == -1) st = i; else if (pt[st].angle < pt[i].angle) st = i; c++; } angle_sum += pt[i].angle; if (_debug) d_printf ("i:%-2d pnr:%-2d angle:%f",i, pt[i].pnr, pt[i].angle); } angle_sum /= (float)pt_c; if (_debug) d_printf ("c:%d pt_c:%d st:%d angle_sum:%f",c, pt_c, st, angle_sum); /* make sure we going counterclock direction, only first area */ if (rotated == 0 && angle_sum > M_PI && a->subid == marea->marea->subid) { struct s_osmareapnt *pt_ = ml_malloc (sizeof (struct s_osmareapnt) * pt_c); if (_debug) d_printf ("change rotation ..."); for (i = 0; i < pt_c; i++) pt_[pt_c - i - 1] = pt[i]; ml_free (pt); pt = pt_; rotated = 1; continue; } /* if c==0 save last areapart */ else if (c == 0) { a->p_cnt = 0; for (i = 0; i < pt_c; i++) { if (_debug) d_printf ("0: added %d pnr:%d", a->p_cnt, pt[i].pnr); a->p[a->p_cnt++] = marea->marea->p[pt[i].pnr]; pt[i].pnr = -1; } map_area_add (a, MHLOAD_RELOAD); a->subid++; } /* if c==1 select j as 0 then quit, if GL_TRIANGLE_STRIP gets kicked out of * openGL we need to change this */ else if (c == 1) { for (a->p_cnt = 0, i = st; a->p_cnt < pt_c;) { if (_debug) d_printf ("1: added %d pnr:%d", a->p_cnt, pt[i].pnr); a->p[a->p_cnt++] = marea->marea->p[pt[i].pnr]; pt[i].pnr = -1; if (i < pt_c-1) i++; else i = 0; } map_area_add (a, MHLOAD_RELOAD); a->subid++; } /* check again for the part to split the area. */ else { int j, sel, s, i_old, c; float dist; float angle; /* check if selected start is working for us */ sel = st; i_old = -1; do { /* fill up all sel_angles and sel_dists */ if (sel < pt_c-1) s = sel + 1; else s = 0; if (_debug) d_printf ("select %d [pnr:%d] second:%d", sel, pt[sel].pnr, s); for (i = 0; i < pt_c; i++) { if (i != sel) { pt[i].sel_angle = point_angle (pt[i].km, pt[sel].km, pt[s].km); pt[i].sel_dist = vec_len (vec_sub (pt[i].km, pt[sel].km)); } else { pt[i].sel_angle = -2.0; pt[i].sel_dist = -2.0; } if (_debug) d_printf (" %-2d pnr:%-2d angle:%f dist:%f", i, pt[i].pnr, pt[i].sel_angle, pt[i].sel_dist); } a->p_cnt = 0; a->p[a->p_cnt++] = marea->marea->p[pt[sel].pnr]; angle = 0.0; if (_debug) d_printf (" check for possible loop: i:%d s:%d st:%d sel:%d angle:%f pt[i].sel_angle:%f", i, s, st, sel, angle, pt[i].sel_angle); for (i_old = -1, i = s, angle = 0.0; i != sel && angle <= pt[i].sel_angle;) { if (_debug) d_printf (" i:%d sel:%d angle:%f pt[i].sel_angle:%f", i, st, angle, pt[i].sel_angle); for (j = i; j != sel;) { if (_debug) d_printf (" j:%d (pnr:%d, angle:%f, dist:%f) i:%d (pnr:%d, angle:%f, dist:%f) ", j, pt[j].pnr, pt[j].sel_angle, pt[j].sel_dist, i, pt[i].pnr, pt[i].sel_angle, pt[i].sel_dist); if (pt[i].sel_angle > pt[j].sel_angle && pt[i].sel_dist > pt[j].sel_dist) { if (_debug) d_printf (" break 1"); break; } j++; if (j >= pt_c) j = 0; } if (j != sel) { /* something is in the way */ if (_debug) d_printf (" break 2"); break; } else { /* found something */ if (i_old >= 0) pt[i_old].pnr = -1; /* already second pass */ a->p[a->p_cnt++] = marea->marea->p[pt[i].pnr]; if (_debug) d_printf ("add nr:%d pnr:%d", a->p_cnt-1, pt[i].pnr); angle = pt[i].sel_angle; } i_old = i; i++; if (i >= pt_c) i = 0; } if (a->p_cnt < 3) { /* found nothing try next one */ sel++; if (sel >= pt_c) sel = 0; } } while (sel != st && a->p_cnt < 3); /* add element */ if (a->p_cnt >= 3) { map_area_add (a, MHLOAD_RELOAD); a->subid++; } } /* recreate pall list, delete unneeded elements (pnr == -1) */ for (c = 0, i = 0; i < pt_c; i++) if (pt[i].pnr != -1) pt[c++] = pt[i]; if (pt_c == c) { d_printf ("%s:%d pt_c == c : nothing deleted.. something went wrong.", __FILE__, __LINE__); d_printf (" rotated:%d", rotated); break; } pt_c = c; } if (a->subid >= MAX_SUBID) { d_printf ("%s:%d max subid reached. area id:%lld", __FILE__, __LINE__, a->id); } if (pt[0].pnr >= 0 && pt_c > 2) { d_printf ("%s:%d osm_area_split_add: something went very wrong", __FILE__, __LINE__); d_printf (" marea->id: %lld:%d", a->id, a->subid); d_printf (" pt[0].pnr:%d pt[1].pnr:%d pall_cnt: %d", pt[0].pnr, pt[1].pnr, pt_c); } /* free unneeded memory and return to caller */ ml_free (a); ml_free (pt); return a->subid; }; /******************************************************************** * save detail information of the node. This will also create the * search index. */ void osm_nodedetail_save (struct osm_nodedetail *onoded, struct osm_node *node) { int i, j; char *data; char *var; char *val; data = onoded->data; if (onoded->type == OSM_NODEDETAIL_PLACE) { struct map_place place; place.lon = node->lon; place.lat = node->lat; place.id = node->id; place.name = NULL; place.country = NULL; place.state = NULL; place.district = NULL; place.postalcode = NULL; place.next = NULL; place.population = 0; place.type = MAP_PLACE_unknown; for (i = 0; i < onoded->elements; i++) { var = data; val = var + strlen (var) + 1; data = val + strlen (val) + 1; // d_printf ("variable:%s value:%s", var, val); if (strcmp (var, "name") == 0) { place.name = val; } else if (strcmp (var, "place") == 0) { for (j = 0; val[j] != 0; j++) val[j] = tolower (val[j]); if (strcmp (val, "city") == 0) { place.type = MAP_PLACE_city; } else if (strcmp (val, "suburb") == 0) { place.type = MAP_PLACE_suburb; } else if (strcmp (val, "village") == 0) { place.type = MAP_PLACE_village; } else if (strcmp (val, "hamlet") == 0) { place.type = MAP_PLACE_hamlet; } else if (strcmp (val, "town") == 0) { place.type = MAP_PLACE_town; } else { // d_printf ("unknown place:'%s' for '%s'", val, place.name); place.type = MAP_PLACE_unknown; } } } // d_printf ("NAME: id:%lld name:'%s' type:%d", place.id, place.name, place.type); if (place.type != MAP_PLACE_unknown) { map_place_add (&place, MHLOAD_RELOAD); map_search_add (place.country, place.name, place.id, place.lon, place.lat); } } else if (onoded->type == OSM_NODEDETAIL_POI) { struct map_poi poi; poi.lon = node->lon; poi.lat = node->lat; poi.id = node->id; poi.name = NULL; poi.additional = NULL; poi.type = MAP_POI_unknown; for (i = 0; i < onoded->elements; i++) { var = data; val = var + strlen (var) + 1; data = val + strlen (val) + 1; if (strcmp (var, "name") == 0) { poi.name = val; } else if (strcmp (var, "highway") == 0) { for (j = 0; val[j] != 0; j++) val[j] = tolower (val[j]); if (strcmp (val, "bus_stop") == 0) { poi.type = MAP_POI_busstop; } } else if (strcmp (var, "amenity") == 0) { for (j = 0; val[j] != 0; j++) val[j] = tolower (val[j]); if (strcmp (val, "restaurant") == 0) { poi.type = MAP_POI_restaurant; } else if (strcmp (val, "fuel") == 0) { poi.type = MAP_POI_gasstation; } } else if (strcmp (var, "tourism") == 0) { for (j = 0; val[j] != 0; j++) val[j] = tolower (val[j]); if (strcmp (val, "hotel") == 0) { poi.type = MAP_POI_hotel; } } } if (poi.type != MAP_POI_unknown && poi.name != NULL) if (strlen (poi.name) > 0) map_poi_add (&poi, MHLOAD_RELOAD); } }; /* * append to the onoded another data, this will also check the size of the allocated data */ void osm_nodedetail_append (struct osm_nodedetail *onoded, char *variable, char *value) { char *data, *var, *val; int i,j; /* allocated memory for the data is too small */ if (onoded->allocsize == 0 || onoded->data == NULL) { onoded->allocsize = strlen (variable) + strlen (value) + 2 + 4096; onoded->size = 0; onoded->data = ml_malloc (onoded->allocsize); } else if ((strlen (variable) + strlen (value) + 2 + onoded->size) >= onoded->allocsize) { char *olddata; int oldsize; olddata = onoded->data; oldsize = onoded->allocsize; onoded->allocsize += (strlen (variable) + strlen (value) + 2 + 4096); onoded->data = ml_malloc (onoded->allocsize); memcpy (onoded->data, olddata, oldsize); ml_free (olddata); } /* go to the last element and save data */ data = onoded->data + onoded->size; var = data; for (i = 0; i < strlen (variable); i++) data[i] = tolower (variable[i]); data[i] = '\0'; data = data + i + 1; val = data; for (j = 0; j < strlen (value); j++) data[j] = value[j]; data[j] = '\0'; onoded->size = onoded->size + j + i + 2; if (strncmp (var, "place", 6) == 0) { onoded->type = OSM_NODEDETAIL_PLACE; } if (strncmp (var, "highway", 8) == 0 && strncmp (val, "bus_stop", 9) == 0) { onoded->type = OSM_NODEDETAIL_POI; } if (strncmp (var, "amenity", 8) == 0) { onoded->type = OSM_NODEDETAIL_POI; } if (strncmp (var, "tourism", 8) == 0) { onoded->type = OSM_NODEDETAIL_POI; } onoded->elements++; }; /*************************************************************************** * read a osmxml file, */ #define XML_TEXTLEN 256 void osm_processdata (xmlTextReaderPtr reader) { const xmlChar *name, *attr, *k, *v; static int xmlolddepth = -1; int xmldepth; char *cid; unsigned long long int id; static struct osm_node onode; static struct osm_nodedetail onoded; struct osm_way *tmpoway = NULL; static void *last = NULL; if (xmlolddepth == -1) { onode.id = 0; onoded.data = NULL; onoded.allocsize = 0; onoded.size = 0; onoded.elements = 0; onoded.type = OSM_NODEDETAIL_NONE; if (osm.oway != NULL) { osm.oway->type = MWAY_unknown; osm.oway->wid = 0; osm.oway->ncnt = 0; } else { osm.oway = osm_way_alloc (32); } last = NULL; } name = xmlTextReaderConstName(reader); if (name == NULL) name = BAD_CAST "--"; /* check if we need to save the data.. */ cid = (char*) xmlTextReaderGetAttribute (reader, (xmlChar*)"id"); if (cid) { id = atoll (cid); free (cid); } else id = 0; xmldepth = xmlTextReaderDepth (reader); if (xmldepth == 1 && (strncmp ((char*) name, "#text", 6) == 0)) { /* * save data */ if (last == (void*) osm.oway) { if (osm.oway->type >= MWAY_MAX) { osm.oway->type -= MWAY_MAX; osm_area_cnt++; if (osm.oway->type != MAREA_ignore) osm_area_save (osm.oway, &osm.area); } else { osm_ways_cnt++; osm_way_save (osm.oway, &osm.way); } } else if (last == (void*) &onode) { /* add the current node */ osm_nodes_cnt++; osm_node_append (onode); if (onoded.type != OSM_NODEDETAIL_NONE) osm_nodedetail_save (&onoded, &onode); } onode.id = 0; onode.waynode = 0; onoded.type = OSM_NODEDETAIL_NONE; onoded.size = 0; onoded.elements = 0; osm.oway->wid = 0; osm.oway->type = MWAY_MAX + MAREA_ignore; osm.oway->ncnt = 0; osm.oway->name[0] = 0; osm.oway->ref[0] = 0; osm.oway->flags = 0; last = NULL; } /* * check and process date for a node */ if (strncmp ((char*) name, (char*) "node",5) == 0) { // it's a node if (id == 0) return; onode.id = id; // d_printf ("xml.. node: %lld\n", onode.id); attr = xmlTextReaderGetAttribute (reader, (xmlChar*)"lat"); // lat if (attr == NULL) return; sscanf ((char*)attr , "%g", &onode.lat); free ((void *)attr); attr = xmlTextReaderGetAttribute (reader, (xmlChar*)"lon"); // lon if (attr == NULL) return; sscanf ((char*)attr, "%g", &onode.lon); free ((void *)attr); xmlolddepth = xmldepth; last = (void*)&onode; } else if ((strncmp ((char*) name, (char*) "tag", 3) == 0) && last == (void*)&onode) { // tag to a node? k = xmlTextReaderGetAttribute (reader, (xmlChar*)"k"); if (k == NULL) return; v = xmlTextReaderGetAttribute (reader, (xmlChar*)"v"); if (v == NULL) { free ((void *)k); return; } onoded.id = onode.id; osm_nodedetail_append (&onoded, (char*)k, (char*)v); free ((void *)k); free ((void *)v); } /* * check and process data for way or an area */ else if (strncmp ((char*) name, (char*) "way",4) == 0) { // it's a way if (id == 0) return; osm.oway->wid = id; xmlolddepth = xmldepth; last = (void*)osm.oway; } else if ((strncmp ((char*) name, (char*) "tag", 3) == 0) && last == (void*)osm.oway) { // tag to a way? k = xmlTextReaderGetAttribute (reader, (xmlChar*)"k"); if (k == NULL) return; v = xmlTextReaderGetAttribute (reader, (xmlChar*)"v"); if (v == NULL) { free ((void *)k); return; } if (strncmp ((char*) k, (char*) "highway", 8) == 0) { if (strcmp ((char*) v, (char*) "primary") == 0) osm.oway->type = MWAY_tertiary; else if (strcmp ((char*) v, (char*) "primary_link") == 0) { osm.oway->type = MWAY_tertiary; osm.oway->flags |= MWAY_F_junction; } else if (strcmp ((char*) v, (char*) "tertiary") == 0) osm.oway->type = MWAY_tertiary; else if (strcmp ((char*) v, (char*) "secondary") == 0) osm.oway->type = MWAY_tertiary; else if (strcmp ((char*) v, (char*) "motorway") == 0) osm.oway->type = MWAY_highway; else if (strcmp ((char*) v, (char*) "motorway_link") == 0) { osm.oway->type = MWAY_highway; osm.oway->flags |= MWAY_F_junction; } else if (strcmp ((char*) v, (char*) "trunk") == 0) osm.oway->type = MWAY_highway; else if (strcmp ((char*) v, (char*) "trunk_link") == 0) { osm.oway->type = MWAY_highway; osm.oway->flags |= MWAY_F_junction; } else if (strcmp ((char*) v, (char*) "residential") == 0) osm.oway->type = MWAY_residential; else if (strcmp ((char*) v, (char*) "living_street") == 0) osm.oway->type = MWAY_residential; else if (strcmp ((char*) v, (char*) "road") == 0) osm.oway->type = MWAY_residential; else if (strcmp ((char*) v, (char*) "unclassified") == 0) osm.oway->type = MWAY_residential; else if (strcmp ((char*) v, (char*) "path") == 0) osm.oway->type = MWAY_residential; else if (strcmp ((char*) v, (char*) "construction") == 0) osm.oway->type = MWAY_residential; else if (strcmp ((char*) v, (char*) "cycleway") == 0) osm.oway->type = MWAY_cycleway; else if (strcmp ((char*) v, (char*) "track") == 0) osm.oway->type = MWAY_railway; else if (strcmp ((char*) v, (char*) "service") == 0) osm.oway->type = MWAY_service; else if (strcmp ((char*) v, (char*) "platform") == 0) osm.oway->type = MWAY_footway; else if (strcmp ((char*) v, (char*) "footway") == 0) osm.oway->type = MWAY_footway; else if (strcmp ((char*) v, (char*) "pedestrian") == 0) osm.oway->type = MWAY_footway; else if (strcmp ((char*) v, (char*) "steps") == 0) osm.oway->type = MWAY_footway; else { osm.oway->type = MWAY_unknown_way; printf ("unknown highway:'%s'\n", v); } } /* * check if it is a railway */ else if (strncmp ((char*) k, (char*) "railway", 8) == 0) { if (strcmp ((char*) v, (char*) "rail") == 0) { osm.oway->flags = osm.oway->flags | MWAY_F_railway; if (osm.oway->type == MWAY_unknown || osm.oway->type == MWAY_unknown_railway) osm.oway->type = MWAY_railway; } else if (strcmp ((char*) v, (char*) "abandoned") == 0) { osm.oway->flags = osm.oway->flags | MWAY_F_railway; if (osm.oway->type == MWAY_unknown || osm.oway->type == MWAY_unknown_railway) osm.oway->type = MWAY_unknown_railway; } else { osm.oway->flags = osm.oway->flags | MWAY_F_railway; // d_printf ("unknown railway:'%s' name:%s type:%d id:%lld", v, osm.oway->name, osm.oway->type, osm.oway->wid); if (osm.oway->type == MWAY_unknown || osm.oway->type == MWAY_unknown_railway) osm.oway->type = MWAY_unknown_railway; } } /* * name ? */ else if (strncmp ((char*) k, (char*) "name", 5) == 0) { strncpy (osm.oway->name, (char*)v, MAP_W_NAMELEN); } /* * ref ? */ else if (strncmp ((char*) k, (char*) "ref", 4) == 0) { strncpy (osm.oway->ref, (char*)v, MAP_W_NAMELEN); } /* * one way ? */ else if (strncmp ((char*) k, (char*) "oneway", 7) == 0) { if (strcmp ((char*) v, (char*) "yes") == 0) osm.oway->flags = osm.oway->flags | MWAY_F_oneway; } /* * junction ? */ else if (strncmp ((char*) k, (char*) "junction", 9) == 0) { if (strcmp ((char*) v, (char*) "roundabout") == 0) osm.oway->flags |= MWAY_F_roundabout; } /* * construction ? */ else if (strncmp ((char*) k, (char*) "construction", 13) == 0) { osm.oway->flags |= MWAY_F_planed; } /* * check if we have an area */ else if (strncmp ((char*) k, (char*) "natural", 8) == 0 || strncmp ((char*) k, (char*) "landuse", 8) == 0) { if (strcmp ((char*) v, (char*) "water") == 0) osm.oway->type = MAREA_water; else if (strcmp ((char*) v, (char*) "industrial") == 0) osm.oway->type = MAREA_industrial; else if (strcmp ((char*) v, (char*) "heath") == 0) osm.oway->type = MAREA_industrial; else if (strcmp ((char*) v, (char*) "construction") == 0) osm.oway->type = MAREA_industrial; else if (strcmp ((char*) v, (char*) "commercial") == 0) osm.oway->type = MAREA_commercial; else if (strcmp ((char*) v, (char*) "retail") == 0) osm.oway->type = MAREA_commercial; else if (strcmp ((char*) v, (char*) "cemetery") == 0) osm.oway->type = MAREA_commercial; else if (strcmp ((char*) v, (char*) "farm") == 0) osm.oway->type = MAREA_farm; else if (strcmp ((char*) v, (char*) "field") == 0) osm.oway->type = MAREA_farm; else if (strcmp ((char*) v, (char*) "farmland") == 0) osm.oway->type = MAREA_farm; else if (strcmp ((char*) v, (char*) "farmyard") == 0) osm.oway->type = MAREA_farm; else if (strcmp ((char*) v, (char*) "village_green") == 0) osm.oway->type = MAREA_greenfield; else if (strcmp ((char*) v, (char*) "greenfield") == 0) osm.oway->type = MAREA_greenfield; else if (strcmp ((char*) v, (char*) "grass") == 0) osm.oway->type = MAREA_greenfield; else if (strcmp ((char*) v, (char*) "residential") == 0) osm.oway->type = MAREA_residential; else if (strcmp ((char*) v, (char*) "allotments") == 0) osm.oway->type = MAREA_residential; else if (strcmp ((char*) v, (char*) "forest") == 0) osm.oway->type = MAREA_wood; else if (strcmp ((char*) v, (char*) "meadow") == 0) osm.oway->type = MAREA_wood; else if (strcmp ((char*) v, (char*) "wood") == 0) osm.oway->type = MAREA_wood; else if (strcmp ((char*) v, (char*) "land") == 0) osm.oway->type = MAREA_land; else if (strcmp ((char*) v, (char*) "military") == 0) osm.oway->type = MAREA_military; else if (strcmp ((char*) v, (char*) "basin") == 0) osm.oway->type = MAREA_water; else if (strcmp ((char*) v, (char*) "reservoir") == 0) osm.oway->type = MAREA_water; else if (strcmp ((char*) v, (char*) "-----") == 0) osm.oway->type = MAREA_ignore; else { osm.oway->type = MAREA_ignore; // d_printf ("unknown natural+landuse:'%s'", v); } osm.oway->type += MWAY_MAX; } else if (strncmp ((char*) k, (char*) "boundary", 8) == 0 && strcmp ((char *) v, (char *) "yes") == 0) { osm.oway->type = MAREA_ignore + MWAY_MAX; } else if (strncmp ((char*) k, (char*) "man made", 8) == 0 && strcmp ((char *) v, (char *) "pipeline") == 0) { osm.oway->type = MAREA_ignore + MWAY_MAX; } else if (strncmp ((char*) k, (char*) "building", 8) == 0 && strcmp ((char *) v, (char *) "yes") == 0) { osm.oway->type = MAREA_ignore + MWAY_MAX; } else if (strncmp ((char*) k, (char*) "tourism", 8) == 0 && strcmp ((char *) v, (char *) "camp_site") == 0) { osm.oway->type = MAREA_campsite + MWAY_MAX; } free ((void *)k); free ((void *)v); } else if ((strncmp ((char*) name, (char*) "nd", 3) == 0) && last == (void*)osm.oway) { // node to a way? attr = xmlTextReaderGetAttribute (reader, (xmlChar*)"ref"); if (attr == NULL) return; id = atoll ((char*)attr); free ((void *)attr); if (osm.oway->ncnt+1 > osm.oway->nmax) { tmpoway = osm_way_alloc (osm.oway->nmax+16); osm_way_copy (tmpoway, osm.oway); ml_free (osm.oway); osm.oway = tmpoway; } osm.oway->nid[osm.oway->ncnt] = id; osm.oway->ncnt++; last = osm.oway; } else if (xmldepth == 1) { xmlolddepth = xmldepth; last = NULL; } }; int osm_loadfile_readcallback (void *context, char *buffer, int len) { int bzerr, bzlen; struct s_osm_xmlcallback *xmlcb = (struct s_osm_xmlcallback*) context; static int loopcnt; if (++loopcnt > 100) { xmlcb->filepos = ftell (xmlcb->f) / 1000; osm_file_pos = (100.0 * (float)(xmlcb->filepos) / (float)(xmlcb->filesize)); loopcnt = 0; } bzlen = BZ2_bzRead (&bzerr, xmlcb->bzf, buffer, len); if (bzerr == BZ_STREAM_END && !feof(xmlcb->f)) { /* next data stream */ unsigned char unused[BZ_MAX_UNUSED]; unsigned char *unusedTmp; int nUnused = 0; BZ2_bzReadGetUnused (&bzerr, xmlcb->bzf, (void**) &unusedTmp, &nUnused); if (nUnused > 0) memcpy (unused, unusedTmp, nUnused); BZ2_bzReadClose (&bzerr, xmlcb->bzf); xmlcb->bzf = BZ2_bzReadOpen(&bzerr, xmlcb->f, 0, 0, unused, nUnused); } if (bzerr != BZ_OK) d_printf ("%s:%d bzread: should:%d is:%d filepos:%d error:%d", __FILE__, __LINE__, bzlen, len, xmlcb->filepos, bzerr); if (bzerr == BZ_CONFIG_ERROR) d_printf ("BZ_CONFIG_ERROR"); else if (bzerr == BZ_PARAM_ERROR) d_printf ("BZ_PARAM_ERROR"); else if (bzerr == BZ_IO_ERROR) d_printf ("BZ_IO_ERROR"); else if (bzerr == BZ_MEM_ERROR) d_printf ("BZ_MEM_ERROR"); else if (bzerr == BZ_SEQUENCE_ERROR) d_printf ("BZ_SEQUENCE_ERROR"); else if (bzerr == BZ_DATA_ERROR) d_printf ("BZ_DATA_ERROR"); else if (bzerr == BZ_DATA_ERROR_MAGIC) d_printf ("BZ_DATA_ERROR_MAGIC"); else if (bzerr == BZ_UNEXPECTED_EOF) d_printf ("BZ_UNEXPECTED_EOF"); else if (bzerr != BZ_OK) d_printf ("any other bz error is there:%d", bzerr); return bzlen; }; int osm_loadfile_closecallback(void *context) { int bzerr; BZ2_bzReadClose(&bzerr, ((struct s_osm_xmlcallback *)context)->bzf); return bzerr == BZ_OK; }; void osm_loadfile (char *fn) { xmlTextReaderPtr reader; struct s_osm_xmlcallback xmlcb; int ret, compressed, i, timeout_cnt = 0, bzerr; time_t timeout; char ext[16]; osm_init (); if (fn == NULL) return; app_status (-1, _("converting file"), 0.0); d_printf ("osm_loadfile (%s)", fn); /* check the extension of the osm file */ for (i = 0; i < 15 && fn[i+strlen(fn)-4] != 0; i++) ext[i] = tolower (fn[i+strlen(fn)-4]); ext[i] = 0; if (strncmp (ext, ".bz2", 5) == 0) compressed = 1; else compressed = 0; /* set the locale to POSIX, needed for decimal numbers. */ setlocale(LC_ALL, "C"); if (compressed) { xmlcb.f = fopen (fn, "r"); if (!xmlcb.f) { d_printf ("%s:%d could not open file '%s' for reading. Error:%s", __FILE__, __LINE__, fn, strerror (errno)); return; } fseek (xmlcb.f, 0, SEEK_END); xmlcb.filesize = ftell (xmlcb.f) / 1000; fseek (xmlcb.f, 0, SEEK_SET); xmlcb.bzf = BZ2_bzReadOpen(&bzerr, xmlcb.f, 0, 0, NULL, 0); if (xmlcb.bzf == NULL || bzerr != BZ_OK) { d_printf ("%s:%d osm_loadfile could not open source file.", __FILE__, __LINE__); exit (0); } reader = xmlReaderForIO(osm_loadfile_readcallback, osm_loadfile_closecallback, &xmlcb, "", NULL, 0); } else reader = xmlReaderForFile(fn, NULL, 0); /* * read the whole file... */ if (reader != NULL) { ret = xmlTextReaderRead(reader); while (ret == 1) { osm_processdata(reader); ret = xmlTextReaderRead(reader); if (++timeout_cnt > 1000 || timeout < time(NULL)) { if (compressed) main_wnd_loop(xmlcb.filepos, xmlcb.filesize); else main_wnd_loop(xmlTextReaderGetParserLineNumber (reader), -1); timeout = time(NULL); timeout_cnt = 0; } } xmlFreeTextReader(reader); } if (compressed) { fclose (xmlcb.f); } /* check data inside the hash for waynodes */ osm_waynodes_check (); /* reset the locale setting back to the environment setting */ setlocale (LC_ALL, NULL); osm_free (); app_status (-1, _(""), 0.0); }; #define MLWEBMAX 10 void map_load_web (struct map_pos hs, struct map_pos he) { char parm1[128]; char parm2[128]; char cmd[255]; char url[128]; char *args[13]; int ret, i; float x1, y1; struct stat sb; struct map_pos h; struct { struct s_execcall p; char fcache[LEN_FILENAME]; } wl[MLWEBMAX]; d_printf ("map_load_web: (%f , %f) --> (%f , %f)", hs.lon, hs.lat, he.lon, he.lat); /* check for cache directory */ if (stat(cfg.cachepath, &sb) == -1) { char fn[LEN_FILENAME]; strncpy (fn, cfg.cachepath, LEN_FILENAME); fn[strlen(fn)-1] = 0; d_printf ("create cache dir:%s", fn); #if !defined(__MINGW32CE__) && !defined(_WIN32_WCE) && !defined(__MINGW32__) mkdir (fn, 0755); #else mkdir (fn); #endif } app.status = APPSTATUS_loadfromweb; #if defined (_LINUX_) osm_load_from_web_end = he; osm_load_from_web_start = hs; app_status (-1, _("refresh from OpenStreetMap.org"), 0.0); for (ret = 0; ret < MLWEBMAX; ret++) wl[ret].p.used = 0; for (ret = 0; ret < 13; ret++) args[ret] = NULL; for (h.lon = hs.lon; h.lon < he.lon || cmpf(h.lon, he.lon); h.lon = h.lon + MAP_OSMWEB_DELTA) for (h.lat = hs.lat; h.lat < he.lat || cmpf(h.lat, he.lat); h.lat = h.lat + MAP_OSMWEB_DELTA) { do { main_wnd_loop (-1,-1); /* check for any finished forked processes * if so, call osm_loadfile */ for (i = 0; i < MLWEBMAX; i++) { if (wl[i].p.used) { ret = execwait (&wl[i].p); if (ret == 1) { osm_loadfile (wl[i].fcache); app_status (-1, _("refresh from OpenStreetMap.org"), 0.0); main_wnd_update (); } } } for (i = 0; i < MLWEBMAX && wl[i].p.used == 1; i++); } while (i >= MLWEBMAX); /* exit if we can fork another process */ y1 = CALC_START (h.lon, MAP_OSMWEB_DELTA); x1 = CALC_START (h.lat, MAP_OSMWEB_DELTA); setlocale(LC_ALL, "C"); sprintf (wl[i].fcache, "%s/c%.4f-%.4f-%.4f-%.4f.osm", cfg.cachepath, y1-MAP_OSMWEB_DELTA, x1-MAP_OSMWEB_DELTA, y1+MAP_OSMWEB_DELTA, x1+MAP_OSMWEB_DELTA); if (stat(wl[i].fcache, &sb) == -1) { setlocale(LC_ALL, "C"); sprintf (cmd, "/usr/bin/wget"); args[0] = cmd; sprintf (parm1, "-O"); args[1] = parm1; sprintf (parm2, "%s", wl[i].fcache); args[2] = parm2; sprintf (url, "http://api.openstreetmap.org/api/0.6/map?bbox=%.5f,%.5f,%.5f,%.5f", y1-MAP_OSMWEB_DELTA, x1-MAP_OSMWEB_DELTA, y1+MAP_OSMWEB_DELTA, x1+MAP_OSMWEB_DELTA); args[3] = url; setlocale(LC_ALL, NULL); ret = execcall(&wl[i].p, cmd, args); } else { osm_loadfile (wl[i].fcache); main_wnd_update (); } } do { main_wnd_loop (-1,-1); for (i = 0; i < MLWEBMAX; i++) { if (wl[i].p.used) { ret = execwait (&wl[i].p); if (ret == 1) { osm_loadfile (wl[i].fcache); main_wnd_update (); } } } for (ret = 0, i = 0; i < MLWEBMAX; i++) if (wl[i].p.used == 1) ret = 1; } while (ret); #endif app.status = APPSTATUS_nothing; }; /*************************************************** * displaying some informations on the screen */ #ifdef HAVE_NCURSES #include void osm_convert_info () { int i; attrset(A_BOLD | COLOR_PAIR(3)); mvprintw(6,10, "OSM HashNodes Information"); attrset(COLOR_PAIR(3)); for (i = 0; i < 16; i++) mvprintw(7+i,1, "hid: hash: nodes: kb"); attrset(A_BOLD | COLOR_PAIR(2)); for (i = 0; i < 16 && i < OSM_HASHNODES; i++) { if (hashnodes[i] == NULL) continue; mvprintw(7+i,5, "%d", hashnodes[i]->hid); mvprintw(7+i,15, "%d", hashnodes[i]->hash_cnt); mvprintw(7+i,31, "%d", hashnodes[i]->nodes_end/1024); if (hashnodes[i]->hash) mvprintw(7+i, 0, "*"); else mvprintw(7+i, 0, " "); } } #endif