17 |
* along with OSM2Go. If not, see <http://www.gnu.org/licenses/>. |
* along with OSM2Go. If not, see <http://www.gnu.org/licenses/>. |
18 |
*/ |
*/ |
19 |
|
|
|
/* xml parsing has a performance issue */ |
|
|
// #define OSM_DOM_PARSER |
|
|
// #define OSM_STREAM_PARSER |
|
|
#define OSM_QND_XML_PARSER |
|
|
|
|
20 |
#include <stdio.h> |
#include <stdio.h> |
21 |
#include <stdlib.h> |
#include <stdlib.h> |
22 |
#include <string.h> |
#include <string.h> |
53 |
bounds->ll_min.lon, bounds->ll_max.lon); |
bounds->ll_min.lon, bounds->ll_max.lon); |
54 |
} |
} |
55 |
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
static bounds_t *osm_parse_osm_bounds(osm_t *osm, |
|
|
xmlDocPtr doc, xmlNode *a_node) { |
|
|
char *prop; |
|
|
|
|
|
if(osm->bounds) { |
|
|
errorf(NULL, "Doubly defined bounds"); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
bounds_t *bounds = g_new0(bounds_t, 1); |
|
|
|
|
|
bounds->ll_min.lat = bounds->ll_min.lon = NAN; |
|
|
bounds->ll_max.lat = bounds->ll_max.lon = NAN; |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"minlat"))) { |
|
|
bounds->ll_min.lat = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"maxlat"))) { |
|
|
bounds->ll_max.lat = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"minlon"))) { |
|
|
bounds->ll_min.lon = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"maxlon"))) { |
|
|
bounds->ll_max.lon = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) || |
|
|
isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) { |
|
|
errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)", |
|
|
bounds->ll_min.lat, bounds->ll_min.lon, |
|
|
bounds->ll_max.lat, bounds->ll_max.lon); |
|
|
|
|
|
osm_bounds_free(bounds); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
|
|
|
/* calculate map zone which will be used as a reference for all */ |
|
|
/* drawing/projection later on */ |
|
|
pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2, |
|
|
(bounds->ll_max.lon + bounds->ll_min.lon)/2 }; |
|
|
|
|
|
pos2lpos_center(¢er, &bounds->center); |
|
|
|
|
|
/* the scale is needed to accomodate for "streching" */ |
|
|
/* by the mercartor projection */ |
|
|
bounds->scale = cos(DEG2RAD(center.lat)); |
|
|
|
|
|
pos2lpos_center(&bounds->ll_min, &bounds->min); |
|
|
bounds->min.x -= bounds->center.x; |
|
|
bounds->min.y -= bounds->center.y; |
|
|
bounds->min.x *= bounds->scale; |
|
|
bounds->min.y *= bounds->scale; |
|
|
|
|
|
pos2lpos_center(&bounds->ll_max, &bounds->max); |
|
|
bounds->max.x -= bounds->center.x; |
|
|
bounds->max.y -= bounds->center.y; |
|
|
bounds->max.x *= bounds->scale; |
|
|
bounds->max.y *= bounds->scale; |
|
|
|
|
|
return bounds; |
|
|
} |
|
|
#endif |
|
|
|
|
56 |
/* ------------------------- user handling --------------------- */ |
/* ------------------------- user handling --------------------- */ |
57 |
|
|
58 |
void osm_users_free(user_t *user) { |
void osm_users_free(user_t *user) { |
252 |
} |
} |
253 |
} |
} |
254 |
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
static node_t *osm_parse_osm_node(osm_t *osm, |
|
|
xmlDocPtr doc, xmlNode *a_node) { |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
/* allocate a new node structure */ |
|
|
node_t *node = g_new0(node_t, 1); |
|
|
node->pos.lat = node->pos.lon = NAN; |
|
|
|
|
|
char *prop; |
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) { |
|
|
node->id = strtoul(prop, NULL, 10); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"lat"))) { |
|
|
node->pos.lat = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"lon"))) { |
|
|
node->pos.lon = g_ascii_strtod(prop, NULL); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) { |
|
|
node->user = osm_user(osm, prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) { |
|
|
node->visible = (strcasecmp(prop, "true") == 0); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) { |
|
|
node->time = convert_iso8601(prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
/* scan for tags and attach a list of tags */ |
|
|
tag_t **tag = &node->tag; |
|
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
if(strcasecmp((char*)cur_node->name, "tag") == 0) { |
|
|
/* attach tag to node */ |
|
|
*tag = osm_parse_osm_tag(osm, doc, cur_node); |
|
|
if(*tag) tag = &((*tag)->next); |
|
|
} else |
|
|
printf("found unhandled osm/node/%s\n", cur_node->name); |
|
|
} |
|
|
} |
|
|
|
|
|
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
|
|
|
|
|
return node; |
|
|
} |
|
|
#endif |
|
|
|
|
255 |
/* ------------------- way handling ------------------- */ |
/* ------------------- way handling ------------------- */ |
256 |
|
|
257 |
void osm_node_chain_free(node_chain_t *node_chain) { |
void osm_node_chain_free(node_chain_t *node_chain) { |
344 |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
345 |
|
|
346 |
/* search matching node */ |
/* search matching node */ |
347 |
node_chain->node = osm->node; |
node_chain->node = osm_get_node_by_id(osm, id); |
|
while(node_chain->node && node_chain->node->id != id) |
|
|
node_chain->node = node_chain->node->next; |
|
|
|
|
348 |
if(!node_chain->node) printf("Node id %lu not found\n", id); |
if(!node_chain->node) printf("Node id %lu not found\n", id); |
349 |
|
else node_chain->node->ways++; |
|
if(node_chain->node) |
|
|
node_chain->node->ways++; |
|
350 |
|
|
351 |
xmlFree(prop); |
xmlFree(prop); |
352 |
|
|
356 |
return NULL; |
return NULL; |
357 |
} |
} |
358 |
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
static way_t *osm_parse_osm_way(osm_t *osm, |
|
|
xmlDocPtr doc, xmlNode *a_node) { |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
/* allocate a new way structure */ |
|
|
way_t *way = g_new0(way_t, 1); |
|
|
|
|
|
char *prop; |
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) { |
|
|
way->id = strtoul(prop, NULL, 10); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) { |
|
|
way->user = osm_user(osm, prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) { |
|
|
way->visible = (strcasecmp(prop, "true") == 0); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) { |
|
|
way->time = convert_iso8601(prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
/* scan for tags/nodes and attach their lists */ |
|
|
tag_t **tag = &way->tag; |
|
|
node_chain_t **node_chain = &way->node_chain; |
|
|
|
|
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
if(strcasecmp((char*)cur_node->name, "tag") == 0) { |
|
|
/* attach tag to node */ |
|
|
*tag = osm_parse_osm_tag(osm, doc, cur_node); |
|
|
if(*tag) tag = &((*tag)->next); |
|
|
} else if(strcasecmp((char*)cur_node->name, "nd") == 0) { |
|
|
*node_chain = osm_parse_osm_way_nd(osm, doc, cur_node); |
|
|
if(*node_chain) |
|
|
node_chain = &((*node_chain)->next); |
|
|
} else |
|
|
printf("found unhandled osm/node/%s\n", cur_node->name); |
|
|
} |
|
|
} |
|
|
|
|
|
return way; |
|
|
} |
|
|
#endif |
|
|
|
|
359 |
/* ------------------- relation handling ------------------- */ |
/* ------------------- relation handling ------------------- */ |
360 |
|
|
361 |
void osm_member_free(member_t *member) { |
void osm_member_free(member_t *member) { |
371 |
} |
} |
372 |
} |
} |
373 |
|
|
374 |
|
void osm_relation_free(relation_t *relation) { |
375 |
|
osm_tags_free(relation->tag); |
376 |
|
osm_members_free(relation->member); |
377 |
|
|
378 |
|
g_free(relation); |
379 |
|
} |
380 |
|
|
381 |
static void osm_relations_free(relation_t *relation) { |
static void osm_relations_free(relation_t *relation) { |
382 |
while(relation) { |
while(relation) { |
383 |
relation_t *next = relation->next; |
relation_t *next = relation->next; |
384 |
|
osm_relation_free(relation); |
|
osm_tags_free(relation->tag); |
|
|
osm_members_free(relation->member); |
|
|
|
|
|
g_free(relation); |
|
385 |
relation = next; |
relation = next; |
386 |
} |
} |
387 |
} |
} |
461 |
|
|
462 |
case WAY: |
case WAY: |
463 |
/* search matching way */ |
/* search matching way */ |
464 |
member->way = osm->way; |
member->way = osm_get_way_by_id(osm, id); |
|
while(member->way && member->way->id != id) |
|
|
member->way = member->way->next; |
|
|
|
|
465 |
if(!member->way) { |
if(!member->way) { |
466 |
member->type = WAY_ID; |
member->type = WAY_ID; |
467 |
member->id = id; |
member->id = id; |
470 |
|
|
471 |
case NODE: |
case NODE: |
472 |
/* search matching node */ |
/* search matching node */ |
473 |
member->node = osm->node; |
member->node = osm_get_node_by_id(osm, id); |
|
while(member->node && member->node->id != id) |
|
|
member->node = member->node->next; |
|
|
|
|
474 |
if(!member->node) { |
if(!member->node) { |
475 |
member->type = NODE_ID; |
member->type = NODE_ID; |
476 |
member->id = id; |
member->id = id; |
479 |
|
|
480 |
case RELATION: |
case RELATION: |
481 |
/* search matching relation */ |
/* search matching relation */ |
482 |
member->relation = osm->relation; |
member->relation = osm_get_relation_by_id(osm, id); |
|
while(member->relation && member->relation->id != id) |
|
|
member->relation = member->relation->next; |
|
|
|
|
483 |
if(!member->relation) { |
if(!member->relation) { |
484 |
member->type = NODE_ID; |
member->type = NODE_ID; |
485 |
member->id = id; |
member->id = id; |
503 |
return member; |
return member; |
504 |
} |
} |
505 |
|
|
506 |
#ifdef OSM_DOM_PARSER |
/* ------------------ osm handling ----------------- */ |
|
static relation_t *osm_parse_osm_relation(osm_t *osm, |
|
|
xmlDocPtr doc, xmlNode *a_node) { |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
/* allocate a new relation structure */ |
|
|
relation_t *relation = g_new0(relation_t, 1); |
|
|
|
|
|
char *prop; |
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"id"))) { |
|
|
relation->id = strtoul(prop, NULL, 10); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"user"))) { |
|
|
relation->user = osm_user(osm, prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"visible"))) { |
|
|
relation->visible = (strcasecmp(prop, "true") == 0); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"timestamp"))) { |
|
|
relation->time = convert_iso8601(prop); |
|
|
xmlFree(prop); |
|
|
} |
|
|
|
|
|
/* scan for tags and attach a list of tags */ |
|
|
tag_t **tag = &relation->tag; |
|
|
member_t **member = &relation->member; |
|
|
|
|
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
if(strcasecmp((char*)cur_node->name, "tag") == 0) { |
|
|
/* attach tag to node */ |
|
|
*tag = osm_parse_osm_tag(osm, doc, cur_node); |
|
|
if(*tag) tag = &((*tag)->next); |
|
|
} else if(strcasecmp((char*)cur_node->name, "member") == 0) { |
|
|
*member = osm_parse_osm_relation_member(osm, doc, cur_node); |
|
|
if(*member) member = &((*member)->next); |
|
|
} else |
|
|
printf("found unhandled osm/node/%s\n", cur_node->name); |
|
|
} |
|
|
} |
|
|
|
|
|
return relation; |
|
|
} |
|
|
|
|
|
/* ----------------------- generic xml handling -------------------------- */ |
|
|
|
|
|
/* parse loc entry */ |
|
|
static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) { |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
|
|
if (cur_node->type == XML_ELEMENT_NODE) { |
|
|
if(strcasecmp((char*)cur_node->name, "bounds") == 0) |
|
|
osm->bounds = osm_parse_osm_bounds(osm, doc, cur_node); |
|
|
else if(strcasecmp((char*)cur_node->name, "node") == 0) { |
|
|
/* parse node and attach it to chain */ |
|
|
node_t *new = osm_parse_osm_node(osm, doc, cur_node); |
|
|
if(new) { |
|
|
node_t **node = &osm->node; |
|
|
|
|
|
#ifdef OSM_SORT_ID |
|
|
/* search chain of nodes */ |
|
|
while(*node && ((*node)->id < new->id)) |
|
|
node = &(*node)->next; |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_SORT_LAST |
|
|
while(*node) node = &(*node)->next; |
|
|
#endif |
|
|
|
|
|
/* insert into chain */ |
|
|
new->next = *node; |
|
|
*node = new; |
|
|
} |
|
|
} else if(strcasecmp((char*)cur_node->name, "way") == 0) { |
|
|
/* parse way and attach it to chain */ |
|
|
way_t *new = osm_parse_osm_way(osm, doc, cur_node); |
|
|
if(new) { |
|
|
way_t **way = &osm->way; |
|
|
|
|
|
#ifdef OSM_SORT_ID |
|
|
/* insert into chain */ |
|
|
while(*way && ((*way)->id < new->id)) |
|
|
way = &(*way)->next; |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_SORT_LAST |
|
|
while(*way) way = &(*way)->next; |
|
|
#endif |
|
|
|
|
|
/* insert into chain */ |
|
|
new->next = *way; |
|
|
*way = new; |
|
|
} |
|
|
} else if(strcasecmp((char*)cur_node->name, "relation") == 0) { |
|
|
/* parse relation and attach it to chain */ |
|
|
relation_t *new = osm_parse_osm_relation(osm, doc, cur_node); |
|
|
if(new) { |
|
|
relation_t **relation = &osm->relation; |
|
|
|
|
|
#ifdef OSM_SORT_ID |
|
|
/* search chain of ways */ |
|
|
while(*relation && ((*relation)->id < new->id)) |
|
|
relation = &(*relation)->next; |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_SORT_LAST |
|
|
while(*relation) relation = &(*relation)->next; |
|
|
#endif |
|
|
|
|
|
/* insert into chain */ |
|
|
new->next = *relation; |
|
|
*relation = new; |
|
|
} |
|
|
} else |
|
|
printf("found unhandled osm/%s\n", cur_node->name); |
|
|
|
|
|
} |
|
|
} |
|
|
} |
|
|
|
|
|
/* parse root element and search for "osm" */ |
|
|
static osm_t *osm_parse_root(xmlDocPtr doc, xmlNode * a_node) { |
|
|
osm_t *osm; |
|
|
xmlNode *cur_node = NULL; |
|
|
|
|
|
/* allocate memory to hold osm file description */ |
|
|
osm = g_new0(osm_t, 1); |
|
507 |
|
|
508 |
for (cur_node = a_node; cur_node; cur_node = cur_node->next) { |
/* the two hash tables eat over 512kBytes memory and may thus be */ |
509 |
if (cur_node->type == XML_ELEMENT_NODE) { |
/* freed at any time. osm2go can work without them (albeit slower) */ |
510 |
/* parse osm osm file ... */ |
static void hash_table_free(hash_table_t *table) { |
511 |
if(strcasecmp((char*)cur_node->name, "osm") == 0) |
if(!table) return; |
512 |
osm_parse_osm(osm, doc, cur_node); |
|
513 |
else |
int i; |
514 |
printf("found unhandled %s\n", cur_node->name); |
for(i=0;i<65536;i++) { |
515 |
|
hash_item_t *item = table->hash[i]; |
516 |
|
while(item) { |
517 |
|
hash_item_t *next = item->next; |
518 |
|
g_free(item); |
519 |
|
item = next; |
520 |
} |
} |
521 |
} |
} |
|
|
|
|
return osm; |
|
522 |
} |
} |
523 |
|
|
524 |
static osm_t *osm_parse_doc(xmlDocPtr doc) { |
void osm_hash_tables_free(osm_t *osm) { |
525 |
osm_t *osm; |
hash_table_free(osm->node_hash); |
526 |
|
osm->node_hash = NULL; |
527 |
/* Get the root element node */ |
hash_table_free(osm->way_hash); |
528 |
xmlNode *root_element = xmlDocGetRootElement(doc); |
osm->way_hash = NULL; |
|
|
|
|
osm = osm_parse_root(doc, root_element); |
|
|
|
|
|
/*free the document */ |
|
|
xmlFreeDoc(doc); |
|
|
|
|
|
/* |
|
|
* Free the global variables that may |
|
|
* have been allocated by the parser. |
|
|
*/ |
|
|
xmlCleanupParser(); |
|
|
|
|
|
return osm; |
|
529 |
} |
} |
|
#endif |
|
|
|
|
|
/* ------------------ osm handling ----------------- */ |
|
530 |
|
|
531 |
void osm_free(icon_t **icon, osm_t *osm) { |
void osm_free(icon_t **icon, osm_t *osm) { |
532 |
if(!osm) return; |
if(!osm) return; |
533 |
|
|
534 |
|
osm_hash_tables_free(osm); |
535 |
|
|
536 |
if(osm->bounds) osm_bounds_free(osm->bounds); |
if(osm->bounds) osm_bounds_free(osm->bounds); |
537 |
if(osm->user) osm_users_free(osm->user); |
if(osm->user) osm_users_free(osm->user); |
538 |
if(osm->way) osm_ways_free(osm->way); |
if(osm->way) osm_ways_free(osm->way); |
549 |
osm_relations_dump(osm->relation); |
osm_relations_dump(osm->relation); |
550 |
} |
} |
551 |
|
|
552 |
#ifdef OSM_STREAM_PARSER |
/* -------------------------- stream parser ------------------- */ |
|
/* -------------------------- stream parser tests ------------------- */ |
|
553 |
|
|
554 |
#include <libxml/xmlreader.h> |
#include <libxml/xmlreader.h> |
555 |
|
|
712 |
|
|
713 |
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
714 |
|
|
715 |
|
/* append node to end of hash table if present */ |
716 |
|
if(osm->node_hash) { |
717 |
|
hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)]; |
718 |
|
while(*item) item = &(*item)->next; |
719 |
|
|
720 |
|
*item = g_new0(hash_item_t, 1); |
721 |
|
(*item)->data.node = node; |
722 |
|
} |
723 |
|
|
724 |
/* just an empty element? then return the node as it is */ |
/* just an empty element? then return the node as it is */ |
725 |
if(xmlTextReaderIsEmptyElement(reader)) |
if(xmlTextReaderIsEmptyElement(reader)) |
726 |
return node; |
return node; |
758 |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
759 |
|
|
760 |
/* search matching node */ |
/* search matching node */ |
761 |
node_chain->node = osm->node; |
node_chain->node = osm_get_node_by_id(osm, id); |
|
while(node_chain->node && node_chain->node->id != id) |
|
|
node_chain->node = node_chain->node->next; |
|
|
|
|
762 |
if(!node_chain->node) printf("Node id %lu not found\n", id); |
if(!node_chain->node) printf("Node id %lu not found\n", id); |
763 |
|
else node_chain->node->ways++; |
|
if(node_chain->node) |
|
|
node_chain->node->ways++; |
|
764 |
|
|
765 |
xmlFree(prop); |
xmlFree(prop); |
766 |
|
|
797 |
xmlFree(prop); |
xmlFree(prop); |
798 |
} |
} |
799 |
|
|
800 |
|
/* append way to end of hash table if present */ |
801 |
|
if(osm->way_hash) { |
802 |
|
hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)]; |
803 |
|
while(*item) item = &(*item)->next; |
804 |
|
|
805 |
|
*item = g_new0(hash_item_t, 1); |
806 |
|
(*item)->data.way = way; |
807 |
|
} |
808 |
|
|
809 |
/* just an empty element? then return the way as it is */ |
/* just an empty element? then return the way as it is */ |
810 |
/* (this should in fact never happen as this would be a way without nodes) */ |
/* (this should in fact never happen as this would be a way without nodes) */ |
811 |
if(xmlTextReaderIsEmptyElement(reader)) |
if(xmlTextReaderIsEmptyElement(reader)) |
861 |
|
|
862 |
case WAY: |
case WAY: |
863 |
/* search matching way */ |
/* search matching way */ |
864 |
member->way = osm->way; |
member->way = osm_get_way_by_id(osm, id); |
|
while(member->way && member->way->id != id) |
|
|
member->way = member->way->next; |
|
|
|
|
865 |
if(!member->way) { |
if(!member->way) { |
866 |
member->type = WAY_ID; |
member->type = WAY_ID; |
867 |
member->id = id; |
member->id = id; |
870 |
|
|
871 |
case NODE: |
case NODE: |
872 |
/* search matching node */ |
/* search matching node */ |
873 |
member->node = osm->node; |
member->node = osm_get_node_by_id(osm, id); |
|
while(member->node && member->node->id != id) |
|
|
member->node = member->node->next; |
|
|
|
|
874 |
if(!member->node) { |
if(!member->node) { |
875 |
member->type = NODE_ID; |
member->type = NODE_ID; |
876 |
member->id = id; |
member->id = id; |
879 |
|
|
880 |
case RELATION: |
case RELATION: |
881 |
/* search matching relation */ |
/* search matching relation */ |
882 |
member->relation = osm->relation; |
member->relation = osm_get_relation_by_id(osm, id); |
|
while(member->relation && member->relation->id != id) |
|
|
member->relation = member->relation->next; |
|
|
|
|
883 |
if(!member->relation) { |
if(!member->relation) { |
884 |
member->type = NODE_ID; |
member->type = NODE_ID; |
885 |
member->id = id; |
member->id = id; |
965 |
static osm_t *process_osm(xmlTextReaderPtr reader) { |
static osm_t *process_osm(xmlTextReaderPtr reader) { |
966 |
/* alloc osm structure */ |
/* alloc osm structure */ |
967 |
osm_t *osm = g_new0(osm_t, 1); |
osm_t *osm = g_new0(osm_t, 1); |
968 |
|
osm->node_hash = g_new0(hash_table_t, 1); |
969 |
|
osm->way_hash = g_new0(hash_table_t, 1); |
970 |
|
|
971 |
node_t **node = &osm->node; |
node_t **node = &osm->node; |
972 |
way_t **way = &osm->way; |
way_t **way = &osm->way; |
1049 |
return osm; |
return osm; |
1050 |
} |
} |
1051 |
|
|
1052 |
/* ----------------------- end of stream parser tests ------------------- */ |
/* ----------------------- end of stream parser ------------------- */ |
|
#endif |
|
1053 |
|
|
1054 |
#ifdef OSM_QND_XML_PARSER |
#include <sys/time.h> |
|
/* -------------------------- qnd-xml parser tests ------------------- */ |
|
1055 |
|
|
1056 |
#ifdef USE_FLOAT |
osm_t *osm_parse(char *filename) { |
|
#define GET_PROP_POS(a,b,c) qnd_xml_get_prop_float(a, b, c) |
|
|
#else |
|
|
#define GET_PROP_POS(a,b,c) qnd_xml_get_prop_double(a, b, c) |
|
|
#endif |
|
1057 |
|
|
1058 |
gboolean osm_bounds_cb(qnd_xml_stack_t *stack, |
struct timeval start; |
1059 |
qnd_xml_attribute_t *attributes, gpointer data) { |
gettimeofday(&start, NULL); |
1060 |
|
|
1061 |
/* get parent pointer */ |
LIBXML_TEST_VERSION; |
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
|
1062 |
|
|
1063 |
if(osm->bounds) { |
// use stream parser |
1064 |
errorf(NULL, "Doubly defined bounds"); |
osm_t *osm = process_file(filename); |
1065 |
return FALSE; |
xmlCleanupParser(); |
|
} |
|
1066 |
|
|
1067 |
bounds_t *bounds = osm->bounds = g_new0(bounds_t, 1); |
struct timeval end; |
1068 |
|
gettimeofday(&end, NULL); |
1069 |
|
|
1070 |
bounds->ll_min.lat = bounds->ll_min.lon = NAN; |
printf("total parse time: %ldms\n", |
1071 |
bounds->ll_max.lat = bounds->ll_max.lon = NAN; |
(end.tv_usec - start.tv_usec)/1000 + |
1072 |
|
(end.tv_sec - start.tv_sec)*1000); |
1073 |
|
|
1074 |
GET_PROP_POS(attributes, "minlat", &bounds->ll_min.lat); |
return osm; |
1075 |
GET_PROP_POS(attributes, "minlon", &bounds->ll_min.lon); |
} |
|
GET_PROP_POS(attributes, "maxlat", &bounds->ll_max.lat); |
|
|
GET_PROP_POS(attributes, "maxlon", &bounds->ll_max.lon); |
|
|
|
|
|
if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) || |
|
|
isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) { |
|
|
errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)", |
|
|
bounds->ll_min.lat, bounds->ll_min.lon, |
|
|
bounds->ll_max.lat, bounds->ll_max.lon); |
|
|
|
|
|
osm_bounds_free(bounds); |
|
|
osm->bounds = NULL; |
|
|
return FALSE; |
|
|
} |
|
|
|
|
|
|
|
|
/* calculate map zone which will be used as a reference for all */ |
|
|
/* drawing/projection later on */ |
|
|
pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2, |
|
|
(bounds->ll_max.lon + bounds->ll_min.lon)/2 }; |
|
|
|
|
|
pos2lpos_center(¢er, &bounds->center); |
|
|
|
|
|
/* the scale is needed to accomodate for "streching" */ |
|
|
/* by the mercartor projection */ |
|
|
bounds->scale = cos(DEG2RAD(center.lat)); |
|
|
|
|
|
pos2lpos_center(&bounds->ll_min, &bounds->min); |
|
|
bounds->min.x -= bounds->center.x; |
|
|
bounds->min.y -= bounds->center.y; |
|
|
bounds->min.x *= bounds->scale; |
|
|
bounds->min.y *= bounds->scale; |
|
|
|
|
|
pos2lpos_center(&bounds->ll_max, &bounds->max); |
|
|
bounds->max.x -= bounds->center.x; |
|
|
bounds->max.y -= bounds->center.y; |
|
|
bounds->max.x *= bounds->scale; |
|
|
bounds->max.y *= bounds->scale; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
static gboolean osm_tag_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
tag_t *tag = *(tag_t**)stack->prev->userdata[1] = g_new0(tag_t, 1); |
|
|
|
|
|
tag->key = qnd_xml_get_prop_str(attributes, "k"); |
|
|
tag->value = qnd_xml_get_prop_str(attributes, "v"); |
|
|
|
|
|
if(!tag->key || !tag->value) { |
|
|
printf("incomplete tag key/value %s/%s\n", tag->key, tag->value); |
|
|
osm_tags_free(tag); |
|
|
tag = NULL; |
|
|
} else |
|
|
stack->prev->userdata[1] = &tag->next; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
static gboolean osm_node_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
|
|
|
|
|
/* allocate a new node structure. userdata[1] points to the current */ |
|
|
/* position a new node is to be stored */ |
|
|
node_t *node = *(node_t**)stack->prev->userdata[1] = |
|
|
stack->userdata[0] = g_new0(node_t, 1); |
|
|
stack->prev->userdata[1] = &node->next; |
|
|
|
|
|
qnd_xml_get_prop_gulong(attributes, "id", &node->id); |
|
|
GET_PROP_POS(attributes, "lat", &node->pos.lat); |
|
|
GET_PROP_POS(attributes, "lon", &node->pos.lon); |
|
|
node->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
|
|
node->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
|
|
node->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
|
|
|
|
|
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
|
|
|
|
|
/* store current tag pointer in userdata for fast access to current tag */ |
|
|
stack->userdata[1] = &node->tag; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
static gboolean osm_way_nd_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->prev->userdata[0]; |
|
|
|
|
|
item_id_t id; |
|
|
if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) { |
|
|
/* allocate a new node_chain structure */ |
|
|
node_chain_t *node_chain = *(node_chain_t**)stack->prev->userdata[2] = |
|
|
g_new0(node_chain_t, 1); |
|
|
|
|
|
/* search matching node */ |
|
|
node_chain->node = osm->node; |
|
|
while(node_chain->node && node_chain->node->id != id) |
|
|
node_chain->node = node_chain->node->next; |
|
|
|
|
|
if(!node_chain->node) printf("Node id %lu not found\n", id); |
|
|
|
|
|
if(node_chain->node) |
|
|
node_chain->node->ways++; |
|
|
|
|
|
stack->prev->userdata[2] = &node_chain->next; |
|
|
} |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
gboolean osm_way_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
|
|
|
|
|
/* allocate a new way structure. userdata[2] points to the current */ |
|
|
/* position a new way is to be stored in the way list */ |
|
|
way_t *way = *(way_t**)stack->prev->userdata[2] = |
|
|
stack->userdata[0] = g_new0(way_t, 1); |
|
|
stack->prev->userdata[2] = &way->next; |
|
|
|
|
|
qnd_xml_get_prop_gulong(attributes, "id", &way->id); |
|
|
way->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
|
|
way->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
|
|
way->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
|
|
|
|
|
/* store current tag and node_chain pointers in userdata for fast */ |
|
|
/* access to current tag/node_chain entry */ |
|
|
stack->userdata[1] = &way->tag; |
|
|
stack->userdata[2] = &way->node_chain; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
static gboolean osm_rel_member_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->prev->userdata[0]; |
|
|
|
|
|
member_t *member = *(member_t**)stack->prev->userdata[2] = |
|
|
g_new0(member_t, 1); |
|
|
stack->prev->userdata[2] = &member->next; |
|
|
member->type = ILLEGAL; |
|
|
|
|
|
char *type = qnd_xml_get_prop(attributes, "type"); |
|
|
if(type) { |
|
|
if(strcasecmp(type, "way") == 0) member->type = WAY; |
|
|
else if(strcasecmp(type, "node") == 0) member->type = NODE; |
|
|
else if(strcasecmp(type, "relation") == 0) member->type = RELATION; |
|
|
} |
|
|
|
|
|
item_id_t id; |
|
|
if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) { |
|
|
switch(member->type) { |
|
|
case ILLEGAL: |
|
|
printf("Unable to store illegal type\n"); |
|
|
break; |
|
|
|
|
|
case WAY: |
|
|
/* search matching way */ |
|
|
member->way = osm->way; |
|
|
while(member->way && member->way->id != id) |
|
|
member->way = member->way->next; |
|
|
|
|
|
if(!member->way) { |
|
|
member->type = WAY_ID; |
|
|
member->id = id; |
|
|
} |
|
|
break; |
|
|
|
|
|
case NODE: |
|
|
/* search matching node */ |
|
|
member->node = osm->node; |
|
|
while(member->node && member->node->id != id) |
|
|
member->node = member->node->next; |
|
|
|
|
|
if(!member->node) { |
|
|
member->type = NODE_ID; |
|
|
member->id = id; |
|
|
} |
|
|
break; |
|
|
|
|
|
case RELATION: |
|
|
/* search matching relation */ |
|
|
member->relation = osm->relation; |
|
|
while(member->relation && member->relation->id != id) |
|
|
member->relation = member->relation->next; |
|
|
|
|
|
if(!member->relation) { |
|
|
member->type = NODE_ID; |
|
|
member->id = id; |
|
|
} |
|
|
break; |
|
|
|
|
|
case WAY_ID: |
|
|
case NODE_ID: |
|
|
case RELATION_ID: |
|
|
break; |
|
|
} |
|
|
} |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
gboolean osm_rel_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
|
|
|
|
|
/* allocate a new relation structure. userdata[3] points to the current */ |
|
|
/* position a new relation is to be stored at in the relation list */ |
|
|
relation_t *relation = *(relation_t**)stack->prev->userdata[3] = |
|
|
stack->userdata[0] = g_new0(relation_t, 1); |
|
|
stack->prev->userdata[3] = &relation->next; |
|
|
|
|
|
qnd_xml_get_prop_gulong(attributes, "id", &relation->id); |
|
|
relation->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
|
|
relation->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
|
|
relation->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
|
|
|
|
|
/* store current tag and member pointers in userdata for fast access */ |
|
|
/* to current tag and members in their chains */ |
|
|
stack->userdata[1] = &relation->tag; |
|
|
stack->userdata[2] = &relation->member; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
gboolean osm_cb(qnd_xml_stack_t *stack, |
|
|
qnd_xml_attribute_t *attributes, gpointer data) { |
|
|
|
|
|
g_assert(!stack->userdata[0]); |
|
|
|
|
|
/* also set parents (roots) userdata as it's the parsers return value */ |
|
|
osm_t *osm = stack->prev->userdata[0] = |
|
|
stack->userdata[0] = g_new0(osm_t, 1); |
|
|
|
|
|
/* store direct pointers for faster list access */ |
|
|
/* (otherwise we'd have to search the end of the lists for every item */ |
|
|
/* to be attached) */ |
|
|
stack->userdata[1] = &osm->node; |
|
|
stack->userdata[2] = &osm->way; |
|
|
stack->userdata[3] = &osm->relation; |
|
|
|
|
|
return TRUE; |
|
|
} |
|
|
|
|
|
|
|
|
/* these structures describe the content qnd_xml expects while parsing */ |
|
|
qnd_xml_entry_t osm_node_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
|
|
|
|
|
qnd_xml_entry_t osm_way_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
|
|
qnd_xml_entry_t osm_way_nd = { "nd", osm_way_nd_cb, QND_XML_LEAF }; |
|
|
|
|
|
qnd_xml_entry_t osm_rel_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
|
|
qnd_xml_entry_t osm_rel_member = { "member", osm_rel_member_cb, QND_XML_LEAF }; |
|
|
|
|
|
qnd_xml_entry_t osm_bounds = { "bounds", osm_bounds_cb, QND_XML_LEAF }; |
|
|
|
|
|
qnd_xml_entry_t *node_children[] = { &osm_node_tag }, |
|
|
osm_node = { "node", osm_node_cb, QND_XML_CHILDREN(node_children) }; |
|
|
|
|
|
qnd_xml_entry_t *way_children[] = { &osm_way_tag, &osm_way_nd }, |
|
|
osm_way = { "way", osm_way_cb, QND_XML_CHILDREN(way_children) }; |
|
|
|
|
|
qnd_xml_entry_t *rel_children[] = { &osm_rel_tag, &osm_rel_member }, |
|
|
osm_rel = { "rel", osm_rel_cb, QND_XML_CHILDREN(rel_children) }; |
|
|
|
|
|
/* the osm element */ |
|
|
qnd_xml_entry_t *osm_children[] = { |
|
|
&osm_bounds, &osm_node, &osm_way, &osm_rel }; |
|
|
qnd_xml_entry_t osm = { "osm", osm_cb, QND_XML_CHILDREN(osm_children) }; |
|
|
|
|
|
/* the root element */ |
|
|
qnd_xml_entry_t *root_children[] = { &osm }; |
|
|
qnd_xml_entry_t root = { "<root>", NULL, QND_XML_CHILDREN(root_children) }; |
|
|
|
|
|
// gcc `pkg-config --cflags --libs glib-2.0` -o qnd_xml qnd_xml.c |
|
|
|
|
|
|
|
|
|
|
|
/* ----------------------- end of qnd-xml parser tests ------------------- */ |
|
|
#endif |
|
|
|
|
|
|
|
|
#include <sys/time.h> |
|
|
|
|
|
osm_t *osm_parse(char *filename) { |
|
|
|
|
|
struct timeval start; |
|
|
gettimeofday(&start, NULL); |
|
|
|
|
|
|
|
|
#ifdef OSM_STREAM_PARSER |
|
|
LIBXML_TEST_VERSION; |
|
|
|
|
|
// use stream parser |
|
|
osm_t *osm = process_file(filename); |
|
|
xmlCleanupParser(); |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_DOM_PARSER |
|
|
LIBXML_TEST_VERSION; |
|
|
|
|
|
// parse into a tree |
|
|
/* parse the file and get the DOM */ |
|
|
xmlDoc *doc = NULL; |
|
|
if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) { |
|
|
xmlErrorPtr errP = xmlGetLastError(); |
|
|
errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message); |
|
|
return NULL; |
|
|
} |
|
|
|
|
|
osm_t *osm = osm_parse_doc(doc); |
|
|
#endif |
|
|
|
|
|
#ifdef OSM_QND_XML_PARSER |
|
|
osm_t *osm = NULL; |
|
|
if(!(osm = qnd_xml_parse(filename, &root, NULL))) { |
|
|
errorf(NULL, "While parsing \"%s\"", filename); |
|
|
return NULL; |
|
|
} |
|
|
#endif |
|
|
|
|
|
struct timeval end; |
|
|
gettimeofday(&end, NULL); |
|
|
|
|
|
printf("total parse time: %ldms\n", |
|
|
(end.tv_usec - start.tv_usec)/1000 + |
|
|
(end.tv_sec - start.tv_sec)*1000); |
|
|
|
|
|
return osm; |
|
|
} |
|
1076 |
|
|
1077 |
gboolean osm_sanity_check(GtkWidget *parent, osm_t *osm) { |
gboolean osm_sanity_check(GtkWidget *parent, osm_t *osm) { |
1078 |
if(!osm->bounds) { |
if(!osm->bounds) { |
1322 |
return osm_generate_xml(osm, RELATION, relation); |
return osm_generate_xml(osm, RELATION, relation); |
1323 |
} |
} |
1324 |
|
|
1325 |
|
/* the following three functions are eating much CPU power */ |
1326 |
|
/* as they search the objects lists. Hashing is supposed to help */ |
1327 |
node_t *osm_get_node_by_id(osm_t *osm, item_id_t id) { |
node_t *osm_get_node_by_id(osm_t *osm, item_id_t id) { |
1328 |
|
if(id > 0 && osm->node_hash) { |
1329 |
|
// use hash table if present |
1330 |
|
hash_item_t *item = osm->node_hash->hash[ID2HASH(id)]; |
1331 |
|
while(item) { |
1332 |
|
if(item->data.node->id == id) |
1333 |
|
return item->data.node; |
1334 |
|
|
1335 |
|
item = item->next; |
1336 |
|
} |
1337 |
|
} |
1338 |
|
|
1339 |
|
/* use linear search if no hash tables are present or search in hash table failed */ |
1340 |
node_t *node = osm->node; |
node_t *node = osm->node; |
1341 |
while(node) { |
while(node) { |
1342 |
if(node->id == id) |
if(node->id == id) |
1343 |
return node; |
return node; |
1344 |
|
|
1345 |
node = node->next; |
node = node->next; |
1346 |
} |
} |
1347 |
|
|
1348 |
return NULL; |
return NULL; |
1349 |
} |
} |
1350 |
|
|
1351 |
way_t *osm_get_way_by_id(osm_t *osm, item_id_t id) { |
way_t *osm_get_way_by_id(osm_t *osm, item_id_t id) { |
1352 |
|
if(id > 0 && osm->way_hash) { |
1353 |
|
// use hash table if present |
1354 |
|
hash_item_t *item = osm->way_hash->hash[ID2HASH(id)]; |
1355 |
|
while(item) { |
1356 |
|
if(item->data.way->id == id) |
1357 |
|
return item->data.way; |
1358 |
|
|
1359 |
|
item = item->next; |
1360 |
|
} |
1361 |
|
} |
1362 |
|
|
1363 |
|
/* use linear search if no hash tables are present or search on hash table failed */ |
1364 |
way_t *way = osm->way; |
way_t *way = osm->way; |
1365 |
while(way) { |
while(way) { |
1366 |
if(way->id == id) |
if(way->id == id) |
1367 |
return way; |
return way; |
1368 |
|
|
1369 |
way = way->next; |
way = way->next; |
1370 |
} |
} |
1371 |
|
|
1372 |
return NULL; |
return NULL; |
1373 |
} |
} |
1374 |
|
|
1375 |
relation_t *osm_get_relation_by_id(osm_t *osm, item_id_t id) { |
relation_t *osm_get_relation_by_id(osm_t *osm, item_id_t id) { |
1376 |
|
// use linear search |
1377 |
relation_t *relation = osm->relation; |
relation_t *relation = osm->relation; |
1378 |
while(relation) { |
while(relation) { |
1379 |
if(relation->id == id) |
if(relation->id == id) |
1431 |
return 0; |
return 0; |
1432 |
} |
} |
1433 |
|
|
1434 |
|
item_id_t osm_new_relation_id(osm_t *osm) { |
1435 |
|
item_id_t id = -1; |
1436 |
|
|
1437 |
|
while(TRUE) { |
1438 |
|
gboolean found = FALSE; |
1439 |
|
relation_t *relation = osm->relation; |
1440 |
|
while(relation) { |
1441 |
|
if(relation->id == id) |
1442 |
|
found = TRUE; |
1443 |
|
|
1444 |
|
relation = relation->next; |
1445 |
|
} |
1446 |
|
|
1447 |
|
/* no such id so far -> use it */ |
1448 |
|
if(!found) return id; |
1449 |
|
|
1450 |
|
id--; |
1451 |
|
} |
1452 |
|
g_assert(0); |
1453 |
|
return 0; |
1454 |
|
} |
1455 |
|
|
1456 |
node_t *osm_node_new(osm_t *osm, gint x, gint y) { |
node_t *osm_node_new(osm_t *osm, gint x, gint y) { |
1457 |
printf("Creating new node\n"); |
printf("Creating new node\n"); |
1458 |
|
|
1489 |
*lnode = node; |
*lnode = node; |
1490 |
} |
} |
1491 |
|
|
1492 |
|
void osm_node_restore(osm_t *osm, node_t *node) { |
1493 |
|
printf("Restoring node\n"); |
1494 |
|
|
1495 |
|
/* attach to end of node list */ |
1496 |
|
node_t **lnode = &osm->node; |
1497 |
|
while(*lnode) lnode = &(*lnode)->next; |
1498 |
|
*lnode = node; |
1499 |
|
} |
1500 |
|
|
1501 |
way_t *osm_way_new(void) { |
way_t *osm_way_new(void) { |
1502 |
printf("Creating new way\n"); |
printf("Creating new way\n"); |
1503 |
|
|
1774 |
} |
} |
1775 |
} |
} |
1776 |
|
|
1777 |
|
relation_t *osm_relation_new(void) { |
1778 |
|
printf("Creating new relation\n"); |
1779 |
|
|
1780 |
|
relation_t *relation = g_new0(relation_t, 1); |
1781 |
|
relation->visible = TRUE; |
1782 |
|
relation->flags = OSM_FLAG_NEW; |
1783 |
|
relation->time = time(NULL); |
1784 |
|
|
1785 |
|
/* add created_by tag */ |
1786 |
|
relation->tag = g_new0(tag_t, 1); |
1787 |
|
relation->tag->key = g_strdup("created_by"); |
1788 |
|
relation->tag->value = g_strdup(PACKAGE " v" VERSION); |
1789 |
|
|
1790 |
|
return relation; |
1791 |
|
} |
1792 |
|
|
1793 |
|
void osm_relation_attach(osm_t *osm, relation_t *relation) { |
1794 |
|
printf("Attaching relation\n"); |
1795 |
|
|
1796 |
|
relation->id = osm_new_relation_id(osm); |
1797 |
|
relation->flags = OSM_FLAG_NEW; |
1798 |
|
|
1799 |
|
/* attach to end of relation list */ |
1800 |
|
relation_t **lrelation = &osm->relation; |
1801 |
|
while(*lrelation) lrelation = &(*lrelation)->next; |
1802 |
|
*lrelation = relation; |
1803 |
|
} |
1804 |
|
|
1805 |
|
|
1806 |
void osm_way_delete(osm_t *osm, icon_t **icon, |
void osm_way_delete(osm_t *osm, icon_t **icon, |
1807 |
way_t *way, gboolean permanently) { |
way_t *way, gboolean permanently) { |
1808 |
|
|
1866 |
} |
} |
1867 |
} |
} |
1868 |
|
|
1869 |
|
void osm_relation_delete(osm_t *osm, relation_t *relation, |
1870 |
|
gboolean permanently) { |
1871 |
|
|
1872 |
|
/* new relations aren't stored on the server and are just */ |
1873 |
|
/* deleted permanently */ |
1874 |
|
if(relation->flags & OSM_FLAG_NEW) { |
1875 |
|
printf("About to delete NEW relation #%ld -> force permanent delete\n", |
1876 |
|
relation->id); |
1877 |
|
permanently = TRUE; |
1878 |
|
} |
1879 |
|
|
1880 |
|
/* the deletion of a relation doesn't affect the members as they */ |
1881 |
|
/* don't have any reference to the relation they are part of */ |
1882 |
|
|
1883 |
|
if(!permanently) { |
1884 |
|
printf("mark relation #%ld as deleted\n", relation->id); |
1885 |
|
relation->flags |= OSM_FLAG_DELETED; |
1886 |
|
} else { |
1887 |
|
printf("permanently delete relation #%ld\n", relation->id); |
1888 |
|
|
1889 |
|
/* remove it from the chain */ |
1890 |
|
relation_t **crelation = &osm->relation; |
1891 |
|
int found = 0; |
1892 |
|
|
1893 |
|
while(*crelation) { |
1894 |
|
if(*crelation == relation) { |
1895 |
|
found++; |
1896 |
|
*crelation = (*crelation)->next; |
1897 |
|
|
1898 |
|
osm_relation_free(relation); |
1899 |
|
} else |
1900 |
|
crelation = &((*crelation)->next); |
1901 |
|
} |
1902 |
|
g_assert(found == 1); |
1903 |
|
} |
1904 |
|
} |
1905 |
|
|
1906 |
void osm_way_revert(way_t *way) { |
void osm_way_revert(way_t *way) { |
1907 |
node_chain_t *new = NULL; |
node_chain_t *new = NULL; |
1908 |
|
|
1978 |
|
|
1979 |
return new_tags; |
return new_tags; |
1980 |
} |
} |
1981 |
|
|
1982 |
|
/* return plain text of type */ |
1983 |
|
char *osm_type_string(type_t type) { |
1984 |
|
const struct { type_t type; char *name; } types[] = { |
1985 |
|
{ ILLEGAL, "illegal" }, |
1986 |
|
{ NODE, "node" }, |
1987 |
|
{ WAY, "way" }, |
1988 |
|
{ RELATION, "relation" }, |
1989 |
|
{ NODE_ID, "node id" }, |
1990 |
|
{ WAY_ID, "way id" }, |
1991 |
|
{ RELATION_ID, "relation id" }, |
1992 |
|
{ 0, NULL } |
1993 |
|
}; |
1994 |
|
|
1995 |
|
int i; |
1996 |
|
for(i=0;types[i].name;i++) |
1997 |
|
if(type == types[i].type) |
1998 |
|
return types[i].name; |
1999 |
|
|
2000 |
|
return NULL; |
2001 |
|
} |
2002 |
|
|
2003 |
|
char *osm_object_string(type_t type, void *object) { |
2004 |
|
char *type_str = osm_type_string(type); |
2005 |
|
|
2006 |
|
if(!object) |
2007 |
|
return g_strdup_printf("%s #<invalid>", type_str); |
2008 |
|
|
2009 |
|
switch(type) { |
2010 |
|
case ILLEGAL: |
2011 |
|
return g_strdup_printf("%s #<unspec>", type_str); |
2012 |
|
break; |
2013 |
|
case NODE: |
2014 |
|
return g_strdup_printf("%s #%ld", type_str, ((node_t*)object)->id); |
2015 |
|
break; |
2016 |
|
case WAY: |
2017 |
|
return g_strdup_printf("%s #%ld", type_str, ((way_t*)object)->id); |
2018 |
|
break; |
2019 |
|
case RELATION: |
2020 |
|
return g_strdup_printf("%s #%ld", type_str, ((relation_t*)object)->id); |
2021 |
|
break; |
2022 |
|
case NODE_ID: |
2023 |
|
case WAY_ID: |
2024 |
|
case RELATION_ID: |
2025 |
|
return g_strdup_printf("%s #%ld", type_str, ((item_id_t)object)); |
2026 |
|
break; |
2027 |
|
} |
2028 |
|
return NULL; |
2029 |
|
} |
2030 |
|
|
2031 |
|
char *osm_id_string(type_t type, void *object) { |
2032 |
|
if(!object) return NULL; |
2033 |
|
|
2034 |
|
switch(type) { |
2035 |
|
case ILLEGAL: |
2036 |
|
return NULL; |
2037 |
|
break; |
2038 |
|
case NODE: |
2039 |
|
return g_strdup_printf("#%ld", ((node_t*)object)->id); |
2040 |
|
break; |
2041 |
|
case WAY: |
2042 |
|
return g_strdup_printf("#%ld", ((way_t*)object)->id); |
2043 |
|
break; |
2044 |
|
case RELATION: |
2045 |
|
return g_strdup_printf("#%ld", ((relation_t*)object)->id); |
2046 |
|
break; |
2047 |
|
case NODE_ID: |
2048 |
|
case WAY_ID: |
2049 |
|
case RELATION_ID: |
2050 |
|
return g_strdup_printf("#%ld", ((item_id_t)object)); |
2051 |
|
break; |
2052 |
|
} |
2053 |
|
return NULL; |
2054 |
|
} |
2055 |
|
|
2056 |
|
tag_t *osm_object_get_tags(type_t type, void *object) { |
2057 |
|
if(!object) return NULL; |
2058 |
|
|
2059 |
|
switch(type) { |
2060 |
|
case ILLEGAL: |
2061 |
|
return NULL; |
2062 |
|
break; |
2063 |
|
case NODE: |
2064 |
|
return ((node_t*)object)->tag; |
2065 |
|
break; |
2066 |
|
case WAY: |
2067 |
|
return ((way_t*)object)->tag; |
2068 |
|
break; |
2069 |
|
case RELATION: |
2070 |
|
return ((relation_t*)object)->tag; |
2071 |
|
break; |
2072 |
|
case NODE_ID: |
2073 |
|
case WAY_ID: |
2074 |
|
case RELATION_ID: |
2075 |
|
return NULL; |
2076 |
|
break; |
2077 |
|
} |
2078 |
|
return NULL; |
2079 |
|
} |
2080 |
|
|
2081 |
|
|
2082 |
|
gint osm_relation_members_num(relation_t *relation) { |
2083 |
|
gint num = 0; |
2084 |
|
member_t *member = relation->member; |
2085 |
|
while(member) { |
2086 |
|
num++; |
2087 |
|
member = member->next; |
2088 |
|
} |
2089 |
|
return num; |
2090 |
|
} |
2091 |
|
|
2092 |
// vim:et:ts=8:sw=2:sts=2:ai |
// vim:et:ts=8:sw=2:sts=2:ai |