Diff of /trunk/src/osm.c

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

revision 35 by achadwick, Wed Dec 31 17:26:59 2008 UTC revision 39 by harbaum, Fri Jan 16 20:01:07 2009 UTC
# Line 17  Line 17 
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  /* xml parsing has a performance issue */
21    // #define OSM_DOM_PARSER
22    // #define OSM_STREAM_PARSER
23    #define OSM_QND_XML_PARSER
24    
25  #include <stdio.h>  #include <stdio.h>
26  #include <stdlib.h>  #include <stdlib.h>
# Line 55  static void osm_bounds_dump(bounds_t *bo Line 58  static void osm_bounds_dump(bounds_t *bo
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;
# Line 150  void osm_users_dump(user_t *user) { Line 153  void osm_users_dump(user_t *user) {
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;
# Line 171  static user_t *osm_user(osm_t *osm, char Line 175  static user_t *osm_user(osm_t *osm, char
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;
# Line 324  void osm_nodes_dump(node_t *node) { Line 330  void osm_nodes_dump(node_t *node) {
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;
# Line 492  node_chain_t *osm_parse_osm_way_nd(osm_t Line 498  node_chain_t *osm_parse_osm_way_nd(osm_t
498    return NULL;    return NULL;
499  }  }
500    
501  #ifndef OSM_STREAM_PARSER  #ifdef OSM_DOM_PARSER
502  static way_t *osm_parse_osm_way(osm_t *osm,  static way_t *osm_parse_osm_way(osm_t *osm,
503                            xmlDocPtr doc, xmlNode *a_node) {                            xmlDocPtr doc, xmlNode *a_node) {
504    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
# Line 697  member_t *osm_parse_osm_relation_member( Line 703  member_t *osm_parse_osm_relation_member(
703    return member;    return member;
704  }  }
705    
706  #ifndef OSM_STREAM_PARSER  #ifdef OSM_DOM_PARSER
707  static relation_t *osm_parse_osm_relation(osm_t *osm,  static relation_t *osm_parse_osm_relation(osm_t *osm,
708                            xmlDocPtr doc, xmlNode *a_node) {                            xmlDocPtr doc, xmlNode *a_node) {
709    xmlNode *cur_node = NULL;    xmlNode *cur_node = NULL;
# Line 1385  static osm_t *process_file(const char *f Line 1391  static osm_t *process_file(const char *f
1391  /* ----------------------- end of stream parser tests ------------------- */  /* ----------------------- end of stream parser tests ------------------- */
1392  #endif  #endif
1393    
1394    #ifdef OSM_QND_XML_PARSER
1395    /* -------------------------- qnd-xml parser tests ------------------- */
1396    
1397    gboolean osm_bounds_cb(qnd_xml_stack_t *stack,
1398                           qnd_xml_attribute_t *attributes, gpointer data) {
1399    
1400      /* get parent pointer */
1401      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1402    
1403      if(osm->bounds) {
1404        errorf(NULL, "Doubly defined bounds");
1405        return FALSE;
1406      }
1407    
1408      bounds_t *bounds = osm->bounds = g_new0(bounds_t, 1);
1409    
1410      bounds->ll_min.lat = bounds->ll_min.lon = NAN;
1411      bounds->ll_max.lat = bounds->ll_max.lon = NAN;
1412    
1413      qnd_xml_get_prop_double(attributes, "minlat", &bounds->ll_min.lat);
1414      qnd_xml_get_prop_double(attributes, "minlon", &bounds->ll_min.lon);
1415      qnd_xml_get_prop_double(attributes, "maxlat", &bounds->ll_max.lat);
1416      qnd_xml_get_prop_double(attributes, "maxlon", &bounds->ll_max.lon);
1417    
1418      if(isnan(bounds->ll_min.lat) || isnan(bounds->ll_min.lon) ||
1419         isnan(bounds->ll_max.lat) || isnan(bounds->ll_max.lon)) {
1420        errorf(NULL, "Invalid coordinate in bounds (%f/%f/%f/%f)",
1421               bounds->ll_min.lat, bounds->ll_min.lon,
1422               bounds->ll_max.lat, bounds->ll_max.lon);
1423    
1424        osm_bounds_free(bounds);
1425        osm->bounds = NULL;
1426        return FALSE;
1427      }
1428    
1429    
1430      /* calculate map zone which will be used as a reference for all */
1431      /* drawing/projection later on */
1432      pos_t center = { (bounds->ll_max.lat + bounds->ll_min.lat)/2,
1433                       (bounds->ll_max.lon + bounds->ll_min.lon)/2 };
1434    
1435      pos2lpos_center(&center, &bounds->center);
1436    
1437      /* the scale is needed to accomodate for "streching" */
1438      /* by the mercartor projection */
1439      bounds->scale = cos(DEG2RAD(center.lat));
1440    
1441      pos2lpos_center(&bounds->ll_min, &bounds->min);
1442      bounds->min.x -= bounds->center.x;
1443      bounds->min.y -= bounds->center.y;
1444      bounds->min.x *= bounds->scale;
1445      bounds->min.y *= bounds->scale;
1446    
1447      pos2lpos_center(&bounds->ll_max, &bounds->max);
1448      bounds->max.x -= bounds->center.x;
1449      bounds->max.y -= bounds->center.y;
1450      bounds->max.x *= bounds->scale;
1451      bounds->max.y *= bounds->scale;
1452    
1453      return TRUE;
1454    }
1455    
1456    static gboolean osm_tag_cb(qnd_xml_stack_t *stack,
1457                             qnd_xml_attribute_t *attributes, gpointer data) {
1458    
1459      tag_t *tag = *(tag_t**)stack->prev->userdata[1] = g_new0(tag_t, 1);
1460    
1461      tag->key = qnd_xml_get_prop_str(attributes, "k");
1462      tag->value = qnd_xml_get_prop_str(attributes, "v");
1463    
1464      if(!tag->key || !tag->value) {
1465        printf("incomplete tag key/value %s/%s\n", tag->key, tag->value);
1466        osm_tags_free(tag);
1467        tag = NULL;
1468      } else
1469        stack->prev->userdata[1] = &tag->next;
1470    
1471      return TRUE;
1472    }
1473    
1474    static gboolean osm_node_cb(qnd_xml_stack_t *stack,
1475                         qnd_xml_attribute_t *attributes, gpointer data) {
1476    
1477      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1478    
1479      /* allocate a new node structure. userdata[1] points to the current */
1480      /* position a new node is to be stored */
1481      node_t *node = *(node_t**)stack->prev->userdata[1] =
1482        stack->userdata[0] = g_new0(node_t, 1);
1483      stack->prev->userdata[1] = &node->next;
1484    
1485      qnd_xml_get_prop_gulong(attributes, "id", &node->id);
1486      qnd_xml_get_prop_double(attributes, "lat", &node->pos.lat);
1487      qnd_xml_get_prop_double(attributes, "lon", &node->pos.lon);
1488      node->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1489      node->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1490      node->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1491    
1492      pos2lpos(osm->bounds, &node->pos, &node->lpos);
1493    
1494      /* store current tag pointer in userdata for fast access to current tag */
1495      stack->userdata[1] = &node->tag;
1496    
1497      return TRUE;
1498    }
1499    
1500    static gboolean osm_way_nd_cb(qnd_xml_stack_t *stack,
1501                             qnd_xml_attribute_t *attributes, gpointer data) {
1502    
1503      osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1504    
1505      item_id_t id;
1506      if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1507        /* allocate a new node_chain structure */
1508        node_chain_t *node_chain = *(node_chain_t**)stack->prev->userdata[2] =
1509          g_new0(node_chain_t, 1);
1510    
1511        /* search matching node */
1512        node_chain->node = osm->node;
1513        while(node_chain->node && node_chain->node->id != id)
1514          node_chain->node = node_chain->node->next;
1515    
1516        if(!node_chain->node) printf("Node id %lu not found\n", id);
1517    
1518        if(node_chain->node)
1519          node_chain->node->ways++;
1520    
1521        stack->prev->userdata[2] = &node_chain->next;
1522      }
1523    
1524      return TRUE;
1525    }
1526    
1527    gboolean osm_way_cb(qnd_xml_stack_t *stack,
1528                        qnd_xml_attribute_t *attributes, gpointer data) {
1529    
1530      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1531    
1532      /* allocate a new way structure. userdata[2] points to the current */
1533      /* position a new way is to be stored in the way list */
1534      way_t *way = *(way_t**)stack->prev->userdata[2] =
1535        stack->userdata[0] = g_new0(way_t, 1);
1536      stack->prev->userdata[2] = &way->next;
1537    
1538      qnd_xml_get_prop_gulong(attributes, "id", &way->id);
1539      way->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1540      way->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1541      way->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1542    
1543      /* store current tag and node_chain pointers in userdata for fast */
1544      /* access to current tag/node_chain entry */
1545      stack->userdata[1] = &way->tag;
1546      stack->userdata[2] = &way->node_chain;
1547    
1548      return TRUE;
1549    }
1550    
1551    static gboolean osm_rel_member_cb(qnd_xml_stack_t *stack,
1552                             qnd_xml_attribute_t *attributes, gpointer data) {
1553    
1554      osm_t *osm = (osm_t*)stack->prev->prev->userdata[0];
1555    
1556      member_t *member = *(member_t**)stack->prev->userdata[2] =
1557        g_new0(member_t, 1);
1558      stack->prev->userdata[2] = &member->next;
1559      member->type = ILLEGAL;
1560    
1561      char *type = qnd_xml_get_prop(attributes, "type");
1562      if(type) {
1563        if(strcasecmp(type, "way") == 0)           member->type = WAY;
1564        else if(strcasecmp(type, "node") == 0)     member->type = NODE;
1565        else if(strcasecmp(type, "relation") == 0) member->type = RELATION;
1566      }
1567    
1568      item_id_t id;
1569      if(qnd_xml_get_prop_gulong(attributes, "ref", &id)) {
1570        switch(member->type) {
1571        case ILLEGAL:
1572          printf("Unable to store illegal type\n");
1573          break;
1574    
1575        case WAY:
1576          /* search matching way */
1577          member->way = osm->way;
1578          while(member->way && member->way->id != id)
1579            member->way = member->way->next;
1580    
1581          if(!member->way) {
1582            member->type = WAY_ID;
1583            member->id = id;
1584          }
1585          break;
1586    
1587        case NODE:
1588          /* search matching node */
1589          member->node = osm->node;
1590          while(member->node && member->node->id != id)
1591            member->node = member->node->next;
1592    
1593          if(!member->node) {
1594            member->type = NODE_ID;
1595            member->id = id;
1596          }
1597          break;
1598    
1599        case RELATION:
1600          /* search matching relation */
1601          member->relation = osm->relation;
1602          while(member->relation && member->relation->id != id)
1603            member->relation = member->relation->next;
1604    
1605          if(!member->relation) {
1606            member->type = NODE_ID;
1607            member->id = id;
1608          }
1609          break;
1610    
1611        case WAY_ID:
1612        case NODE_ID:
1613        case RELATION_ID:
1614          break;
1615        }
1616      }
1617    
1618      return TRUE;
1619    }
1620    
1621    gboolean osm_rel_cb(qnd_xml_stack_t *stack,
1622                        qnd_xml_attribute_t *attributes, gpointer data) {
1623    
1624      osm_t *osm = (osm_t*)stack->prev->userdata[0];
1625    
1626      /* allocate a new relation structure. userdata[3] points to the current */
1627      /* position a new relation is to be stored at in the relation list */
1628      relation_t *relation = *(relation_t**)stack->prev->userdata[3] =
1629        stack->userdata[0] = g_new0(relation_t, 1);
1630      stack->prev->userdata[3] = &relation->next;
1631    
1632      qnd_xml_get_prop_gulong(attributes, "id", &relation->id);
1633      relation->user = osm_user(osm, qnd_xml_get_prop(attributes, "user"));
1634      relation->visible = qnd_xml_get_prop_is(attributes, "visible", "true");
1635      relation->time = convert_iso8601(qnd_xml_get_prop(attributes, "timestamp"));
1636    
1637      /* store current tag and member pointers in userdata for fast access */
1638      /* to current tag and members in their chains */
1639      stack->userdata[1] = &relation->tag;
1640      stack->userdata[2] = &relation->member;
1641    
1642      return TRUE;
1643    }
1644    
1645    gboolean osm_cb(qnd_xml_stack_t *stack,
1646                    qnd_xml_attribute_t *attributes, gpointer data) {
1647    
1648      g_assert(!stack->userdata[0]);
1649    
1650      /* also set parents (roots) userdata as it's the parsers return value */
1651      osm_t *osm = stack->prev->userdata[0] =
1652        stack->userdata[0] = g_new0(osm_t, 1);
1653    
1654      /* store direct pointers for faster list access */
1655      /* (otherwise we'd have to search the end of the lists for every item */
1656      /* to be attached) */
1657      stack->userdata[1] = &osm->node;
1658      stack->userdata[2] = &osm->way;
1659      stack->userdata[3] = &osm->relation;
1660    
1661      return TRUE;
1662    }
1663    
1664    
1665    /* these structures describe the content qnd_xml expects while parsing */
1666    qnd_xml_entry_t osm_node_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1667    
1668    qnd_xml_entry_t osm_way_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1669    qnd_xml_entry_t osm_way_nd = { "nd", osm_way_nd_cb, QND_XML_LEAF };
1670    
1671    qnd_xml_entry_t osm_rel_tag = { "tag", osm_tag_cb, QND_XML_LEAF };
1672    qnd_xml_entry_t osm_rel_member = { "member", osm_rel_member_cb, QND_XML_LEAF };
1673    
1674    qnd_xml_entry_t osm_bounds = { "bounds", osm_bounds_cb, QND_XML_LEAF };
1675    
1676    qnd_xml_entry_t *node_children[] = { &osm_node_tag },
1677      osm_node = { "node", osm_node_cb, QND_XML_CHILDREN(node_children) };
1678    
1679    qnd_xml_entry_t *way_children[] = { &osm_way_tag, &osm_way_nd },
1680      osm_way = { "way", osm_way_cb, QND_XML_CHILDREN(way_children) };
1681    
1682    qnd_xml_entry_t *rel_children[] = { &osm_rel_tag, &osm_rel_member },
1683      osm_rel = { "rel", osm_rel_cb, QND_XML_CHILDREN(rel_children) };
1684    
1685    /* the osm element */
1686    qnd_xml_entry_t *osm_children[] = {
1687      &osm_bounds, &osm_node, &osm_way, &osm_rel };
1688    qnd_xml_entry_t osm = { "osm", osm_cb, QND_XML_CHILDREN(osm_children) };
1689    
1690    /* the root element */
1691    qnd_xml_entry_t *root_children[] = { &osm };
1692    qnd_xml_entry_t root = { "<root>", NULL, QND_XML_CHILDREN(root_children) };
1693    
1694    // gcc `pkg-config --cflags --libs glib-2.0` -o qnd_xml qnd_xml.c
1695    
1696    
1697    
1698    /* ----------------------- end of qnd-xml parser tests ------------------- */
1699    #endif
1700    
1701    
1702  #include <sys/time.h>  #include <sys/time.h>
1703    
1704  osm_t *osm_parse(char *filename) {  osm_t *osm_parse(char *filename) {
# Line 1392  osm_t *osm_parse(char *filename) { Line 1706  osm_t *osm_parse(char *filename) {
1706    struct timeval start;    struct timeval start;
1707    gettimeofday(&start, NULL);    gettimeofday(&start, NULL);
1708    
   LIBXML_TEST_VERSION;  
1709    
1710  #ifdef OSM_STREAM_PARSER  #ifdef OSM_STREAM_PARSER
1711      LIBXML_TEST_VERSION;
1712    
1713    // use stream parser    // use stream parser
1714    osm_t *osm = process_file(filename);    osm_t *osm = process_file(filename);
1715    xmlCleanupParser();    xmlCleanupParser();
1716    #endif
1717    
1718    #ifdef OSM_DOM_PARSER
1719      LIBXML_TEST_VERSION;
1720    
 #else  
1721    // parse into a tree    // parse into a tree
1722    /* parse the file and get the DOM */    /* parse the file and get the DOM */
1723    xmlDoc *doc = NULL;    xmlDoc *doc = NULL;
# Line 1412  osm_t *osm_parse(char *filename) { Line 1730  osm_t *osm_parse(char *filename) {
1730    osm_t *osm = osm_parse_doc(doc);    osm_t *osm = osm_parse_doc(doc);
1731  #endif  #endif
1732    
1733    #ifdef OSM_QND_XML_PARSER
1734      osm_t *osm = NULL;
1735      if(!(osm = qnd_xml_parse(filename, &root, NULL))) {
1736        errorf(NULL, "While parsing \"%s\"", filename);
1737        return NULL;
1738      }
1739    #endif
1740    
1741    struct timeval end;    struct timeval end;
1742    gettimeofday(&end, NULL);    gettimeofday(&end, NULL);
1743    

Legend:
Removed from v.35  
changed lines
  Added in v.39