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.
2123 lines
63 KiB
2123 lines
63 KiB
/***************************************************************************
|
|
* 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 <locale.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <dirent.h>
|
|
#include <ctype.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/stat.h>
|
|
#include <time.h>
|
|
#include <libxml/xmlreader.h>
|
|
#include <bzlib.h>
|
|
|
|
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 (text, 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++;
|
|
|
|
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 (_("converting file"), 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);
|
|
};
|
|
|
|
|
|
#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 (_("refresh from OpenStreetMap.org"), 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 (_("refresh from OpenStreetMap.org"), 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 <curses.h>
|
|
|
|
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
|