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 |
|
|
|
#define OSM_STREAM_PARSER |
|
|
|
|
20 |
#include <stdio.h> |
#include <stdio.h> |
21 |
#include <stdlib.h> |
#include <stdlib.h> |
22 |
#include <string.h> |
#include <string.h> |
35 |
#error "Tree not enabled in libxml" |
#error "Tree not enabled in libxml" |
36 |
#endif |
#endif |
37 |
|
|
|
/* determine where a node/way/relation read from the osm file */ |
|
|
/* is inserted into the internal database */ |
|
|
// #define OSM_SORT_ID |
|
|
#define OSM_SORT_LAST |
|
|
// #define OSM_SORT_FIRST |
|
|
|
|
38 |
/* ------------------------- bounds handling --------------------- */ |
/* ------------------------- bounds handling --------------------- */ |
39 |
|
|
40 |
static void osm_bounds_free(bounds_t *bounds) { |
static void osm_bounds_free(bounds_t *bounds) { |
47 |
bounds->ll_min.lon, bounds->ll_max.lon); |
bounds->ll_min.lon, bounds->ll_max.lon); |
48 |
} |
} |
49 |
|
|
|
#ifndef OSM_STREAM_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 |
|
|
|
|
50 |
/* ------------------------- user handling --------------------- */ |
/* ------------------------- user handling --------------------- */ |
51 |
|
|
52 |
void osm_users_free(user_t *user) { |
void osm_users_free(user_t *user) { |
69 |
} |
} |
70 |
|
|
71 |
static user_t *osm_user(osm_t *osm, char *name) { |
static user_t *osm_user(osm_t *osm, char *name) { |
72 |
|
if(!name) return NULL; |
73 |
|
|
74 |
/* search through user list */ |
/* search through user list */ |
75 |
user_t **user = &osm->user; |
user_t **user = &osm->user; |
91 |
|
|
92 |
static |
static |
93 |
time_t convert_iso8601(const char *str) { |
time_t convert_iso8601(const char *str) { |
94 |
|
if(!str) return 0; |
95 |
|
|
96 |
tzset(); |
tzset(); |
97 |
|
|
98 |
struct tm ctime; |
struct tm ctime; |
227 |
char buf[64]; |
char buf[64]; |
228 |
struct tm tm; |
struct tm tm; |
229 |
|
|
230 |
printf("Id: %lu\n", node->id); |
printf("Id: "ITEM_ID_FORMAT"\n", node->id); |
231 |
printf("User: %s\n", node->user?node->user->name:"<unspecified>"); |
printf("User: %s\n", node->user?node->user->name:"<unspecified>"); |
232 |
printf("Visible: %s\n", node->visible?"yes":"no"); |
printf("Visible: %s\n", node->visible?"yes":"no"); |
233 |
|
|
246 |
} |
} |
247 |
} |
} |
248 |
|
|
|
#ifndef OSM_STREAM_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 |
|
|
|
|
249 |
/* ------------------- way handling ------------------- */ |
/* ------------------- way handling ------------------- */ |
250 |
|
|
251 |
void osm_node_chain_free(node_chain_t *node_chain) { |
void osm_node_chain_free(node_chain_t *node_chain) { |
260 |
} |
} |
261 |
|
|
262 |
void osm_way_free(way_t *way) { |
void osm_way_free(way_t *way) { |
263 |
// printf("freeing way #%ld\n", way->id); |
// printf("freeing way #" ITEM_ID_FORMAT "\n", way->id); |
264 |
|
|
265 |
osm_node_chain_free(way->node_chain); |
osm_node_chain_free(way->node_chain); |
266 |
osm_tags_free(way->tag); |
osm_tags_free(way->tag); |
305 |
char buf[64]; |
char buf[64]; |
306 |
struct tm tm; |
struct tm tm; |
307 |
|
|
308 |
printf("Id: %lu\n", way->id); |
printf("Id: "ITEM_ID_FORMAT"\n", way->id); |
309 |
printf("User: %s\n", way->user?way->user->name:"<unspecified>"); |
printf("User: %s\n", way->user?way->user->name:"<unspecified>"); |
310 |
printf("Visible: %s\n", way->visible?"yes":"no"); |
printf("Visible: %s\n", way->visible?"yes":"no"); |
311 |
node_chain_t *node_chain = way->node_chain; |
node_chain_t *node_chain = way->node_chain; |
312 |
while(node_chain) { |
while(node_chain) { |
313 |
printf(" Node: %lu\n", node_chain->node->id); |
printf(" Node: "ITEM_ID_FORMAT"\n", node_chain->node->id); |
314 |
node_chain = node_chain->next; |
node_chain = node_chain->next; |
315 |
} |
} |
316 |
|
|
338 |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
node_chain_t *node_chain = g_new0(node_chain_t, 1); |
339 |
|
|
340 |
/* search matching node */ |
/* search matching node */ |
341 |
node_chain->node = osm->node; |
node_chain->node = osm_get_node_by_id(osm, id); |
342 |
while(node_chain->node && node_chain->node->id != id) |
if(!node_chain->node) printf("Node id " ITEM_ID_FORMAT " not found\n", id); |
343 |
node_chain->node = node_chain->node->next; |
else node_chain->node->ways++; |
|
|
|
|
if(!node_chain->node) printf("Node id %lu not found\n", id); |
|
|
|
|
|
if(node_chain->node) |
|
|
node_chain->node->ways++; |
|
344 |
|
|
345 |
xmlFree(prop); |
xmlFree(prop); |
346 |
|
|
350 |
return NULL; |
return NULL; |
351 |
} |
} |
352 |
|
|
|
#ifndef OSM_STREAM_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 |
|
|
|
|
353 |
/* ------------------- relation handling ------------------- */ |
/* ------------------- relation handling ------------------- */ |
354 |
|
|
355 |
void osm_member_free(member_t *member) { |
void osm_member_free(member_t *member) { |
365 |
} |
} |
366 |
} |
} |
367 |
|
|
368 |
|
void osm_relation_free(relation_t *relation) { |
369 |
|
osm_tags_free(relation->tag); |
370 |
|
osm_members_free(relation->member); |
371 |
|
|
372 |
|
g_free(relation); |
373 |
|
} |
374 |
|
|
375 |
static void osm_relations_free(relation_t *relation) { |
static void osm_relations_free(relation_t *relation) { |
376 |
while(relation) { |
while(relation) { |
377 |
relation_t *next = relation->next; |
relation_t *next = relation->next; |
378 |
|
osm_relation_free(relation); |
|
osm_tags_free(relation->tag); |
|
|
osm_members_free(relation->member); |
|
|
|
|
|
g_free(relation); |
|
379 |
relation = next; |
relation = next; |
380 |
} |
} |
381 |
} |
} |
386 |
char buf[64]; |
char buf[64]; |
387 |
struct tm tm; |
struct tm tm; |
388 |
|
|
389 |
printf("Id: %lu\n", relation->id); |
printf("Id: "ITEM_ID_FORMAT"\n", relation->id); |
390 |
printf("User: %s\n", |
printf("User: %s\n", |
391 |
relation->user?relation->user->name:"<unspecified>"); |
relation->user?relation->user->name:"<unspecified>"); |
392 |
printf("Visible: %s\n", relation->visible?"yes":"no"); |
printf("Visible: %s\n", relation->visible?"yes":"no"); |
393 |
|
|
394 |
member_t *member = relation->member; |
member_t *member = relation->member; |
395 |
while(member) { |
while(member) { |
396 |
switch(member->type) { |
switch(member->object.type) { |
397 |
case ILLEGAL: |
case ILLEGAL: |
398 |
case NODE_ID: |
case NODE_ID: |
399 |
case WAY_ID: |
case WAY_ID: |
401 |
break; |
break; |
402 |
|
|
403 |
case NODE: |
case NODE: |
404 |
if(member->node) |
if(member->object.node) |
405 |
printf(" Member: Node, id = %lu, role = %s\n", |
printf(" Member: Node, id = " ITEM_ID_FORMAT ", role = %s\n", |
406 |
member->node->id, member->role); |
member->object.node->id, member->role); |
407 |
break; |
break; |
408 |
|
|
409 |
case WAY: |
case WAY: |
410 |
if(member->way) |
if(member->object.way) |
411 |
printf(" Member: Way, id = %lu, role = %s\n", |
printf(" Member: Way, id = " ITEM_ID_FORMAT ", role = %s\n", |
412 |
member->way->id, member->role); |
member->object.way->id, member->role); |
413 |
break; |
break; |
414 |
|
|
415 |
case RELATION: |
case RELATION: |
416 |
if(member->relation) |
if(member->object.relation) |
417 |
printf(" Member: Relation, id = %lu, role = %s\n", |
printf(" Member: Relation, id = " ITEM_ID_FORMAT ", role = %s\n", |
418 |
member->relation->id, member->role); |
member->object.relation->id, member->role); |
419 |
break; |
break; |
420 |
} |
} |
421 |
|
|
436 |
xmlDocPtr doc, xmlNode *a_node) { |
xmlDocPtr doc, xmlNode *a_node) { |
437 |
char *prop; |
char *prop; |
438 |
member_t *member = g_new0(member_t, 1); |
member_t *member = g_new0(member_t, 1); |
439 |
member->type = ILLEGAL; |
member->object.type = ILLEGAL; |
440 |
|
|
441 |
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"type"))) { |
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"type"))) { |
442 |
if(strcasecmp(prop, "way") == 0) member->type = WAY; |
if(strcasecmp(prop, "way") == 0) member->object.type = WAY; |
443 |
else if(strcasecmp(prop, "node") == 0) member->type = NODE; |
else if(strcasecmp(prop, "node") == 0) member->object.type = NODE; |
444 |
else if(strcasecmp(prop, "relation") == 0) member->type = RELATION; |
else if(strcasecmp(prop, "relation") == 0) member->object.type = RELATION; |
445 |
xmlFree(prop); |
xmlFree(prop); |
446 |
} |
} |
447 |
|
|
448 |
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"ref"))) { |
if((prop = (char*)xmlGetProp(a_node, (unsigned char*)"ref"))) { |
449 |
item_id_t id = strtoul(prop, NULL, 10); |
item_id_t id = strtoul(prop, NULL, 10); |
450 |
|
|
451 |
switch(member->type) { |
switch(member->object.type) { |
452 |
case ILLEGAL: |
case ILLEGAL: |
453 |
printf("Unable to store illegal type\n"); |
printf("Unable to store illegal type\n"); |
454 |
break; |
break; |
455 |
|
|
456 |
case WAY: |
case WAY: |
457 |
/* search matching way */ |
/* search matching way */ |
458 |
member->way = osm->way; |
member->object.way = osm_get_way_by_id(osm, id); |
459 |
while(member->way && member->way->id != id) |
if(!member->object.way) { |
460 |
member->way = member->way->next; |
member->object.type = WAY_ID; |
461 |
|
member->object.id = id; |
|
if(!member->way) { |
|
|
member->type = WAY_ID; |
|
|
member->id = id; |
|
462 |
} |
} |
463 |
break; |
break; |
464 |
|
|
465 |
case NODE: |
case NODE: |
466 |
/* search matching node */ |
/* search matching node */ |
467 |
member->node = osm->node; |
member->object.node = osm_get_node_by_id(osm, id); |
468 |
while(member->node && member->node->id != id) |
if(!member->object.node) { |
469 |
member->node = member->node->next; |
member->object.type = NODE_ID; |
470 |
|
member->object.id = id; |
|
if(!member->node) { |
|
|
member->type = NODE_ID; |
|
|
member->id = id; |
|
471 |
} |
} |
472 |
break; |
break; |
473 |
|
|
474 |
case RELATION: |
case RELATION: |
475 |
/* search matching relation */ |
/* search matching relation */ |
476 |
member->relation = osm->relation; |
member->object.relation = osm_get_relation_by_id(osm, id); |
477 |
while(member->relation && member->relation->id != id) |
if(!member->object.relation) { |
478 |
member->relation = member->relation->next; |
member->object.type = NODE_ID; |
479 |
|
member->object.id = id; |
|
if(!member->relation) { |
|
|
member->type = NODE_ID; |
|
|
member->id = id; |
|
480 |
} |
} |
481 |
break; |
break; |
482 |
|
|
497 |
return member; |
return member; |
498 |
} |
} |
499 |
|
|
500 |
#ifndef OSM_STREAM_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); |
|
501 |
|
|
502 |
for (cur_node = a_node; cur_node; cur_node = cur_node->next) { |
/* the two hash tables eat over 512kBytes memory and may thus be */ |
503 |
if (cur_node->type == XML_ELEMENT_NODE) { |
/* freed at any time. osm2go can work without them (albeit slower) */ |
504 |
/* parse osm osm file ... */ |
static void hash_table_free(hash_table_t *table) { |
505 |
if(strcasecmp((char*)cur_node->name, "osm") == 0) |
if(!table) return; |
506 |
osm_parse_osm(osm, doc, cur_node); |
|
507 |
else |
int i; |
508 |
printf("found unhandled %s\n", cur_node->name); |
for(i=0;i<65536;i++) { |
509 |
|
hash_item_t *item = table->hash[i]; |
510 |
|
while(item) { |
511 |
|
hash_item_t *next = item->next; |
512 |
|
g_free(item); |
513 |
|
item = next; |
514 |
} |
} |
515 |
} |
} |
|
|
|
|
return osm; |
|
516 |
} |
} |
517 |
|
|
518 |
static osm_t *osm_parse_doc(xmlDocPtr doc) { |
void osm_hash_tables_free(osm_t *osm) { |
519 |
osm_t *osm; |
hash_table_free(osm->node_hash); |
520 |
|
osm->node_hash = NULL; |
521 |
/* Get the root element node */ |
hash_table_free(osm->way_hash); |
522 |
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; |
|
523 |
} |
} |
|
#endif |
|
|
|
|
|
/* ------------------ osm handling ----------------- */ |
|
524 |
|
|
525 |
void osm_free(icon_t **icon, osm_t *osm) { |
void osm_free(icon_t **icon, osm_t *osm) { |
526 |
if(!osm) return; |
if(!osm) return; |
527 |
|
|
528 |
|
osm_hash_tables_free(osm); |
529 |
|
|
530 |
if(osm->bounds) osm_bounds_free(osm->bounds); |
if(osm->bounds) osm_bounds_free(osm->bounds); |
531 |
if(osm->user) osm_users_free(osm->user); |
if(osm->user) osm_users_free(osm->user); |
532 |
if(osm->way) osm_ways_free(osm->way); |
if(osm->way) osm_ways_free(osm->way); |
543 |
osm_relations_dump(osm->relation); |
osm_relations_dump(osm->relation); |
544 |
} |
} |
545 |
|
|
546 |
#ifdef OSM_STREAM_PARSER |
/* -------------------------- stream parser ------------------- */ |
|
/* -------------------------- stream parser tests ------------------- */ |
|
547 |
|
|
548 |
#include <libxml/xmlreader.h> |
#include <libxml/xmlreader.h> |
549 |
|
|
679 |
xmlFree(prop); |
xmlFree(prop); |
680 |
} |
} |
681 |
|
|
682 |
|
/* new in api 0.6: */ |
683 |
|
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version"))) { |
684 |
|
node->version = strtoul(prop, NULL, 10); |
685 |
|
xmlFree(prop); |
686 |
|
} |
687 |
|
|
688 |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lat"))) { |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "lat"))) { |
689 |
node->pos.lat = g_ascii_strtod(prop, NULL); |
node->pos.lat = g_ascii_strtod(prop, NULL); |
690 |
xmlFree(prop); |
xmlFree(prop); |
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); |
762 |
while(node_chain->node && node_chain->node->id != id) |
if(!node_chain->node) printf("Node id " ITEM_ID_FORMAT " not found\n", id); |
763 |
node_chain->node = node_chain->node->next; |
else node_chain->node->ways++; |
|
|
|
|
if(!node_chain->node) printf("Node id %lu not found\n", id); |
|
|
|
|
|
if(node_chain->node) |
|
|
node_chain->node->ways++; |
|
764 |
|
|
765 |
xmlFree(prop); |
xmlFree(prop); |
766 |
|
|
782 |
xmlFree(prop); |
xmlFree(prop); |
783 |
} |
} |
784 |
|
|
785 |
|
/* new in api 0.6: */ |
786 |
|
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version"))) { |
787 |
|
way->version = strtoul(prop, NULL, 10); |
788 |
|
xmlFree(prop); |
789 |
|
} |
790 |
|
|
791 |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) { |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) { |
792 |
way->user = osm_user(osm, prop); |
way->user = osm_user(osm, prop); |
793 |
xmlFree(prop); |
xmlFree(prop); |
803 |
xmlFree(prop); |
xmlFree(prop); |
804 |
} |
} |
805 |
|
|
806 |
|
/* append way to end of hash table if present */ |
807 |
|
if(osm->way_hash) { |
808 |
|
hash_item_t **item = &osm->way_hash->hash[ID2HASH(way->id)]; |
809 |
|
while(*item) item = &(*item)->next; |
810 |
|
|
811 |
|
*item = g_new0(hash_item_t, 1); |
812 |
|
(*item)->data.way = way; |
813 |
|
} |
814 |
|
|
815 |
/* just an empty element? then return the way as it is */ |
/* just an empty element? then return the way as it is */ |
816 |
/* (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) */ |
817 |
if(xmlTextReaderIsEmptyElement(reader)) |
if(xmlTextReaderIsEmptyElement(reader)) |
848 |
static member_t *process_member(xmlTextReaderPtr reader, osm_t *osm) { |
static member_t *process_member(xmlTextReaderPtr reader, osm_t *osm) { |
849 |
char *prop; |
char *prop; |
850 |
member_t *member = g_new0(member_t, 1); |
member_t *member = g_new0(member_t, 1); |
851 |
member->type = ILLEGAL; |
member->object.type = ILLEGAL; |
852 |
|
|
853 |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "type"))) { |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "type"))) { |
854 |
if(strcasecmp(prop, "way") == 0) member->type = WAY; |
if(strcasecmp(prop, "way") == 0) member->object.type = WAY; |
855 |
else if(strcasecmp(prop, "node") == 0) member->type = NODE; |
else if(strcasecmp(prop, "node") == 0) member->object.type = NODE; |
856 |
else if(strcasecmp(prop, "relation") == 0) member->type = RELATION; |
else if(strcasecmp(prop, "relation") == 0) member->object.type = RELATION; |
857 |
xmlFree(prop); |
xmlFree(prop); |
858 |
} |
} |
859 |
|
|
860 |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) { |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "ref"))) { |
861 |
item_id_t id = strtoul(prop, NULL, 10); |
item_id_t id = strtoul(prop, NULL, 10); |
862 |
|
|
863 |
switch(member->type) { |
switch(member->object.type) { |
864 |
case ILLEGAL: |
case ILLEGAL: |
865 |
printf("Unable to store illegal type\n"); |
printf("Unable to store illegal type\n"); |
866 |
break; |
break; |
867 |
|
|
868 |
case WAY: |
case WAY: |
869 |
/* search matching way */ |
/* search matching way */ |
870 |
member->way = osm->way; |
member->object.way = osm_get_way_by_id(osm, id); |
871 |
while(member->way && member->way->id != id) |
if(!member->object.way) { |
872 |
member->way = member->way->next; |
member->object.type = WAY_ID; |
873 |
|
member->object.id = id; |
|
if(!member->way) { |
|
|
member->type = WAY_ID; |
|
|
member->id = id; |
|
874 |
} |
} |
875 |
break; |
break; |
876 |
|
|
877 |
case NODE: |
case NODE: |
878 |
/* search matching node */ |
/* search matching node */ |
879 |
member->node = osm->node; |
member->object.node = osm_get_node_by_id(osm, id); |
880 |
while(member->node && member->node->id != id) |
if(!member->object.node) { |
881 |
member->node = member->node->next; |
member->object.type = NODE_ID; |
882 |
|
member->object.id = id; |
|
if(!member->node) { |
|
|
member->type = NODE_ID; |
|
|
member->id = id; |
|
883 |
} |
} |
884 |
break; |
break; |
885 |
|
|
886 |
case RELATION: |
case RELATION: |
887 |
/* search matching relation */ |
/* search matching relation */ |
888 |
member->relation = osm->relation; |
member->object.relation = osm_get_relation_by_id(osm, id); |
889 |
while(member->relation && member->relation->id != id) |
if(!member->object.relation) { |
890 |
member->relation = member->relation->next; |
member->object.type = NODE_ID; |
891 |
|
member->object.id = id; |
|
if(!member->relation) { |
|
|
member->type = NODE_ID; |
|
|
member->id = id; |
|
892 |
} |
} |
893 |
break; |
break; |
894 |
|
|
919 |
xmlFree(prop); |
xmlFree(prop); |
920 |
} |
} |
921 |
|
|
922 |
|
/* new in api 0.6: */ |
923 |
|
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "version"))) { |
924 |
|
relation->version = strtoul(prop, NULL, 10); |
925 |
|
xmlFree(prop); |
926 |
|
} |
927 |
|
|
928 |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) { |
if((prop = (char*)xmlTextReaderGetAttribute(reader, BAD_CAST "user"))) { |
929 |
relation->user = osm_user(osm, prop); |
relation->user = osm_user(osm, prop); |
930 |
xmlFree(prop); |
xmlFree(prop); |
977 |
static osm_t *process_osm(xmlTextReaderPtr reader) { |
static osm_t *process_osm(xmlTextReaderPtr reader) { |
978 |
/* alloc osm structure */ |
/* alloc osm structure */ |
979 |
osm_t *osm = g_new0(osm_t, 1); |
osm_t *osm = g_new0(osm_t, 1); |
980 |
|
osm->node_hash = g_new0(hash_table_t, 1); |
981 |
|
osm->way_hash = g_new0(hash_table_t, 1); |
982 |
|
|
983 |
node_t **node = &osm->node; |
node_t **node = &osm->node; |
984 |
way_t **way = &osm->way; |
way_t **way = &osm->way; |
1061 |
return osm; |
return osm; |
1062 |
} |
} |
1063 |
|
|
1064 |
/* ----------------------- end of stream parser tests ------------------- */ |
/* ----------------------- end of stream parser ------------------- */ |
|
#endif |
|
1065 |
|
|
1066 |
#include <sys/time.h> |
#include <sys/time.h> |
1067 |
|
|
1068 |
osm_t *osm_parse(char *filename) { |
osm_t *osm_parse(char *path, char *filename) { |
1069 |
|
|
1070 |
struct timeval start; |
struct timeval start; |
1071 |
gettimeofday(&start, NULL); |
gettimeofday(&start, NULL); |
1072 |
|
|
1073 |
LIBXML_TEST_VERSION; |
LIBXML_TEST_VERSION; |
1074 |
|
|
|
#ifdef OSM_STREAM_PARSER |
|
1075 |
// use stream parser |
// use stream parser |
1076 |
osm_t *osm = process_file(filename); |
osm_t *osm = NULL; |
1077 |
xmlCleanupParser(); |
if(filename[0] == '/') |
1078 |
|
osm = process_file(filename); |
1079 |
#else |
else { |
1080 |
// parse into a tree |
char *full = g_strjoin(NULL, path, filename, NULL); |
1081 |
/* parse the file and get the DOM */ |
osm = process_file(full); |
1082 |
xmlDoc *doc = NULL; |
g_free(full); |
|
if ((doc = xmlReadFile(filename, NULL, 0)) == NULL) { |
|
|
xmlErrorPtr errP = xmlGetLastError(); |
|
|
errorf(NULL, "While parsing \"%s\":\n\n%s", filename, errP->message); |
|
|
return NULL; |
|
1083 |
} |
} |
1084 |
|
|
1085 |
osm_t *osm = osm_parse_doc(doc); |
xmlCleanupParser(); |
|
#endif |
|
1086 |
|
|
1087 |
struct timeval end; |
struct timeval end; |
1088 |
gettimeofday(&end, NULL); |
gettimeofday(&end, NULL); |
1176 |
gboolean osm_node_has_tag(node_t *node) { |
gboolean osm_node_has_tag(node_t *node) { |
1177 |
tag_t *tag = node->tag; |
tag_t *tag = node->tag; |
1178 |
|
|
1179 |
|
/* created_by tags don't count as real tags */ |
1180 |
if(tag && strcasecmp(tag->key, "created_by") == 0) |
if(tag && strcasecmp(tag->key, "created_by") == 0) |
1181 |
tag = tag->next; |
tag = tag->next; |
1182 |
|
|
1199 |
while(tag) { |
while(tag) { |
1200 |
/* make sure "created_by" tag contains our id */ |
/* make sure "created_by" tag contains our id */ |
1201 |
if(strcasecmp(tag->key, "created_by") == 0) { |
if(strcasecmp(tag->key, "created_by") == 0) { |
1202 |
g_free(tag->value); |
if(strcasecmp(tag->value, PACKAGE " v" VERSION) != 0) { |
1203 |
tag->value = g_strdup(PACKAGE " v" VERSION); |
g_free(tag->value); |
1204 |
|
tag->value = g_strdup(PACKAGE " v" VERSION); |
1205 |
|
} |
1206 |
} |
} |
1207 |
|
|
1208 |
xmlNodePtr tag_node = xmlNewChild(node, NULL, BAD_CAST "tag", NULL); |
xmlNodePtr tag_node = xmlNewChild(node, NULL, BAD_CAST "tag", NULL); |
1213 |
} |
} |
1214 |
|
|
1215 |
/* build xml representation for a way */ |
/* build xml representation for a way */ |
1216 |
char *osm_generate_xml(osm_t *osm, type_t type, void *item) { |
static char *osm_generate_xml(osm_t *osm, item_id_t changeset, |
1217 |
|
type_t type, void *item) { |
1218 |
char str[32]; |
char str[32]; |
1219 |
xmlChar *result = NULL; |
xmlChar *result = NULL; |
1220 |
int len = 0; |
int len = 0; |
1223 |
|
|
1224 |
xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); |
xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); |
1225 |
xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm"); |
xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm"); |
|
xmlNewProp(root_node, BAD_CAST "version", BAD_CAST "0.5"); |
|
|
xmlNewProp(root_node, BAD_CAST "generator", BAD_CAST PACKAGE " V" VERSION); |
|
1226 |
xmlDocSetRootElement(doc, root_node); |
xmlDocSetRootElement(doc, root_node); |
1227 |
|
|
1228 |
switch(type) { |
switch(type) { |
1236 |
snprintf(str, sizeof(str), "%u", (unsigned)node->id); |
snprintf(str, sizeof(str), "%u", (unsigned)node->id); |
1237 |
xmlNewProp(node_node, BAD_CAST "id", BAD_CAST str); |
xmlNewProp(node_node, BAD_CAST "id", BAD_CAST str); |
1238 |
} |
} |
1239 |
g_ascii_dtostr(str, sizeof(str), node->pos.lat); |
snprintf(str, sizeof(str), "%u", (unsigned)node->version); |
1240 |
|
xmlNewProp(node_node, BAD_CAST "version", BAD_CAST str); |
1241 |
|
snprintf(str, sizeof(str), "%u", (unsigned)changeset); |
1242 |
|
xmlNewProp(node_node, BAD_CAST "changeset", BAD_CAST str); |
1243 |
|
g_ascii_formatd(str, sizeof(str), LL_FORMAT, node->pos.lat); |
1244 |
xmlNewProp(node_node, BAD_CAST "lat", BAD_CAST str); |
xmlNewProp(node_node, BAD_CAST "lat", BAD_CAST str); |
1245 |
g_ascii_dtostr(str, sizeof(str), node->pos.lon); |
g_ascii_formatd(str, sizeof(str), LL_FORMAT, node->pos.lon); |
1246 |
xmlNewProp(node_node, BAD_CAST "lon", BAD_CAST str); |
xmlNewProp(node_node, BAD_CAST "lon", BAD_CAST str); |
1247 |
osm_generate_tags(node->tag, node_node); |
osm_generate_tags(node->tag, node_node); |
1248 |
} |
} |
1254 |
xmlNodePtr way_node = xmlNewChild(root_node, NULL, BAD_CAST "way", NULL); |
xmlNodePtr way_node = xmlNewChild(root_node, NULL, BAD_CAST "way", NULL); |
1255 |
snprintf(str, sizeof(str), "%u", (unsigned)way->id); |
snprintf(str, sizeof(str), "%u", (unsigned)way->id); |
1256 |
xmlNewProp(way_node, BAD_CAST "id", BAD_CAST str); |
xmlNewProp(way_node, BAD_CAST "id", BAD_CAST str); |
1257 |
|
snprintf(str, sizeof(str), "%u", (unsigned)way->version); |
1258 |
|
xmlNewProp(way_node, BAD_CAST "version", BAD_CAST str); |
1259 |
|
snprintf(str, sizeof(str), "%u", (unsigned)changeset); |
1260 |
|
xmlNewProp(way_node, BAD_CAST "changeset", BAD_CAST str); |
1261 |
|
|
1262 |
node_chain_t *node_chain = way->node_chain; |
node_chain_t *node_chain = way->node_chain; |
1263 |
while(node_chain) { |
while(node_chain) { |
1264 |
xmlNodePtr nd_node = xmlNewChild(way_node, NULL, BAD_CAST "nd", NULL); |
xmlNodePtr nd_node = xmlNewChild(way_node, NULL, BAD_CAST "nd", NULL); |
1265 |
char *str = g_strdup_printf("%ld", node_chain->node->id); |
char *str = g_strdup_printf(ITEM_ID_FORMAT, node_chain->node->id); |
1266 |
xmlNewProp(nd_node, BAD_CAST "ref", BAD_CAST str); |
xmlNewProp(nd_node, BAD_CAST "ref", BAD_CAST str); |
1267 |
g_free(str); |
g_free(str); |
1268 |
node_chain = node_chain->next; |
node_chain = node_chain->next; |
1279 |
BAD_CAST "relation", NULL); |
BAD_CAST "relation", NULL); |
1280 |
snprintf(str, sizeof(str), "%u", (unsigned)relation->id); |
snprintf(str, sizeof(str), "%u", (unsigned)relation->id); |
1281 |
xmlNewProp(rel_node, BAD_CAST "id", BAD_CAST str); |
xmlNewProp(rel_node, BAD_CAST "id", BAD_CAST str); |
1282 |
|
snprintf(str, sizeof(str), "%u", (unsigned)relation->version); |
1283 |
|
xmlNewProp(rel_node, BAD_CAST "version", BAD_CAST str); |
1284 |
|
snprintf(str, sizeof(str), "%u", (unsigned)changeset); |
1285 |
|
xmlNewProp(rel_node, BAD_CAST "changeset", BAD_CAST str); |
1286 |
|
|
1287 |
member_t *member = relation->member; |
member_t *member = relation->member; |
1288 |
while(member) { |
while(member) { |
1289 |
xmlNodePtr m_node = xmlNewChild(rel_node,NULL,BAD_CAST "member", NULL); |
xmlNodePtr m_node = xmlNewChild(rel_node,NULL,BAD_CAST "member", NULL); |
1290 |
char *str = NULL; |
char *str = NULL; |
1291 |
|
|
1292 |
switch(member->type) { |
switch(member->object.type) { |
1293 |
case NODE: |
case NODE: |
1294 |
xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "node"); |
xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "node"); |
1295 |
str = g_strdup_printf("%ld", member->node->id); |
str = g_strdup_printf(ITEM_ID_FORMAT, member->object.node->id); |
1296 |
break; |
break; |
1297 |
|
|
1298 |
case WAY: |
case WAY: |
1299 |
xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "way"); |
xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "way"); |
1300 |
str = g_strdup_printf("%ld", member->way->id); |
str = g_strdup_printf(ITEM_ID_FORMAT, member->object.way->id); |
1301 |
break; |
break; |
1302 |
|
|
1303 |
case RELATION: |
case RELATION: |
1304 |
xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "relation"); |
xmlNewProp(m_node, BAD_CAST "type", BAD_CAST "relation"); |
1305 |
str = g_strdup_printf("%ld", member->relation->id); |
str = g_strdup_printf(ITEM_ID_FORMAT, member->object.relation->id); |
1306 |
break; |
break; |
1307 |
|
|
1308 |
default: |
default: |
1342 |
} |
} |
1343 |
|
|
1344 |
/* build xml representation for a node */ |
/* build xml representation for a node */ |
1345 |
char *osm_generate_xml_node(osm_t *osm, node_t *node) { |
char *osm_generate_xml_node(osm_t *osm, item_id_t changeset, node_t *node) { |
1346 |
return osm_generate_xml(osm, NODE, node); |
return osm_generate_xml(osm, changeset, NODE, node); |
1347 |
} |
} |
1348 |
|
|
1349 |
/* build xml representation for a way */ |
/* build xml representation for a way */ |
1350 |
char *osm_generate_xml_way(osm_t *osm, way_t *way) { |
char *osm_generate_xml_way(osm_t *osm, item_id_t changeset, way_t *way) { |
1351 |
return osm_generate_xml(osm, WAY, way); |
return osm_generate_xml(osm, changeset, WAY, way); |
1352 |
} |
} |
1353 |
|
|
1354 |
/* build xml representation for a relation */ |
/* build xml representation for a relation */ |
1355 |
char *osm_generate_xml_relation(osm_t *osm, relation_t *relation) { |
char *osm_generate_xml_relation(osm_t *osm, item_id_t changeset, |
1356 |
return osm_generate_xml(osm, RELATION, relation); |
relation_t *relation) { |
1357 |
|
return osm_generate_xml(osm, changeset, RELATION, relation); |
1358 |
} |
} |
1359 |
|
|
1360 |
|
/* build xml representation for a changeset */ |
1361 |
|
char *osm_generate_xml_changeset(osm_t *osm, char *comment) { |
1362 |
|
xmlChar *result = NULL; |
1363 |
|
int len = 0; |
1364 |
|
|
1365 |
|
/* tags for this changeset */ |
1366 |
|
tag_t tag_comment = { |
1367 |
|
.key = "comment", .value = comment, .next = NULL }; |
1368 |
|
tag_t tag_creator = { |
1369 |
|
.key = "created_by", .value = PACKAGE " v" VERSION, .next = &tag_comment }; |
1370 |
|
|
1371 |
|
LIBXML_TEST_VERSION; |
1372 |
|
|
1373 |
|
xmlDocPtr doc = xmlNewDoc(BAD_CAST "1.0"); |
1374 |
|
xmlNodePtr root_node = xmlNewNode(NULL, BAD_CAST "osm"); |
1375 |
|
xmlDocSetRootElement(doc, root_node); |
1376 |
|
|
1377 |
|
xmlNodePtr cs_node = xmlNewChild(root_node, NULL, BAD_CAST "changeset", NULL); |
1378 |
|
osm_generate_tags(&tag_creator, cs_node); |
1379 |
|
|
1380 |
|
xmlDocDumpFormatMemoryEnc(doc, &result, &len, "UTF-8", 1); |
1381 |
|
xmlFreeDoc(doc); |
1382 |
|
xmlCleanupParser(); |
1383 |
|
|
1384 |
|
// puts("xml encoding result:"); |
1385 |
|
// puts((char*)result); |
1386 |
|
|
1387 |
|
return (char*)result; |
1388 |
|
} |
1389 |
|
|
1390 |
|
|
1391 |
|
/* the following three functions are eating much CPU power */ |
1392 |
|
/* as they search the objects lists. Hashing is supposed to help */ |
1393 |
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) { |
1394 |
|
if(id > 0 && osm->node_hash) { |
1395 |
|
// use hash table if present |
1396 |
|
hash_item_t *item = osm->node_hash->hash[ID2HASH(id)]; |
1397 |
|
while(item) { |
1398 |
|
if(item->data.node->id == id) |
1399 |
|
return item->data.node; |
1400 |
|
|
1401 |
|
item = item->next; |
1402 |
|
} |
1403 |
|
} |
1404 |
|
|
1405 |
|
/* use linear search if no hash tables are present or search in hash table failed */ |
1406 |
node_t *node = osm->node; |
node_t *node = osm->node; |
1407 |
while(node) { |
while(node) { |
1408 |
if(node->id == id) |
if(node->id == id) |
1409 |
return node; |
return node; |
1410 |
|
|
1411 |
node = node->next; |
node = node->next; |
1412 |
} |
} |
1413 |
|
|
1414 |
return NULL; |
return NULL; |
1415 |
} |
} |
1416 |
|
|
1417 |
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) { |
1418 |
|
if(id > 0 && osm->way_hash) { |
1419 |
|
// use hash table if present |
1420 |
|
hash_item_t *item = osm->way_hash->hash[ID2HASH(id)]; |
1421 |
|
while(item) { |
1422 |
|
if(item->data.way->id == id) |
1423 |
|
return item->data.way; |
1424 |
|
|
1425 |
|
item = item->next; |
1426 |
|
} |
1427 |
|
} |
1428 |
|
|
1429 |
|
/* use linear search if no hash tables are present or search on hash table failed */ |
1430 |
way_t *way = osm->way; |
way_t *way = osm->way; |
1431 |
while(way) { |
while(way) { |
1432 |
if(way->id == id) |
if(way->id == id) |
1433 |
return way; |
return way; |
1434 |
|
|
1435 |
way = way->next; |
way = way->next; |
1436 |
} |
} |
1437 |
|
|
1438 |
return NULL; |
return NULL; |
1439 |
} |
} |
1440 |
|
|
1441 |
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) { |
1442 |
|
// use linear search |
1443 |
relation_t *relation = osm->relation; |
relation_t *relation = osm->relation; |
1444 |
while(relation) { |
while(relation) { |
1445 |
if(relation->id == id) |
if(relation->id == id) |
1497 |
return 0; |
return 0; |
1498 |
} |
} |
1499 |
|
|
1500 |
|
item_id_t osm_new_relation_id(osm_t *osm) { |
1501 |
|
item_id_t id = -1; |
1502 |
|
|
1503 |
|
while(TRUE) { |
1504 |
|
gboolean found = FALSE; |
1505 |
|
relation_t *relation = osm->relation; |
1506 |
|
while(relation) { |
1507 |
|
if(relation->id == id) |
1508 |
|
found = TRUE; |
1509 |
|
|
1510 |
|
relation = relation->next; |
1511 |
|
} |
1512 |
|
|
1513 |
|
/* no such id so far -> use it */ |
1514 |
|
if(!found) return id; |
1515 |
|
|
1516 |
|
id--; |
1517 |
|
} |
1518 |
|
g_assert(0); |
1519 |
|
return 0; |
1520 |
|
} |
1521 |
|
|
1522 |
node_t *osm_node_new(osm_t *osm, gint x, gint y) { |
node_t *osm_node_new(osm_t *osm, gint x, gint y) { |
1523 |
printf("Creating new node\n"); |
printf("Creating new node\n"); |
1524 |
|
|
1525 |
node_t *node = g_new0(node_t, 1); |
node_t *node = g_new0(node_t, 1); |
1526 |
|
node->version = 1; |
1527 |
node->lpos.x = x; |
node->lpos.x = x; |
1528 |
node->lpos.y = y; |
node->lpos.y = y; |
1529 |
node->visible = TRUE; |
node->visible = TRUE; |
1530 |
node->time = time(NULL); |
node->time = time(NULL); |
1531 |
|
|
|
/* add created_by tag */ |
|
|
node->tag = g_new0(tag_t, 1); |
|
|
node->tag->key = g_strdup("created_by"); |
|
|
node->tag->value = g_strdup(PACKAGE " v" VERSION); |
|
|
|
|
1532 |
/* convert screen position back to ll */ |
/* convert screen position back to ll */ |
1533 |
lpos2pos(osm->bounds, &node->lpos, &node->pos); |
lpos2pos(osm->bounds, &node->lpos, &node->pos); |
1534 |
|
|
1551 |
*lnode = node; |
*lnode = node; |
1552 |
} |
} |
1553 |
|
|
1554 |
|
void osm_node_restore(osm_t *osm, node_t *node) { |
1555 |
|
printf("Restoring node\n"); |
1556 |
|
|
1557 |
|
/* attach to end of node list */ |
1558 |
|
node_t **lnode = &osm->node; |
1559 |
|
while(*lnode) lnode = &(*lnode)->next; |
1560 |
|
*lnode = node; |
1561 |
|
} |
1562 |
|
|
1563 |
way_t *osm_way_new(void) { |
way_t *osm_way_new(void) { |
1564 |
printf("Creating new way\n"); |
printf("Creating new way\n"); |
1565 |
|
|
1566 |
way_t *way = g_new0(way_t, 1); |
way_t *way = g_new0(way_t, 1); |
1567 |
|
way->version = 1; |
1568 |
way->visible = TRUE; |
way->visible = TRUE; |
1569 |
way->flags = OSM_FLAG_NEW; |
way->flags = OSM_FLAG_NEW; |
1570 |
way->time = time(NULL); |
way->time = time(NULL); |
1571 |
|
|
|
/* add created_by tag */ |
|
|
way->tag = g_new0(tag_t, 1); |
|
|
way->tag->key = g_strdup("created_by"); |
|
|
way->tag->value = g_strdup(PACKAGE " v" VERSION); |
|
|
|
|
1572 |
return way; |
return way; |
1573 |
} |
} |
1574 |
|
|
1592 |
|
|
1593 |
/* new nodes aren't stored on the server and are just deleted permanently */ |
/* new nodes aren't stored on the server and are just deleted permanently */ |
1594 |
if(node->flags & OSM_FLAG_NEW) { |
if(node->flags & OSM_FLAG_NEW) { |
1595 |
printf("About to delete NEW node #%ld -> force permanent delete\n", |
printf("About to delete NEW node #" ITEM_ID_FORMAT |
1596 |
node->id); |
" -> force permanent delete\n", node->id); |
1597 |
permanently = TRUE; |
permanently = TRUE; |
1598 |
} |
} |
1599 |
|
|
1629 |
} |
} |
1630 |
|
|
1631 |
if(!permanently) { |
if(!permanently) { |
1632 |
printf("mark node #%ld as deleted\n", node->id); |
printf("mark node #" ITEM_ID_FORMAT " as deleted\n", node->id); |
1633 |
node->flags |= OSM_FLAG_DELETED; |
node->flags |= OSM_FLAG_DELETED; |
1634 |
} else { |
} else { |
1635 |
printf("permanently delete node #%ld\n", node->id); |
printf("permanently delete node #" ITEM_ID_FORMAT "\n", node->id); |
1636 |
|
|
1637 |
/* remove it from the chain */ |
/* remove it from the chain */ |
1638 |
node_t **cnode = &osm->node; |
node_t **cnode = &osm->node; |
1673 |
|
|
1674 |
member_t *member = relation->member; |
member_t *member = relation->member; |
1675 |
while(member) { |
while(member) { |
1676 |
switch(member->type) { |
switch(member->object.type) { |
1677 |
case NODE: |
case NODE: |
1678 |
/* nodes are checked directly */ |
/* nodes are checked directly */ |
1679 |
if(member->node == node) |
if(member->object.node == node) |
1680 |
is_member = TRUE; |
is_member = TRUE; |
1681 |
break; |
break; |
1682 |
|
|
1683 |
case WAY: { |
case WAY: { |
1684 |
/* ways have to be checked for the nodes they consist of */ |
/* ways have to be checked for the nodes they consist of */ |
1685 |
node_chain_t *chain = member->way->node_chain; |
node_chain_t *chain = member->object.way->node_chain; |
1686 |
while(chain && !is_member) { |
while(chain && !is_member) { |
1687 |
if(chain->node == node) |
if(chain->node == node) |
1688 |
is_member = TRUE; |
is_member = TRUE; |
1720 |
|
|
1721 |
member_t *member = relation->member; |
member_t *member = relation->member; |
1722 |
while(member) { |
while(member) { |
1723 |
switch(member->type) { |
switch(member->object.type) { |
1724 |
case WAY: { |
case WAY: { |
1725 |
/* ways can be check directly */ |
/* ways can be check directly */ |
1726 |
if(member->way == way) |
if(member->object.way == way) |
1727 |
|
is_member = TRUE; |
1728 |
|
} break; |
1729 |
|
|
1730 |
|
default: |
1731 |
|
break; |
1732 |
|
} |
1733 |
|
member = member->next; |
1734 |
|
} |
1735 |
|
|
1736 |
|
/* way is a member of this relation, so move it to the member chain */ |
1737 |
|
if(is_member) { |
1738 |
|
*cur_rel_chain = g_new0(relation_chain_t, 1); |
1739 |
|
(*cur_rel_chain)->relation = relation; |
1740 |
|
cur_rel_chain = &((*cur_rel_chain)->next); |
1741 |
|
} |
1742 |
|
|
1743 |
|
relation = relation->next; |
1744 |
|
} |
1745 |
|
|
1746 |
|
return rel_chain; |
1747 |
|
} |
1748 |
|
|
1749 |
|
/* return all relations a relation is in */ |
1750 |
|
relation_chain_t *osm_relation_to_relation(osm_t *osm, relation_t *rel) { |
1751 |
|
relation_chain_t *rel_chain = NULL, **cur_rel_chain = &rel_chain; |
1752 |
|
|
1753 |
|
relation_t *relation = osm->relation; |
1754 |
|
while(relation) { |
1755 |
|
gboolean is_member = FALSE; |
1756 |
|
|
1757 |
|
member_t *member = relation->member; |
1758 |
|
while(member) { |
1759 |
|
switch(member->object.type) { |
1760 |
|
case RELATION: { |
1761 |
|
/* relations can be check directly */ |
1762 |
|
if(member->object.relation == rel) |
1763 |
is_member = TRUE; |
is_member = TRUE; |
1764 |
} break; |
} break; |
1765 |
|
|
1782 |
return rel_chain; |
return rel_chain; |
1783 |
} |
} |
1784 |
|
|
1785 |
|
/* return all relations an object is in */ |
1786 |
|
relation_chain_t *osm_object_to_relation(osm_t *osm, object_t *object) { |
1787 |
|
relation_chain_t *rel_chain = NULL; |
1788 |
|
|
1789 |
|
switch(object->type) { |
1790 |
|
case NODE: |
1791 |
|
rel_chain = osm_node_to_relation(osm, object->node); |
1792 |
|
break; |
1793 |
|
|
1794 |
|
case WAY: |
1795 |
|
rel_chain = osm_way_to_relation(osm, object->way); |
1796 |
|
break; |
1797 |
|
|
1798 |
|
case RELATION: |
1799 |
|
rel_chain = osm_relation_to_relation(osm, object->relation); |
1800 |
|
break; |
1801 |
|
|
1802 |
|
default: |
1803 |
|
break; |
1804 |
|
} |
1805 |
|
|
1806 |
|
return rel_chain; |
1807 |
|
} |
1808 |
|
|
1809 |
|
void osm_relation_chain_free(relation_chain_t *rchain) { |
1810 |
|
while(rchain) { |
1811 |
|
relation_chain_t *next = rchain->next; |
1812 |
|
g_free(rchain); |
1813 |
|
rchain = next; |
1814 |
|
} |
1815 |
|
} |
1816 |
|
|
1817 |
/* return all ways a node is in */ |
/* return all ways a node is in */ |
1818 |
way_chain_t *osm_node_to_way(osm_t *osm, node_t *node) { |
way_chain_t *osm_node_to_way(osm_t *osm, node_t *node) { |
1819 |
way_chain_t *chain = NULL, **cur_chain = &chain; |
way_chain_t *chain = NULL, **cur_chain = &chain; |
1853 |
/* be deleted */ |
/* be deleted */ |
1854 |
void osm_node_remove_from_relation(osm_t *osm, node_t *node) { |
void osm_node_remove_from_relation(osm_t *osm, node_t *node) { |
1855 |
relation_t *relation = osm->relation; |
relation_t *relation = osm->relation; |
1856 |
printf("removing node #%ld from all relations:\n", node->id); |
printf("removing node #" ITEM_ID_FORMAT " from all relations:\n", node->id); |
1857 |
|
|
1858 |
while(relation) { |
while(relation) { |
1859 |
member_t **member = &relation->member; |
member_t **member = &relation->member; |
1860 |
while(*member) { |
while(*member) { |
1861 |
if(((*member)->type == NODE) && |
if(((*member)->object.type == NODE) && |
1862 |
((*member)->node == node)) { |
((*member)->object.node == node)) { |
1863 |
|
|
1864 |
printf(" from relation #%ld\n", relation->id); |
printf(" from relation #" ITEM_ID_FORMAT "\n", relation->id); |
1865 |
|
|
1866 |
member_t *cur = *member; |
member_t *cur = *member; |
1867 |
*member = (*member)->next; |
*member = (*member)->next; |
1878 |
/* remove the given way from all relations */ |
/* remove the given way from all relations */ |
1879 |
void osm_way_remove_from_relation(osm_t *osm, way_t *way) { |
void osm_way_remove_from_relation(osm_t *osm, way_t *way) { |
1880 |
relation_t *relation = osm->relation; |
relation_t *relation = osm->relation; |
1881 |
printf("removing way #%ld from all relations:\n", way->id); |
printf("removing way #" ITEM_ID_FORMAT " from all relations:\n", way->id); |
1882 |
|
|
1883 |
while(relation) { |
while(relation) { |
1884 |
member_t **member = &relation->member; |
member_t **member = &relation->member; |
1885 |
while(*member) { |
while(*member) { |
1886 |
if(((*member)->type == WAY) && |
if(((*member)->object.type == WAY) && |
1887 |
((*member)->way == way)) { |
((*member)->object.way == way)) { |
1888 |
|
|
1889 |
printf(" from relation #%ld\n", relation->id); |
printf(" from relation #" ITEM_ID_FORMAT "\n", relation->id); |
1890 |
|
|
1891 |
member_t *cur = *member; |
member_t *cur = *member; |
1892 |
*member = (*member)->next; |
*member = (*member)->next; |
1900 |
} |
} |
1901 |
} |
} |
1902 |
|
|
1903 |
|
relation_t *osm_relation_new(void) { |
1904 |
|
printf("Creating new relation\n"); |
1905 |
|
|
1906 |
|
relation_t *relation = g_new0(relation_t, 1); |
1907 |
|
relation->version = 1; |
1908 |
|
relation->visible = TRUE; |
1909 |
|
relation->flags = OSM_FLAG_NEW; |
1910 |
|
relation->time = time(NULL); |
1911 |
|
|
1912 |
|
return relation; |
1913 |
|
} |
1914 |
|
|
1915 |
|
void osm_relation_attach(osm_t *osm, relation_t *relation) { |
1916 |
|
printf("Attaching relation\n"); |
1917 |
|
|
1918 |
|
relation->id = osm_new_relation_id(osm); |
1919 |
|
relation->flags = OSM_FLAG_NEW; |
1920 |
|
|
1921 |
|
/* attach to end of relation list */ |
1922 |
|
relation_t **lrelation = &osm->relation; |
1923 |
|
while(*lrelation) lrelation = &(*lrelation)->next; |
1924 |
|
*lrelation = relation; |
1925 |
|
} |
1926 |
|
|
1927 |
|
|
1928 |
void osm_way_delete(osm_t *osm, icon_t **icon, |
void osm_way_delete(osm_t *osm, icon_t **icon, |
1929 |
way_t *way, gboolean permanently) { |
way_t *way, gboolean permanently) { |
1930 |
|
|
1931 |
/* new ways aren't stored on the server and are just deleted permanently */ |
/* new ways aren't stored on the server and are just deleted permanently */ |
1932 |
if(way->flags & OSM_FLAG_NEW) { |
if(way->flags & OSM_FLAG_NEW) { |
1933 |
printf("About to delete NEW way #%ld -> force permanent delete\n", |
printf("About to delete NEW way #" ITEM_ID_FORMAT |
1934 |
way->id); |
" -> force permanent delete\n", way->id); |
1935 |
permanently = TRUE; |
permanently = TRUE; |
1936 |
} |
} |
1937 |
|
|
1940 |
while(*chain) { |
while(*chain) { |
1941 |
|
|
1942 |
(*chain)->node->ways--; |
(*chain)->node->ways--; |
1943 |
printf("checking node #%ld (still used by %d)\n", |
printf("checking node #" ITEM_ID_FORMAT " (still used by %d)\n", |
1944 |
(*chain)->node->id, (*chain)->node->ways); |
(*chain)->node->id, (*chain)->node->ways); |
1945 |
|
|
1946 |
/* this node must only be part of this way */ |
/* this node must only be part of this way */ |
1966 |
way->node_chain = NULL; |
way->node_chain = NULL; |
1967 |
|
|
1968 |
if(!permanently) { |
if(!permanently) { |
1969 |
printf("mark way #%ld as deleted\n", way->id); |
printf("mark way #" ITEM_ID_FORMAT " as deleted\n", way->id); |
1970 |
way->flags |= OSM_FLAG_DELETED; |
way->flags |= OSM_FLAG_DELETED; |
1971 |
} else { |
} else { |
1972 |
printf("permanently delete way #%ld\n", way->id); |
printf("permanently delete way #" ITEM_ID_FORMAT "\n", way->id); |
1973 |
|
|
1974 |
/* remove it from the chain */ |
/* remove it from the chain */ |
1975 |
way_t **cway = &osm->way; |
way_t **cway = &osm->way; |
1988 |
} |
} |
1989 |
} |
} |
1990 |
|
|
1991 |
void osm_way_revert(way_t *way) { |
void osm_relation_delete(osm_t *osm, relation_t *relation, |
1992 |
|
gboolean permanently) { |
1993 |
|
|
1994 |
|
/* new relations aren't stored on the server and are just */ |
1995 |
|
/* deleted permanently */ |
1996 |
|
if(relation->flags & OSM_FLAG_NEW) { |
1997 |
|
printf("About to delete NEW relation #" ITEM_ID_FORMAT |
1998 |
|
" -> force permanent delete\n", relation->id); |
1999 |
|
permanently = TRUE; |
2000 |
|
} |
2001 |
|
|
2002 |
|
/* the deletion of a relation doesn't affect the members as they */ |
2003 |
|
/* don't have any reference to the relation they are part of */ |
2004 |
|
|
2005 |
|
if(!permanently) { |
2006 |
|
printf("mark relation #" ITEM_ID_FORMAT " as deleted\n", relation->id); |
2007 |
|
relation->flags |= OSM_FLAG_DELETED; |
2008 |
|
} else { |
2009 |
|
printf("permanently delete relation #" ITEM_ID_FORMAT "\n", relation->id); |
2010 |
|
|
2011 |
|
/* remove it from the chain */ |
2012 |
|
relation_t **crelation = &osm->relation; |
2013 |
|
int found = 0; |
2014 |
|
|
2015 |
|
while(*crelation) { |
2016 |
|
if(*crelation == relation) { |
2017 |
|
found++; |
2018 |
|
*crelation = (*crelation)->next; |
2019 |
|
|
2020 |
|
osm_relation_free(relation); |
2021 |
|
} else |
2022 |
|
crelation = &((*crelation)->next); |
2023 |
|
} |
2024 |
|
g_assert(found == 1); |
2025 |
|
} |
2026 |
|
} |
2027 |
|
|
2028 |
|
void osm_way_reverse(way_t *way) { |
2029 |
node_chain_t *new = NULL; |
node_chain_t *new = NULL; |
2030 |
|
|
2031 |
/* walk old chain first to last */ |
/* walk old chain first to last */ |
2043 |
way->node_chain = new; |
way->node_chain = new; |
2044 |
} |
} |
2045 |
|
|
2046 |
|
static const char *DS_ONEWAY_FWD = "yes"; |
2047 |
|
static const char *DS_ONEWAY_REV = "-1"; |
2048 |
|
static const char *DS_LEFT_SUFFIX = ":left"; |
2049 |
|
static const char *DS_RIGHT_SUFFIX = ":right"; |
2050 |
|
|
2051 |
|
/* Reverse direction-sensitive tags like "oneway". Marks the way as dirty if |
2052 |
|
* anything is changed, and returns the number of flipped tags. */ |
2053 |
|
|
2054 |
|
guint |
2055 |
|
osm_way_reverse_direction_sensitive_tags (way_t *way) { |
2056 |
|
tag_t *tag = way->tag; |
2057 |
|
guint n_tags_altered = 0; |
2058 |
|
while (tag != NULL) { |
2059 |
|
char *lc_key = g_ascii_strdown(tag->key, -1); |
2060 |
|
char *lc_value = g_ascii_strdown(tag->value, -1); |
2061 |
|
|
2062 |
|
if (strcmp(lc_key, "oneway") == 0) { |
2063 |
|
// oneway={yes/true/1/-1} is unusual. |
2064 |
|
// Favour "yes" and "-1". |
2065 |
|
if ((strcmp(lc_value, DS_ONEWAY_FWD) == 0) || |
2066 |
|
(strcmp(lc_value, "true") == 0) || |
2067 |
|
(strcmp(lc_value, "1") == 0)) { |
2068 |
|
g_free(tag->value); |
2069 |
|
tag->value = g_strdup(DS_ONEWAY_REV); |
2070 |
|
n_tags_altered++; |
2071 |
|
} |
2072 |
|
else if (strcmp(lc_value, DS_ONEWAY_REV) == 0) { |
2073 |
|
g_free(tag->value); |
2074 |
|
tag->value = g_strdup(DS_ONEWAY_FWD); |
2075 |
|
n_tags_altered++; |
2076 |
|
} |
2077 |
|
else { |
2078 |
|
printf("warning: unknown tag: %s=%s\n", tag->key, tag->value); |
2079 |
|
} |
2080 |
|
} |
2081 |
|
|
2082 |
|
// :left and :right suffixes |
2083 |
|
else if (g_str_has_suffix(lc_key, DS_LEFT_SUFFIX)) { |
2084 |
|
char *key_old = tag->key; |
2085 |
|
char *lastcolon = rindex(key_old, ':'); |
2086 |
|
g_assert(lastcolon != NULL); |
2087 |
|
*lastcolon = '\000'; |
2088 |
|
tag->key = g_strconcat(key_old, DS_RIGHT_SUFFIX, NULL); |
2089 |
|
*lastcolon = ':'; |
2090 |
|
g_free(key_old); |
2091 |
|
n_tags_altered++; |
2092 |
|
} |
2093 |
|
else if (g_str_has_suffix(lc_key, DS_RIGHT_SUFFIX)) { |
2094 |
|
char *key_old = tag->key; |
2095 |
|
char *lastcolon = rindex(key_old, ':'); |
2096 |
|
g_assert(lastcolon != NULL); |
2097 |
|
*lastcolon = '\000'; |
2098 |
|
tag->key = g_strconcat(key_old, DS_LEFT_SUFFIX, NULL); |
2099 |
|
*lastcolon = ':'; |
2100 |
|
g_free(key_old); |
2101 |
|
n_tags_altered++; |
2102 |
|
} |
2103 |
|
|
2104 |
|
g_free(lc_key); |
2105 |
|
g_free(lc_value); |
2106 |
|
tag = tag->next; |
2107 |
|
} |
2108 |
|
if (n_tags_altered > 0) { |
2109 |
|
way->flags |= OSM_FLAG_DIRTY; |
2110 |
|
} |
2111 |
|
return n_tags_altered; |
2112 |
|
} |
2113 |
|
|
2114 |
|
/* Reverse a way's role within relations where the role is direction-sensitive. |
2115 |
|
* Returns the number of roles flipped, and marks any relations changed as |
2116 |
|
* dirty. */ |
2117 |
|
|
2118 |
|
static const char *DS_ROUTE_FORWARD = "forward"; |
2119 |
|
static const char *DS_ROUTE_REVERSE = "reverse"; |
2120 |
|
|
2121 |
|
guint |
2122 |
|
osm_way_reverse_direction_sensitive_roles(osm_t *osm, way_t *way) { |
2123 |
|
relation_chain_t *rel_chain0, *rel_chain; |
2124 |
|
rel_chain0 = rel_chain = osm_way_to_relation(osm, way); |
2125 |
|
guint n_roles_flipped = 0; |
2126 |
|
|
2127 |
|
for (; rel_chain != NULL; rel_chain = rel_chain->next) { |
2128 |
|
char *type = osm_tag_get_by_key(rel_chain->relation->tag, "type"); |
2129 |
|
|
2130 |
|
// Route relations; http://wiki.openstreetmap.org/wiki/Relation:route |
2131 |
|
if (strcasecmp(type, "route") == 0) { |
2132 |
|
|
2133 |
|
// First find the member corresponding to our way: |
2134 |
|
member_t *member = rel_chain->relation->member; |
2135 |
|
for (; member != NULL; member = member->next) { |
2136 |
|
if (member->object.type == WAY) { |
2137 |
|
if (member->object.way == way) |
2138 |
|
break; |
2139 |
|
} |
2140 |
|
if (member->object.type == WAY_ID) { |
2141 |
|
if (member->object.id == way->id) |
2142 |
|
break; |
2143 |
|
} |
2144 |
|
} |
2145 |
|
g_assert(member); // osm_way_to_relation() broken? |
2146 |
|
|
2147 |
|
// Then flip its role if it's one of the direction-sensitive ones |
2148 |
|
if (member->role == NULL) { |
2149 |
|
printf("null role in route relation -> ignore\n"); |
2150 |
|
} |
2151 |
|
else if (strcasecmp(member->role, DS_ROUTE_FORWARD) == 0) { |
2152 |
|
g_free(member->role); |
2153 |
|
member->role = g_strdup(DS_ROUTE_REVERSE); |
2154 |
|
rel_chain->relation->flags |= OSM_FLAG_DIRTY; |
2155 |
|
++n_roles_flipped; |
2156 |
|
} |
2157 |
|
else if (strcasecmp(member->role, DS_ROUTE_REVERSE) == 0) { |
2158 |
|
g_free(member->role); |
2159 |
|
member->role = g_strdup(DS_ROUTE_FORWARD); |
2160 |
|
rel_chain->relation->flags |= OSM_FLAG_DIRTY; |
2161 |
|
++n_roles_flipped; |
2162 |
|
} |
2163 |
|
|
2164 |
|
// TODO: what about numbered stops? Guess we ignore them; there's no |
2165 |
|
// consensus about whether they should be placed on the way or to one side |
2166 |
|
// of it. |
2167 |
|
|
2168 |
|
}//if-route |
2169 |
|
|
2170 |
|
|
2171 |
|
} |
2172 |
|
if (rel_chain0) { |
2173 |
|
g_free(rel_chain0); |
2174 |
|
} |
2175 |
|
return n_roles_flipped; |
2176 |
|
} |
2177 |
|
|
2178 |
node_t *osm_way_get_first_node(way_t *way) { |
node_t *osm_way_get_first_node(way_t *way) { |
2179 |
node_chain_t *chain = way->node_chain; |
node_chain_t *chain = way->node_chain; |
2180 |
if(!chain) return NULL; |
if(!chain) return NULL; |
2232 |
|
|
2233 |
return new_tags; |
return new_tags; |
2234 |
} |
} |
2235 |
|
|
2236 |
|
/* return plain text of type */ |
2237 |
|
char *osm_object_type_string(object_t *object) { |
2238 |
|
const struct { type_t type; char *name; } types[] = { |
2239 |
|
{ ILLEGAL, "illegal" }, |
2240 |
|
{ NODE, "node" }, |
2241 |
|
{ WAY, "way" }, |
2242 |
|
{ RELATION, "relation" }, |
2243 |
|
{ NODE_ID, "node id" }, |
2244 |
|
{ WAY_ID, "way id" }, |
2245 |
|
{ RELATION_ID, "relation id" }, |
2246 |
|
{ 0, NULL } |
2247 |
|
}; |
2248 |
|
|
2249 |
|
int i; |
2250 |
|
for(i=0;types[i].name;i++) |
2251 |
|
if(object->type == types[i].type) |
2252 |
|
return types[i].name; |
2253 |
|
|
2254 |
|
return NULL; |
2255 |
|
} |
2256 |
|
|
2257 |
|
char *osm_object_string(object_t *object) { |
2258 |
|
char *type_str = osm_object_type_string(object); |
2259 |
|
|
2260 |
|
if(!object) |
2261 |
|
return g_strdup_printf("%s #<invalid>", type_str); |
2262 |
|
|
2263 |
|
switch(object->type) { |
2264 |
|
case ILLEGAL: |
2265 |
|
return g_strdup_printf("%s #<unspec>", type_str); |
2266 |
|
break; |
2267 |
|
case NODE: |
2268 |
|
return g_strdup_printf("%s #" ITEM_ID_FORMAT, type_str, object->node->id); |
2269 |
|
break; |
2270 |
|
case WAY: |
2271 |
|
return g_strdup_printf("%s #" ITEM_ID_FORMAT, type_str, object->way->id); |
2272 |
|
break; |
2273 |
|
case RELATION: |
2274 |
|
return g_strdup_printf("%s #" ITEM_ID_FORMAT, type_str, |
2275 |
|
object->relation->id); |
2276 |
|
break; |
2277 |
|
case NODE_ID: |
2278 |
|
case WAY_ID: |
2279 |
|
case RELATION_ID: |
2280 |
|
return g_strdup_printf("%s #" ITEM_ID_FORMAT, type_str, object->id); |
2281 |
|
break; |
2282 |
|
} |
2283 |
|
return NULL; |
2284 |
|
} |
2285 |
|
|
2286 |
|
char *osm_object_id_string(object_t *object) { |
2287 |
|
if(!object) return NULL; |
2288 |
|
|
2289 |
|
switch(object->type) { |
2290 |
|
case ILLEGAL: |
2291 |
|
return NULL; |
2292 |
|
break; |
2293 |
|
case NODE: |
2294 |
|
return g_strdup_printf("#"ITEM_ID_FORMAT, object->node->id); |
2295 |
|
break; |
2296 |
|
case WAY: |
2297 |
|
return g_strdup_printf("#"ITEM_ID_FORMAT, object->way->id); |
2298 |
|
break; |
2299 |
|
case RELATION: |
2300 |
|
return g_strdup_printf("#"ITEM_ID_FORMAT, object->relation->id); |
2301 |
|
break; |
2302 |
|
case NODE_ID: |
2303 |
|
case WAY_ID: |
2304 |
|
case RELATION_ID: |
2305 |
|
return g_strdup_printf("#"ITEM_ID_FORMAT, object->id); |
2306 |
|
break; |
2307 |
|
} |
2308 |
|
return NULL; |
2309 |
|
} |
2310 |
|
|
2311 |
|
tag_t *osm_object_get_tags(object_t *object) { |
2312 |
|
if(!object) return NULL; |
2313 |
|
|
2314 |
|
switch(object->type) { |
2315 |
|
case ILLEGAL: |
2316 |
|
return NULL; |
2317 |
|
break; |
2318 |
|
case NODE: |
2319 |
|
return object->node->tag; |
2320 |
|
break; |
2321 |
|
case WAY: |
2322 |
|
return object->way->tag; |
2323 |
|
break; |
2324 |
|
case RELATION: |
2325 |
|
return object->relation->tag; |
2326 |
|
break; |
2327 |
|
case NODE_ID: |
2328 |
|
case WAY_ID: |
2329 |
|
case RELATION_ID: |
2330 |
|
return NULL; |
2331 |
|
break; |
2332 |
|
} |
2333 |
|
return NULL; |
2334 |
|
} |
2335 |
|
|
2336 |
|
|
2337 |
|
gint osm_relation_members_num(relation_t *relation) { |
2338 |
|
gint num = 0; |
2339 |
|
member_t *member = relation->member; |
2340 |
|
while(member) { |
2341 |
|
num++; |
2342 |
|
member = member->next; |
2343 |
|
} |
2344 |
|
return num; |
2345 |
|
} |
2346 |
|
|
2347 |
|
void osm_object_set_flags(object_t *object, int set, int clr) { |
2348 |
|
|
2349 |
|
switch(object->type) { |
2350 |
|
case NODE: |
2351 |
|
object->node->flags |= set; |
2352 |
|
object->node->flags &= ~clr; |
2353 |
|
break; |
2354 |
|
|
2355 |
|
case WAY: |
2356 |
|
object->way->flags |= set; |
2357 |
|
object->way->flags &= ~clr; |
2358 |
|
break; |
2359 |
|
|
2360 |
|
case RELATION: |
2361 |
|
object->relation->flags |= set; |
2362 |
|
object->relation->flags &= ~clr; |
2363 |
|
break; |
2364 |
|
|
2365 |
|
default: |
2366 |
|
g_assert(0); |
2367 |
|
break; |
2368 |
|
} |
2369 |
|
} |
2370 |
|
|
2371 |
// vim:et:ts=8:sw=2:sts=2:ai |
// vim:et:ts=8:sw=2:sts=2:ai |