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 |
|
|
20 |
#define OSM_STREAM_PARSER |
/* these defines select one of three possible xml parsers */ |
21 |
|
/* this is in fact selected depending on the plattform in the Makefile */ |
22 |
|
// #define OSM_DOM_PARSER |
23 |
|
// #define OSM_STREAM_PARSER |
24 |
|
|
25 |
#include <stdio.h> |
#include <stdio.h> |
26 |
#include <stdlib.h> |
#include <stdlib.h> |
58 |
bounds->ll_min.lon, bounds->ll_max.lon); |
bounds->ll_min.lon, bounds->ll_max.lon); |
59 |
} |
} |
60 |
|
|
61 |
#ifndef OSM_STREAM_PARSER |
#ifdef OSM_DOM_PARSER |
62 |
static bounds_t *osm_parse_osm_bounds(osm_t *osm, |
static bounds_t *osm_parse_osm_bounds(osm_t *osm, |
63 |
xmlDocPtr doc, xmlNode *a_node) { |
xmlDocPtr doc, xmlNode *a_node) { |
64 |
char *prop; |
char *prop; |
153 |
} |
} |
154 |
|
|
155 |
static user_t *osm_user(osm_t *osm, char *name) { |
static user_t *osm_user(osm_t *osm, char *name) { |
156 |
|
if(!name) return NULL; |
157 |
|
|
158 |
/* search through user list */ |
/* search through user list */ |
159 |
user_t **user = &osm->user; |
user_t **user = &osm->user; |
175 |
|
|
176 |
static |
static |
177 |
time_t convert_iso8601(const char *str) { |
time_t convert_iso8601(const char *str) { |
178 |
|
if(!str) return 0; |
179 |
|
|
180 |
tzset(); |
tzset(); |
181 |
|
|
182 |
struct tm ctime; |
struct tm ctime; |
330 |
} |
} |
331 |
} |
} |
332 |
|
|
333 |
#ifndef OSM_STREAM_PARSER |
#ifdef OSM_DOM_PARSER |
334 |
static node_t *osm_parse_osm_node(osm_t *osm, |
static node_t *osm_parse_osm_node(osm_t *osm, |
335 |
xmlDocPtr doc, xmlNode *a_node) { |
xmlDocPtr doc, xmlNode *a_node) { |
336 |
xmlNode *cur_node = NULL; |
xmlNode *cur_node = NULL; |
370 |
xmlFree(prop); |
xmlFree(prop); |
371 |
} |
} |
372 |
|
|
373 |
|
/* append node to end of hash table if present */ |
374 |
|
if(osm->node_hash) { |
375 |
|
hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)]; |
376 |
|
while(*item) item = &(*item)->next; |
377 |
|
|
378 |
|
*item = g_new0(hash_item_t, 1); |
379 |
|
(*item)->data.node = node; |
380 |
|
} |
381 |
|
|
382 |
/* scan for tags and attach a list of tags */ |
/* scan for tags and attach a list of tags */ |
383 |
tag_t **tag = &node->tag; |
tag_t **tag = &node->tag; |
384 |
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
for (cur_node = a_node->children; cur_node; cur_node = cur_node->next) { |
490 |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
491 |
|
|
492 |
/* search matching node */ |
/* search matching node */ |
493 |
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; |
|
|
|
|
494 |
if(!node_chain->node) printf("Node id %lu not found\n", id); |
if(!node_chain->node) printf("Node id %lu not found\n", id); |
495 |
|
else node_chain->node->ways++; |
|
if(node_chain->node) |
|
|
node_chain->node->ways++; |
|
496 |
|
|
497 |
xmlFree(prop); |
xmlFree(prop); |
498 |
|
|
502 |
return NULL; |
return NULL; |
503 |
} |
} |
504 |
|
|
505 |
#ifndef OSM_STREAM_PARSER |
#ifdef OSM_DOM_PARSER |
506 |
static way_t *osm_parse_osm_way(osm_t *osm, |
static way_t *osm_parse_osm_way(osm_t *osm, |
507 |
xmlDocPtr doc, xmlNode *a_node) { |
xmlDocPtr doc, xmlNode *a_node) { |
508 |
xmlNode *cur_node = NULL; |
xmlNode *cur_node = NULL; |
531 |
xmlFree(prop); |
xmlFree(prop); |
532 |
} |
} |
533 |
|
|
534 |
|
/* append way to end of hash table if present */ |
535 |
|
if(osm->way_hash) { |
536 |
|
hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)]; |
537 |
|
while(*item) item = &(*item)->next; |
538 |
|
|
539 |
|
*item = g_new0(hash_item_t, 1); |
540 |
|
(*item)->data.way = way; |
541 |
|
} |
542 |
|
|
543 |
/* scan for tags/nodes and attach their lists */ |
/* scan for tags/nodes and attach their lists */ |
544 |
tag_t **tag = &way->tag; |
tag_t **tag = &way->tag; |
545 |
node_chain_t **node_chain = &way->node_chain; |
node_chain_t **node_chain = &way->node_chain; |
578 |
} |
} |
579 |
} |
} |
580 |
|
|
581 |
|
void osm_relation_free(relation_t *relation) { |
582 |
|
osm_tags_free(relation->tag); |
583 |
|
osm_members_free(relation->member); |
584 |
|
|
585 |
|
g_free(relation); |
586 |
|
} |
587 |
|
|
588 |
static void osm_relations_free(relation_t *relation) { |
static void osm_relations_free(relation_t *relation) { |
589 |
while(relation) { |
while(relation) { |
590 |
relation_t *next = relation->next; |
relation_t *next = relation->next; |
591 |
|
osm_relation_free(relation); |
|
osm_tags_free(relation->tag); |
|
|
osm_members_free(relation->member); |
|
|
|
|
|
g_free(relation); |
|
592 |
relation = next; |
relation = next; |
593 |
} |
} |
594 |
} |
} |
668 |
|
|
669 |
case WAY: |
case WAY: |
670 |
/* search matching way */ |
/* search matching way */ |
671 |
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; |
|
|
|
|
672 |
if(!member->way) { |
if(!member->way) { |
673 |
member->type = WAY_ID; |
member->type = WAY_ID; |
674 |
member->id = id; |
member->id = id; |
677 |
|
|
678 |
case NODE: |
case NODE: |
679 |
/* search matching node */ |
/* search matching node */ |
680 |
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; |
|
|
|
|
681 |
if(!member->node) { |
if(!member->node) { |
682 |
member->type = NODE_ID; |
member->type = NODE_ID; |
683 |
member->id = id; |
member->id = id; |
686 |
|
|
687 |
case RELATION: |
case RELATION: |
688 |
/* search matching relation */ |
/* search matching relation */ |
689 |
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; |
|
|
|
|
690 |
if(!member->relation) { |
if(!member->relation) { |
691 |
member->type = NODE_ID; |
member->type = NODE_ID; |
692 |
member->id = id; |
member->id = id; |
710 |
return member; |
return member; |
711 |
} |
} |
712 |
|
|
713 |
#ifndef OSM_STREAM_PARSER |
#ifdef OSM_DOM_PARSER |
714 |
static relation_t *osm_parse_osm_relation(osm_t *osm, |
static relation_t *osm_parse_osm_relation(osm_t *osm, |
715 |
xmlDocPtr doc, xmlNode *a_node) { |
xmlDocPtr doc, xmlNode *a_node) { |
716 |
xmlNode *cur_node = NULL; |
xmlNode *cur_node = NULL; |
762 |
|
|
763 |
/* ----------------------- generic xml handling -------------------------- */ |
/* ----------------------- generic xml handling -------------------------- */ |
764 |
|
|
765 |
/* parse loc entry */ |
/* parse osm entry */ |
766 |
static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) { |
static void osm_parse_osm(osm_t *osm, xmlDocPtr doc, xmlNode * a_node) { |
767 |
xmlNode *cur_node = NULL; |
xmlNode *cur_node = NULL; |
768 |
|
|
844 |
|
|
845 |
/* allocate memory to hold osm file description */ |
/* allocate memory to hold osm file description */ |
846 |
osm = g_new0(osm_t, 1); |
osm = g_new0(osm_t, 1); |
847 |
|
osm->node_hash = g_new0(hash_table_t, 1); |
848 |
|
osm->way_hash = g_new0(hash_table_t, 1); |
849 |
|
|
850 |
for (cur_node = a_node; cur_node; cur_node = cur_node->next) { |
for (cur_node = a_node; cur_node; cur_node = cur_node->next) { |
851 |
if (cur_node->type == XML_ELEMENT_NODE) { |
if (cur_node->type == XML_ELEMENT_NODE) { |
883 |
|
|
884 |
/* ------------------ osm handling ----------------- */ |
/* ------------------ osm handling ----------------- */ |
885 |
|
|
886 |
|
/* the two hash tables eat over 512kBytes memory and may thus be */ |
887 |
|
/* freed at any time. osm2go can work without them (albeit slower) */ |
888 |
|
static void hash_table_free(hash_table_t *table) { |
889 |
|
if(!table) return; |
890 |
|
|
891 |
|
int i; |
892 |
|
for(i=0;i<65536;i++) { |
893 |
|
hash_item_t *item = table->hash[i]; |
894 |
|
while(item) { |
895 |
|
hash_item_t *next = item->next; |
896 |
|
g_free(item); |
897 |
|
item = next; |
898 |
|
} |
899 |
|
} |
900 |
|
} |
901 |
|
|
902 |
|
void osm_hash_tables_free(osm_t *osm) { |
903 |
|
hash_table_free(osm->node_hash); |
904 |
|
osm->node_hash = NULL; |
905 |
|
hash_table_free(osm->way_hash); |
906 |
|
osm->way_hash = NULL; |
907 |
|
} |
908 |
|
|
909 |
void osm_free(icon_t **icon, osm_t *osm) { |
void osm_free(icon_t **icon, osm_t *osm) { |
910 |
if(!osm) return; |
if(!osm) return; |
911 |
|
|
912 |
|
osm_hash_tables_free(osm); |
913 |
|
|
914 |
if(osm->bounds) osm_bounds_free(osm->bounds); |
if(osm->bounds) osm_bounds_free(osm->bounds); |
915 |
if(osm->user) osm_users_free(osm->user); |
if(osm->user) osm_users_free(osm->user); |
916 |
if(osm->way) osm_ways_free(osm->way); |
if(osm->way) osm_ways_free(osm->way); |
1091 |
|
|
1092 |
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
1093 |
|
|
1094 |
|
/* append node to end of hash table if present */ |
1095 |
|
if(osm->node_hash) { |
1096 |
|
hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)]; |
1097 |
|
while(*item) item = &(*item)->next; |
1098 |
|
|
1099 |
|
*item = g_new0(hash_item_t, 1); |
1100 |
|
(*item)->data.node = node; |
1101 |
|
} |
1102 |
|
|
1103 |
/* just an empty element? then return the node as it is */ |
/* just an empty element? then return the node as it is */ |
1104 |
if(xmlTextReaderIsEmptyElement(reader)) |
if(xmlTextReaderIsEmptyElement(reader)) |
1105 |
return node; |
return node; |
1137 |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
1138 |
|
|
1139 |
/* search matching node */ |
/* search matching node */ |
1140 |
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; |
|
|
|
|
1141 |
if(!node_chain->node) printf("Node id %lu not found\n", id); |
if(!node_chain->node) printf("Node id %lu not found\n", id); |
1142 |
|
else node_chain->node->ways++; |
|
if(node_chain->node) |
|
|
node_chain->node->ways++; |
|
1143 |
|
|
1144 |
xmlFree(prop); |
xmlFree(prop); |
1145 |
|
|
1176 |
xmlFree(prop); |
xmlFree(prop); |
1177 |
} |
} |
1178 |
|
|
1179 |
|
/* append way to end of hash table if present */ |
1180 |
|
if(osm->way_hash) { |
1181 |
|
hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)]; |
1182 |
|
while(*item) item = &(*item)->next; |
1183 |
|
|
1184 |
|
*item = g_new0(hash_item_t, 1); |
1185 |
|
(*item)->data.way = way; |
1186 |
|
} |
1187 |
|
|
1188 |
/* just an empty element? then return the way as it is */ |
/* just an empty element? then return the way as it is */ |
1189 |
/* (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) */ |
1190 |
if(xmlTextReaderIsEmptyElement(reader)) |
if(xmlTextReaderIsEmptyElement(reader)) |
1240 |
|
|
1241 |
case WAY: |
case WAY: |
1242 |
/* search matching way */ |
/* search matching way */ |
1243 |
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; |
|
|
|
|
1244 |
if(!member->way) { |
if(!member->way) { |
1245 |
member->type = WAY_ID; |
member->type = WAY_ID; |
1246 |
member->id = id; |
member->id = id; |
1249 |
|
|
1250 |
case NODE: |
case NODE: |
1251 |
/* search matching node */ |
/* search matching node */ |
1252 |
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; |
|
|
|
|
1253 |
if(!member->node) { |
if(!member->node) { |
1254 |
member->type = NODE_ID; |
member->type = NODE_ID; |
1255 |
member->id = id; |
member->id = id; |
1258 |
|
|
1259 |
case RELATION: |
case RELATION: |
1260 |
/* search matching relation */ |
/* search matching relation */ |
1261 |
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; |
|
|
|
|
1262 |
if(!member->relation) { |
if(!member->relation) { |
1263 |
member->type = NODE_ID; |
member->type = NODE_ID; |
1264 |
member->id = id; |
member->id = id; |
1326 |
|
|
1327 |
if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) { |
if(xmlTextReaderNodeType(reader) == XML_READER_TYPE_ELEMENT) { |
1328 |
char *subname = (char*)xmlTextReaderConstName(reader); |
char *subname = (char*)xmlTextReaderConstName(reader); |
1329 |
if(strcasecmp(subname, "nd") == 0) { |
if(strcasecmp(subname, "member") == 0) { |
1330 |
*member = process_member(reader, osm); |
*member = process_member(reader, osm); |
1331 |
if(*member) member = &(*member)->next; |
if(*member) member = &(*member)->next; |
1332 |
} else if(strcasecmp(subname, "tag") == 0) { |
} else if(strcasecmp(subname, "tag") == 0) { |
1344 |
static osm_t *process_osm(xmlTextReaderPtr reader) { |
static osm_t *process_osm(xmlTextReaderPtr reader) { |
1345 |
/* alloc osm structure */ |
/* alloc osm structure */ |
1346 |
osm_t *osm = g_new0(osm_t, 1); |
osm_t *osm = g_new0(osm_t, 1); |
1347 |
|
osm->node_hash = g_new0(hash_table_t, 1); |
1348 |
|
osm->way_hash = g_new0(hash_table_t, 1); |
1349 |
|
|
1350 |
node_t **node = &osm->node; |
node_t **node = &osm->node; |
1351 |
way_t **way = &osm->way; |
way_t **way = &osm->way; |
1431 |
/* ----------------------- end of stream parser tests ------------------- */ |
/* ----------------------- end of stream parser tests ------------------- */ |
1432 |
#endif |
#endif |
1433 |
|
|
1434 |
|
#ifdef OSM_QND_XML_PARSER |
1435 |
|
/* -------------------------- qnd-xml parser tests ------------------- */ |
1436 |
|
|
1437 |
|
#ifdef USE_FLOAT |
1438 |
|
#define GET_PROP_POS(a,b,c) qnd_xml_get_prop_float(a, b, c) |
1439 |
|
#else |
1440 |
|
#define GET_PROP_POS(a,b,c) qnd_xml_get_prop_double(a, b, c) |
1441 |
|
#endif |
1442 |
|
|
1443 |
|
gboolean osm_bounds_cb(qnd_xml_stack_t *stack, |
1444 |
|
qnd_xml_attribute_t *attributes, gpointer data) { |
1445 |
|
|
1446 |
|
/* get parent pointer */ |
1447 |
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
1448 |
|
|
1449 |
|
if(osm->bounds) { |
1450 |
|
errorf(NULL, "Doubly defined bounds"); |
1451 |
|
return FALSE; |
1452 |
|
} |
1453 |
|
|
1454 |
|
bounds_t *bounds = osm->bounds = g_new0(bounds_t, 1); |
1455 |
|
|
1456 |
|
bounds->ll_min.lat = bounds->ll_min.lon = NAN; |
1457 |
|
bounds->ll_max.lat = bounds->ll_max.lon = NAN; |
1458 |
|
|
1459 |
|
GET_PROP_POS(attributes, "minlat", &bounds->ll_min.lat); |
1460 |
|
GET_PROP_POS(attributes, "minlon", &bounds->ll_min.lon); |
1461 |
|
GET_PROP_POS(attributes, "maxlat", &bounds->ll_max.lat); |
1462 |
|
GET_PROP_POS(attributes, "maxlon", &bounds->ll_max.lon); |
1463 |
|
|
1464 |
|
if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) || |
1465 |
|
isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) { |
1466 |
|
errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)", |
1467 |
|
bounds->ll_min.lat, bounds->ll_min.lon, |
1468 |
|
bounds->ll_max.lat, bounds->ll_max.lon); |
1469 |
|
|
1470 |
|
osm_bounds_free(bounds); |
1471 |
|
osm->bounds = NULL; |
1472 |
|
return FALSE; |
1473 |
|
} |
1474 |
|
|
1475 |
|
|
1476 |
|
/* calculate map zone which will be used as a reference for all */ |
1477 |
|
/* drawing/projection later on */ |
1478 |
|
pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2, |
1479 |
|
(bounds->ll_max.lon + bounds->ll_min.lon)/2 }; |
1480 |
|
|
1481 |
|
pos2lpos_center(¢er, &bounds->center); |
1482 |
|
|
1483 |
|
/* the scale is needed to accomodate for "streching" */ |
1484 |
|
/* by the mercartor projection */ |
1485 |
|
bounds->scale = cos(DEG2RAD(center.lat)); |
1486 |
|
|
1487 |
|
pos2lpos_center(&bounds->ll_min, &bounds->min); |
1488 |
|
bounds->min.x -= bounds->center.x; |
1489 |
|
bounds->min.y -= bounds->center.y; |
1490 |
|
bounds->min.x *= bounds->scale; |
1491 |
|
bounds->min.y *= bounds->scale; |
1492 |
|
|
1493 |
|
pos2lpos_center(&bounds->ll_max, &bounds->max); |
1494 |
|
bounds->max.x -= bounds->center.x; |
1495 |
|
bounds->max.y -= bounds->center.y; |
1496 |
|
bounds->max.x *= bounds->scale; |
1497 |
|
bounds->max.y *= bounds->scale; |
1498 |
|
|
1499 |
|
return TRUE; |
1500 |
|
} |
1501 |
|
|
1502 |
|
static gboolean osm_tag_cb(qnd_xml_stack_t *stack, |
1503 |
|
qnd_xml_attribute_t *attributes, gpointer data) { |
1504 |
|
|
1505 |
|
tag_t *tag = *(tag_t**)stack->prev->userdata[1] = g_new0(tag_t, 1); |
1506 |
|
|
1507 |
|
tag->key = qnd_xml_get_prop_str(attributes, "k"); |
1508 |
|
tag->value = qnd_xml_get_prop_str(attributes, "v"); |
1509 |
|
|
1510 |
|
if(!tag->key || !tag->value) { |
1511 |
|
printf("incomplete tag key/value %s/%s\n", tag->key, tag->value); |
1512 |
|
osm_tags_free(tag); |
1513 |
|
tag = NULL; |
1514 |
|
} else |
1515 |
|
stack->prev->userdata[1] = &tag->next; |
1516 |
|
|
1517 |
|
return TRUE; |
1518 |
|
} |
1519 |
|
|
1520 |
|
static gboolean osm_node_cb(qnd_xml_stack_t *stack, |
1521 |
|
qnd_xml_attribute_t *attributes, gpointer data) { |
1522 |
|
|
1523 |
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
1524 |
|
|
1525 |
|
/* allocate a new node structure. userdata[1] points to the current */ |
1526 |
|
/* position a new node is to be stored */ |
1527 |
|
node_t *node = *(node_t**)stack->prev->userdata[1] = |
1528 |
|
stack->userdata[0] = g_new0(node_t, 1); |
1529 |
|
stack->prev->userdata[1] = &node->next; |
1530 |
|
|
1531 |
|
qnd_xml_get_prop_gulong(attributes, "id", &node->id); |
1532 |
|
GET_PROP_POS(attributes, "lat", &node->pos.lat); |
1533 |
|
GET_PROP_POS(attributes, "lon", &node->pos.lon); |
1534 |
|
node->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
1535 |
|
node->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
1536 |
|
node->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
1537 |
|
|
1538 |
|
pos2lpos(osm->bounds, &node->pos, &node->lpos); |
1539 |
|
|
1540 |
|
/* store current tag pointer in userdata for fast access to current tag */ |
1541 |
|
stack->userdata[1] = &node->tag; |
1542 |
|
|
1543 |
|
/* append node to end of hash table if present */ |
1544 |
|
if(osm->node_hash) { |
1545 |
|
hash_item_t **item = &osm->node_hash->hash[ID2HASH(node->id)]; |
1546 |
|
while(*item) item = &(*item)->next; |
1547 |
|
|
1548 |
|
*item = g_new0(hash_item_t, 1); |
1549 |
|
(*item)->data.node = node; |
1550 |
|
} |
1551 |
|
|
1552 |
|
return TRUE; |
1553 |
|
} |
1554 |
|
|
1555 |
|
static gboolean osm_way_nd_cb(qnd_xml_stack_t *stack, |
1556 |
|
qnd_xml_attribute_t *attributes, gpointer data) { |
1557 |
|
|
1558 |
|
osm_t *osm = (osm_t*)stack->prev->prev->userdata[0]; |
1559 |
|
|
1560 |
|
item_id_t id; |
1561 |
|
if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) { |
1562 |
|
/* allocate a new node_chain structure */ |
1563 |
|
node_chain_t *node_chain = *(node_chain_t**)stack->prev->userdata[2] = |
1564 |
|
g_new0(node_chain_t, 1); |
1565 |
|
|
1566 |
|
/* search matching node */ |
1567 |
|
node_chain->node = osm_get_node_by_id(osm, id); |
1568 |
|
if(!node_chain->node) printf("Node id %lu not found\n", id); |
1569 |
|
else node_chain->node->ways++; |
1570 |
|
|
1571 |
|
stack->prev->userdata[2] = &node_chain->next; |
1572 |
|
} |
1573 |
|
|
1574 |
|
return TRUE; |
1575 |
|
} |
1576 |
|
|
1577 |
|
gboolean osm_way_cb(qnd_xml_stack_t *stack, |
1578 |
|
qnd_xml_attribute_t *attributes, gpointer data) { |
1579 |
|
|
1580 |
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
1581 |
|
|
1582 |
|
/* allocate a new way structure. userdata[2] points to the current */ |
1583 |
|
/* position a new way is to be stored in the way list */ |
1584 |
|
way_t *way = *(way_t**)stack->prev->userdata[2] = |
1585 |
|
stack->userdata[0] = g_new0(way_t, 1); |
1586 |
|
stack->prev->userdata[2] = &way->next; |
1587 |
|
|
1588 |
|
qnd_xml_get_prop_gulong(attributes, "id", &way->id); |
1589 |
|
way->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
1590 |
|
way->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
1591 |
|
way->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
1592 |
|
|
1593 |
|
/* store current tag and node_chain pointers in userdata for fast */ |
1594 |
|
/* access to current tag/node_chain entry */ |
1595 |
|
stack->userdata[1] = &way->tag; |
1596 |
|
stack->userdata[2] = &way->node_chain; |
1597 |
|
|
1598 |
|
/* append way to end of hash table if present */ |
1599 |
|
if(osm->way_hash) { |
1600 |
|
hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)]; |
1601 |
|
while(*item) item = &(*item)->next; |
1602 |
|
|
1603 |
|
*item = g_new0(hash_item_t, 1); |
1604 |
|
(*item)->data.way = way; |
1605 |
|
} |
1606 |
|
|
1607 |
|
return TRUE; |
1608 |
|
} |
1609 |
|
|
1610 |
|
static gboolean osm_rel_member_cb(qnd_xml_stack_t *stack, |
1611 |
|
qnd_xml_attribute_t *attributes, gpointer data) { |
1612 |
|
|
1613 |
|
osm_t *osm = (osm_t*)stack->prev->prev->userdata[0]; |
1614 |
|
|
1615 |
|
member_t *member = *(member_t**)stack->prev->userdata[2] = |
1616 |
|
g_new0(member_t, 1); |
1617 |
|
stack->prev->userdata[2] = &member->next; |
1618 |
|
member->type = ILLEGAL; |
1619 |
|
|
1620 |
|
char *type = qnd_xml_get_prop(attributes, "type"); |
1621 |
|
if(type) { |
1622 |
|
if(strcasecmp(type, "way") == 0) member->type = WAY; |
1623 |
|
else if(strcasecmp(type, "node") == 0) member->type = NODE; |
1624 |
|
else if(strcasecmp(type, "relation") == 0) member->type = RELATION; |
1625 |
|
} |
1626 |
|
|
1627 |
|
item_id_t id; |
1628 |
|
if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) { |
1629 |
|
switch(member->type) { |
1630 |
|
case ILLEGAL: |
1631 |
|
printf("Unable to store illegal type\n"); |
1632 |
|
break; |
1633 |
|
|
1634 |
|
case WAY: |
1635 |
|
/* search matching way */ |
1636 |
|
member->way = osm_get_way_by_id(osm, id); |
1637 |
|
if(!member->way) { |
1638 |
|
member->type = WAY_ID; |
1639 |
|
member->id = id; |
1640 |
|
} |
1641 |
|
break; |
1642 |
|
|
1643 |
|
case NODE: |
1644 |
|
/* search matching node */ |
1645 |
|
member->node = osm_get_node_by_id(osm, id); |
1646 |
|
if(!member->node) { |
1647 |
|
member->type = NODE_ID; |
1648 |
|
member->id = id; |
1649 |
|
} |
1650 |
|
break; |
1651 |
|
|
1652 |
|
case RELATION: |
1653 |
|
/* search matching relation */ |
1654 |
|
member->relation = osm_get_relation_by_id(osm, id); |
1655 |
|
if(!member->relation) { |
1656 |
|
member->type = NODE_ID; |
1657 |
|
member->id = id; |
1658 |
|
} |
1659 |
|
break; |
1660 |
|
|
1661 |
|
case WAY_ID: |
1662 |
|
case NODE_ID: |
1663 |
|
case RELATION_ID: |
1664 |
|
break; |
1665 |
|
} |
1666 |
|
} |
1667 |
|
|
1668 |
|
return TRUE; |
1669 |
|
} |
1670 |
|
|
1671 |
|
gboolean osm_rel_cb(qnd_xml_stack_t *stack, |
1672 |
|
qnd_xml_attribute_t *attributes, gpointer data) { |
1673 |
|
|
1674 |
|
osm_t *osm = (osm_t*)stack->prev->userdata[0]; |
1675 |
|
|
1676 |
|
/* allocate a new relation structure. userdata[3] points to the current */ |
1677 |
|
/* position a new relation is to be stored at in the relation list */ |
1678 |
|
relation_t *relation = *(relation_t**)stack->prev->userdata[3] = |
1679 |
|
stack->userdata[0] = g_new0(relation_t, 1); |
1680 |
|
stack->prev->userdata[3] = &relation->next; |
1681 |
|
|
1682 |
|
qnd_xml_get_prop_gulong(attributes, "id", &relation->id); |
1683 |
|
relation->user = osm_user(osm, qnd_xml_get_prop(attributes, "user")); |
1684 |
|
relation->visible = qnd_xml_get_prop_is(attributes, "visible", "true"); |
1685 |
|
relation->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp")); |
1686 |
|
|
1687 |
|
/* store current tag and member pointers in userdata for fast access */ |
1688 |
|
/* to current tag and members in their chains */ |
1689 |
|
stack->userdata[1] = &relation->tag; |
1690 |
|
stack->userdata[2] = &relation->member; |
1691 |
|
|
1692 |
|
return TRUE; |
1693 |
|
} |
1694 |
|
|
1695 |
|
gboolean osm_cb(qnd_xml_stack_t *stack, |
1696 |
|
qnd_xml_attribute_t *attributes, gpointer data) { |
1697 |
|
|
1698 |
|
g_assert(!stack->userdata[0]); |
1699 |
|
|
1700 |
|
/* also set parents (roots) userdata as it's the parsers return value */ |
1701 |
|
osm_t *osm = stack->prev->userdata[0] = |
1702 |
|
stack->userdata[0] = g_new0(osm_t, 1); |
1703 |
|
|
1704 |
|
osm->node_hash = g_new0(hash_table_t, 1); |
1705 |
|
osm->way_hash = g_new0(hash_table_t, 1); |
1706 |
|
|
1707 |
|
/* store direct pointers for faster list access */ |
1708 |
|
/* (otherwise we'd have to search the end of the lists for every item */ |
1709 |
|
/* to be attached) */ |
1710 |
|
stack->userdata[1] = &osm->node; |
1711 |
|
stack->userdata[2] = &osm->way; |
1712 |
|
stack->userdata[3] = &osm->relation; |
1713 |
|
|
1714 |
|
return TRUE; |
1715 |
|
} |
1716 |
|
|
1717 |
|
|
1718 |
|
/* these structures describe the content qnd_xml expects while parsing */ |
1719 |
|
qnd_xml_entry_t osm_node_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
1720 |
|
|
1721 |
|
qnd_xml_entry_t osm_way_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
1722 |
|
qnd_xml_entry_t osm_way_nd = { "nd", osm_way_nd_cb, QND_XML_LEAF }; |
1723 |
|
|
1724 |
|
qnd_xml_entry_t osm_rel_tag = { "tag", osm_tag_cb, QND_XML_LEAF }; |
1725 |
|
qnd_xml_entry_t osm_rel_member = { "member", osm_rel_member_cb, QND_XML_LEAF }; |
1726 |
|
|
1727 |
|
qnd_xml_entry_t osm_bounds = { "bounds", osm_bounds_cb, QND_XML_LEAF }; |
1728 |
|
|
1729 |
|
qnd_xml_entry_t *node_children[] = { &osm_node_tag }, |
1730 |
|
osm_node = { "node", osm_node_cb, QND_XML_CHILDREN(node_children) }; |
1731 |
|
|
1732 |
|
qnd_xml_entry_t *way_children[] = { &osm_way_tag, &osm_way_nd }, |
1733 |
|
osm_way = { "way", osm_way_cb, QND_XML_CHILDREN(way_children) }; |
1734 |
|
|
1735 |
|
qnd_xml_entry_t *rel_children[] = { &osm_rel_tag, &osm_rel_member }, |
1736 |
|
osm_rel = { "rel", osm_rel_cb, QND_XML_CHILDREN(rel_children) }; |
1737 |
|
|
1738 |
|
/* the osm element */ |
1739 |
|
qnd_xml_entry_t *osm_children[] = { |
1740 |
|
&osm_bounds, &osm_node, &osm_way, &osm_rel }; |
1741 |
|
qnd_xml_entry_t osm = { "osm", osm_cb, QND_XML_CHILDREN(osm_children) }; |
1742 |
|
|
1743 |
|
/* the root element */ |
1744 |
|
qnd_xml_entry_t *root_children[] = { &osm }; |
1745 |
|
qnd_xml_entry_t root = { "<root>", NULL, QND_XML_CHILDREN(root_children) }; |
1746 |
|
|
1747 |
|
// gcc `pkg-config --cflags --libs glib-2.0` -o qnd_xml qnd_xml.c |
1748 |
|
|
1749 |
|
|
1750 |
|
|
1751 |
|
/* ----------------------- end of qnd-xml parser tests ------------------- */ |
1752 |
|
#endif |
1753 |
|
|
1754 |
|
|
1755 |
#include <sys/time.h> |
#include <sys/time.h> |
1756 |
|
|
1757 |
osm_t *osm_parse(char *filename) { |
osm_t *osm_parse(char *filename) { |
1759 |
struct timeval start; |
struct timeval start; |
1760 |
gettimeofday(&start, NULL); |
gettimeofday(&start, NULL); |
1761 |
|
|
1762 |
|
#ifdef OSM_STREAM_PARSER |
1763 |
LIBXML_TEST_VERSION; |
LIBXML_TEST_VERSION; |
1764 |
|
|
|
#ifdef OSM_STREAM_PARSER |
|
1765 |
// use stream parser |
// use stream parser |
1766 |
osm_t *osm = process_file(filename); |
osm_t *osm = process_file(filename); |
1767 |
xmlCleanupParser(); |
xmlCleanupParser(); |
1768 |
|
#endif |
1769 |
|
|
1770 |
|
#ifdef OSM_DOM_PARSER |
1771 |
|
LIBXML_TEST_VERSION; |
1772 |
|
|
|
#else |
|
1773 |
// parse into a tree |
// parse into a tree |
1774 |
/* parse the file and get the DOM */ |
/* parse the file and get the DOM */ |
1775 |
xmlDoc *doc = NULL; |
xmlDoc *doc = NULL; |
1782 |
osm_t *osm = osm_parse_doc(doc); |
osm_t *osm = osm_parse_doc(doc); |
1783 |
#endif |
#endif |
1784 |
|
|
1785 |
|
#ifdef OSM_QND_XML_PARSER |
1786 |
|
osm_t *osm = NULL; |
1787 |
|
if(!(osm = qnd_xml_parse(filename, &root, NULL))) { |
1788 |
|
errorf(NULL, "While parsing \"%s\"", filename); |
1789 |
|
return NULL; |
1790 |
|
} |
1791 |
|
#endif |
1792 |
|
|
1793 |
struct timeval end; |
struct timeval end; |
1794 |
gettimeofday(&end, NULL); |
gettimeofday(&end, NULL); |
1795 |
|
|
2048 |
return osm_generate_xml(osm, RELATION, relation); |
return osm_generate_xml(osm, RELATION, relation); |
2049 |
} |
} |
2050 |
|
|
2051 |
|
/* the following three functions are eating much CPU power */ |
2052 |
|
/* as they search the objects lists. Hashing is supposed to help */ |
2053 |
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) { |
2054 |
|
if(id > 0 && osm->node_hash) { |
2055 |
|
// use hash table if present |
2056 |
|
hash_item_t *item = osm->node_hash->hash[ID2HASH(id)]; |
2057 |
|
while(item) { |
2058 |
|
if(item->data.node->id == id) |
2059 |
|
return item->data.node; |
2060 |
|
|
2061 |
|
item = item->next; |
2062 |
|
} |
2063 |
|
} |
2064 |
|
|
2065 |
|
/* use linear search if no hash tables are present or search in hash table failed */ |
2066 |
node_t *node = osm->node; |
node_t *node = osm->node; |
2067 |
while(node) { |
while(node) { |
2068 |
if(node->id == id) |
if(node->id == id) |
2069 |
return node; |
return node; |
2070 |
|
|
2071 |
node = node->next; |
node = node->next; |
2072 |
} |
} |
2073 |
|
|
2074 |
return NULL; |
return NULL; |
2075 |
} |
} |
2076 |
|
|
2077 |
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) { |
2078 |
|
if(id > 0 && osm->way_hash) { |
2079 |
|
// use hash table if present |
2080 |
|
hash_item_t *item = osm->way_hash->hash[ID2HASH(id)]; |
2081 |
|
while(item) { |
2082 |
|
if(item->data.way->id == id) |
2083 |
|
return item->data.way; |
2084 |
|
|
2085 |
|
item = item->next; |
2086 |
|
} |
2087 |
|
} |
2088 |
|
|
2089 |
|
/* use linear search if no hash tables are present or search on hash table failed */ |
2090 |
way_t *way = osm->way; |
way_t *way = osm->way; |
2091 |
while(way) { |
while(way) { |
2092 |
if(way->id == id) |
if(way->id == id) |
2093 |
return way; |
return way; |
2094 |
|
|
2095 |
way = way->next; |
way = way->next; |
2096 |
} |
} |
2097 |
|
|
2098 |
return NULL; |
return NULL; |
2099 |
} |
} |
2100 |
|
|
2101 |
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) { |
2102 |
|
// use linear search |
2103 |
relation_t *relation = osm->relation; |
relation_t *relation = osm->relation; |
2104 |
while(relation) { |
while(relation) { |
2105 |
if(relation->id == id) |
if(relation->id == id) |
2157 |
return 0; |
return 0; |
2158 |
} |
} |
2159 |
|
|
2160 |
|
item_id_t osm_new_relation_id(osm_t *osm) { |
2161 |
|
item_id_t id = -1; |
2162 |
|
|
2163 |
|
while(TRUE) { |
2164 |
|
gboolean found = FALSE; |
2165 |
|
relation_t *relation = osm->relation; |
2166 |
|
while(relation) { |
2167 |
|
if(relation->id == id) |
2168 |
|
found = TRUE; |
2169 |
|
|
2170 |
|
relation = relation->next; |
2171 |
|
} |
2172 |
|
|
2173 |
|
/* no such id so far -> use it */ |
2174 |
|
if(!found) return id; |
2175 |
|
|
2176 |
|
id--; |
2177 |
|
} |
2178 |
|
g_assert(0); |
2179 |
|
return 0; |
2180 |
|
} |
2181 |
|
|
2182 |
node_t *osm_node_new(osm_t *osm, gint x, gint y) { |
node_t *osm_node_new(osm_t *osm, gint x, gint y) { |
2183 |
printf("Creating new node\n"); |
printf("Creating new node\n"); |
2184 |
|
|
2215 |
*lnode = node; |
*lnode = node; |
2216 |
} |
} |
2217 |
|
|
2218 |
|
void osm_node_restore(osm_t *osm, node_t *node) { |
2219 |
|
printf("Restoring node\n"); |
2220 |
|
|
2221 |
|
/* attach to end of node list */ |
2222 |
|
node_t **lnode = &osm->node; |
2223 |
|
while(*lnode) lnode = &(*lnode)->next; |
2224 |
|
*lnode = node; |
2225 |
|
} |
2226 |
|
|
2227 |
way_t *osm_way_new(void) { |
way_t *osm_way_new(void) { |
2228 |
printf("Creating new way\n"); |
printf("Creating new way\n"); |
2229 |
|
|
2500 |
} |
} |
2501 |
} |
} |
2502 |
|
|
2503 |
|
relation_t *osm_relation_new(void) { |
2504 |
|
printf("Creating new relation\n"); |
2505 |
|
|
2506 |
|
relation_t *relation = g_new0(relation_t, 1); |
2507 |
|
relation->visible = TRUE; |
2508 |
|
relation->flags = OSM_FLAG_NEW; |
2509 |
|
relation->time = time(NULL); |
2510 |
|
|
2511 |
|
/* add created_by tag */ |
2512 |
|
relation->tag = g_new0(tag_t, 1); |
2513 |
|
relation->tag->key = g_strdup("created_by"); |
2514 |
|
relation->tag->value = g_strdup(PACKAGE " v" VERSION); |
2515 |
|
|
2516 |
|
return relation; |
2517 |
|
} |
2518 |
|
|
2519 |
|
void osm_relation_attach(osm_t *osm, relation_t *relation) { |
2520 |
|
printf("Attaching relation\n"); |
2521 |
|
|
2522 |
|
relation->id = osm_new_relation_id(osm); |
2523 |
|
relation->flags = OSM_FLAG_NEW; |
2524 |
|
|
2525 |
|
/* attach to end of relation list */ |
2526 |
|
relation_t **lrelation = &osm->relation; |
2527 |
|
while(*lrelation) lrelation = &(*lrelation)->next; |
2528 |
|
*lrelation = relation; |
2529 |
|
} |
2530 |
|
|
2531 |
|
|
2532 |
void osm_way_delete(osm_t *osm, icon_t **icon, |
void osm_way_delete(osm_t *osm, icon_t **icon, |
2533 |
way_t *way, gboolean permanently) { |
way_t *way, gboolean permanently) { |
2534 |
|
|
2592 |
} |
} |
2593 |
} |
} |
2594 |
|
|
2595 |
|
void osm_relation_delete(osm_t *osm, relation_t *relation, |
2596 |
|
gboolean permanently) { |
2597 |
|
|
2598 |
|
/* new relations aren't stored on the server and are just */ |
2599 |
|
/* deleted permanently */ |
2600 |
|
if(relation->flags & OSM_FLAG_NEW) { |
2601 |
|
printf("About to delete NEW relation #%ld -> force permanent delete\n", |
2602 |
|
relation->id); |
2603 |
|
permanently = TRUE; |
2604 |
|
} |
2605 |
|
|
2606 |
|
/* the deletion of a relation doesn't affect the members as they */ |
2607 |
|
/* don't have any reference to the relation they are part of */ |
2608 |
|
|
2609 |
|
if(!permanently) { |
2610 |
|
printf("mark relation #%ld as deleted\n", relation->id); |
2611 |
|
relation->flags |= OSM_FLAG_DELETED; |
2612 |
|
} else { |
2613 |
|
printf("permanently delete relation #%ld\n", relation->id); |
2614 |
|
|
2615 |
|
/* remove it from the chain */ |
2616 |
|
relation_t **crelation = &osm->relation; |
2617 |
|
int found = 0; |
2618 |
|
|
2619 |
|
while(*crelation) { |
2620 |
|
if(*crelation == relation) { |
2621 |
|
found++; |
2622 |
|
*crelation = (*crelation)->next; |
2623 |
|
|
2624 |
|
osm_relation_free(relation); |
2625 |
|
} else |
2626 |
|
crelation = &((*crelation)->next); |
2627 |
|
} |
2628 |
|
g_assert(found == 1); |
2629 |
|
} |
2630 |
|
} |
2631 |
|
|
2632 |
void osm_way_revert(way_t *way) { |
void osm_way_revert(way_t *way) { |
2633 |
node_chain_t *new = NULL; |
node_chain_t *new = NULL; |
2634 |
|
|
2704 |
|
|
2705 |
return new_tags; |
return new_tags; |
2706 |
} |
} |
2707 |
|
|
2708 |
|
/* return plain text of type */ |
2709 |
|
char *osm_type_string(type_t type) { |
2710 |
|
const struct { type_t type; char *name; } types[] = { |
2711 |
|
{ ILLEGAL, "illegal" }, |
2712 |
|
{ NODE, "node" }, |
2713 |
|
{ WAY, "way" }, |
2714 |
|
{ RELATION, "relation" }, |
2715 |
|
{ NODE_ID, "node id" }, |
2716 |
|
{ WAY_ID, "way id" }, |
2717 |
|
{ RELATION_ID, "relation id" }, |
2718 |
|
{ 0, NULL } |
2719 |
|
}; |
2720 |
|
|
2721 |
|
int i; |
2722 |
|
for(i=0;types[i].name;i++) |
2723 |
|
if(type == types[i].type) |
2724 |
|
return types[i].name; |
2725 |
|
|
2726 |
|
return NULL; |
2727 |
|
} |
2728 |
|
|
2729 |
|
char *osm_object_string(type_t type, void *object) { |
2730 |
|
char *type_str = osm_type_string(type); |
2731 |
|
|
2732 |
|
if(!object) |
2733 |
|
return g_strdup_printf("%s #<invalid>", type_str); |
2734 |
|
|
2735 |
|
switch(type) { |
2736 |
|
case ILLEGAL: |
2737 |
|
return g_strdup_printf("%s #<unspec>", type_str); |
2738 |
|
break; |
2739 |
|
case NODE: |
2740 |
|
return g_strdup_printf("%s #%ld", type_str, ((node_t*)object)->id); |
2741 |
|
break; |
2742 |
|
case WAY: |
2743 |
|
return g_strdup_printf("%s #%ld", type_str, ((way_t*)object)->id); |
2744 |
|
break; |
2745 |
|
case RELATION: |
2746 |
|
return g_strdup_printf("%s #%ld", type_str, ((relation_t*)object)->id); |
2747 |
|
break; |
2748 |
|
case NODE_ID: |
2749 |
|
case WAY_ID: |
2750 |
|
case RELATION_ID: |
2751 |
|
return g_strdup_printf("%s #%ld", type_str, ((item_id_t)object)); |
2752 |
|
break; |
2753 |
|
} |
2754 |
|
return NULL; |
2755 |
|
} |
2756 |
|
|
2757 |
|
char *osm_id_string(type_t type, void *object) { |
2758 |
|
if(!object) return NULL; |
2759 |
|
|
2760 |
|
switch(type) { |
2761 |
|
case ILLEGAL: |
2762 |
|
return NULL; |
2763 |
|
break; |
2764 |
|
case NODE: |
2765 |
|
return g_strdup_printf("#%ld", ((node_t*)object)->id); |
2766 |
|
break; |
2767 |
|
case WAY: |
2768 |
|
return g_strdup_printf("#%ld", ((way_t*)object)->id); |
2769 |
|
break; |
2770 |
|
case RELATION: |
2771 |
|
return g_strdup_printf("#%ld", ((relation_t*)object)->id); |
2772 |
|
break; |
2773 |
|
case NODE_ID: |
2774 |
|
case WAY_ID: |
2775 |
|
case RELATION_ID: |
2776 |
|
return g_strdup_printf("#%ld", ((item_id_t)object)); |
2777 |
|
break; |
2778 |
|
} |
2779 |
|
return NULL; |
2780 |
|
} |
2781 |
|
|
2782 |
|
tag_t *osm_object_get_tags(type_t type, void *object) { |
2783 |
|
if(!object) return NULL; |
2784 |
|
|
2785 |
|
switch(type) { |
2786 |
|
case ILLEGAL: |
2787 |
|
return NULL; |
2788 |
|
break; |
2789 |
|
case NODE: |
2790 |
|
return ((node_t*)object)->tag; |
2791 |
|
break; |
2792 |
|
case WAY: |
2793 |
|
return ((way_t*)object)->tag; |
2794 |
|
break; |
2795 |
|
case RELATION: |
2796 |
|
return ((relation_t*)object)->tag; |
2797 |
|
break; |
2798 |
|
case NODE_ID: |
2799 |
|
case WAY_ID: |
2800 |
|
case RELATION_ID: |
2801 |
|
return NULL; |
2802 |
|
break; |
2803 |
|
} |
2804 |
|
return NULL; |
2805 |
|
} |
2806 |
|
|
2807 |
|
|
2808 |
|
gint osm_relation_members_num(relation_t *relation) { |
2809 |
|
gint num = 0; |
2810 |
|
member_t *member = relation->member; |
2811 |
|
while(member) { |
2812 |
|
num++; |
2813 |
|
member = member->next; |
2814 |
|
} |
2815 |
|
return num; |
2816 |
|
} |
2817 |
|
|
2818 |
// vim:et:ts=8:sw=2:sts=2:ai |
// vim:et:ts=8:sw=2:sts=2:ai |