* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
+
+/*
+ * Utility to read OSM planet XML file and store it in a sqlite3 database.
+ * Reads in all nodes (if used, skips nodes outside bounding box)
+ * Special POI nodes are stored in POI table.
+ * Place POI nodes are stored in place table.
+ *
+ * Ways are read in and their data (name, type, etc) are stored
+ * in way, way_name and way_ref tables.
+ *
+ * Nodes used by they ways are stored in way_n2n table.
+ *
+ * ...
+ *
+ */
+
#define _GNU_SOURCE
#include <stdio.h>
#include "osm.h"
#include "latlon.h"
-/* #define VERBOSE */
+#if 0
+#define VERBOSE
+#endif
/* #define VERBOSE_KEYS */
#define FILE_BUFFER 65535
node_data *data;
};
+/* Way data structure */
typedef struct _way_data way_data;
struct _way_data {
gchar *name;
GSList *nodes;
};
+/* XML tag IDs */
typedef enum {
START,
IN_OSM_TAG,
ERROR
} tag_state_t;
+/* Parent tag type */
typedef enum {
IS_NONE,
IS_NODE,
IS_WAY
} tag_parent_t;
+/* Node types table */
+/* XXX: Add support for parent category */
struct _nodeinfo {
gchar *k, *v;
node_type_t type;
} nodeinfo[] = {
{ "amenity", "fuel", NODE_AMENITY_FUEL },
+ { "amenity", "parking", NODE_AMENITY_PARKING },
+
{ "amenity", "pub", NODE_AMENITY_PUB },
{ "amenity", "biergarten", NODE_AMENITY_PUB },
{ "amenity", "cafe", NODE_AMENITY_CAFE },
- { "amenity", "telephone", NODE_AMENITY_TELEPHONE },
- { "amenity", "toilets", NODE_AMENITY_WC },
{ "amenity", "fast_food", NODE_AMENITY_FOOD },
{ "amenity", "restaurant", NODE_AMENITY_FOOD },
- { "amenity", "parking", NODE_AMENITY_PARKING },
+
+ { "amenity", "telephone", NODE_AMENITY_TELEPHONE },
+ { "amenity", "toilets", NODE_AMENITY_WC },
+
{ "amenity", "hospital", NODE_AMENITY_HOSPITAL },
{ "amenity", "doctors", NODE_AMENITY_HOSPITAL },
{ "amenity", "pharmacy", NODE_AMENITY_PHARMACY },
+
{ "amenity", "post_office", NODE_AMENITY_POST },
{ "amenity", "post_box", NODE_AMENITY_POST_BOX },
+
{ "amenity", "cinema", NODE_AMENITY_CINEMA },
{ "amenity", "theatre", NODE_AMENITY_THEATRE },
+
{ "amenity", "atm", NODE_AMENITY_ATM },
{ "amenity", "bank", NODE_AMENITY_BANK },
+
{ "amenity", "police", NODE_AMENITY_POLICE },
{ "amenity", "speed_trap", NODE_AMENITY_SPEEDCAM },
- { "amenity", "supermarket", NODE_AMENITY_SHOP },
- { "amenity", "shop", NODE_AMENITY_SHOP },
+ { "amenity", "speed_camera", NODE_AMENITY_SPEEDCAM },
+ { "amenity", "speed camera", NODE_AMENITY_SPEEDCAM },
+
{ "amenity", "place_of_worship",NODE_AMENITY_POW },
+
{ "amenity", "school", NODE_AMENITY_SCHOOL },
{ "amenity", "college", NODE_AMENITY_COLLEGE },
{ "amenity", "university", NODE_AMENITY_COLLEGE },
+ { "amenity", "library", NODE_AMENITY_LIBRARY },
+ { "amenity", "townhall", NODE_AMENITY_TOWNHALL },
+
+ { "amenity", "supermarket", NODE_AMENITY_SHOP },
+ { "amenity", "shopping_centre", NODE_AMENITY_SHOP },
+ { "amenity", "shop", NODE_AMENITY_SHOP },
+ { "amenity", "shops", NODE_AMENITY_SHOP },
+ { "amenity", "shopping", NODE_AMENITY_SHOP },
+ { "amenity", "shopping_mall",NODE_AMENITY_SHOP },
+ { "amenity", "cycle_shop", NODE_AMENITY_SHOP },
+ { "amenity", "bike_shop", NODE_AMENITY_SHOP },
+ { "amenity", "coffee_shop", NODE_AMENITY_SHOP },
+ { "amenity", "indoor_shopping_centre", NODE_AMENITY_SHOP },
+ { "amenity", "farm_shop", NODE_AMENITY_SHOP },
+ { "amenity", "tea_shop", NODE_AMENITY_SHOP },
+
+ /* Shops */
+ { "shop", "supermarket", NODE_AMENITY_SHOP },
+ { "shop", "bakery", NODE_AMENITY_SHOP },
+ { "shop", "alcohol", NODE_AMENITY_SHOP },
+ { "shop", "butcher", NODE_AMENITY_SHOP },
+ { "shop", "flowers", NODE_AMENITY_SHOP },
+ { "shop", "clothing", NODE_AMENITY_SHOP },
+ { "shop", "souvenir", NODE_AMENITY_SHOP },
+ { "shop", "bicycles", NODE_AMENITY_SHOP },
+ { "shop", "grocers", NODE_AMENITY_SHOP },
+ { "shop", "newsagents", NODE_AMENITY_SHOP },
+ { "shop", "convenience", NODE_AMENITY_SHOP },
+ { "shop", "bakers", NODE_AMENITY_SHOP },
+ { "shop", "garden_centre",NODE_AMENITY_SHOP },
+ { "shop", "photography", NODE_AMENITY_SHOP },
+ { "shop", "general_store",NODE_AMENITY_SHOP },
+ { "shop", "food", NODE_AMENITY_SHOP },
+ { "shop", "drinks", NODE_AMENITY_SHOP },
+ { "shop", "pharmacy", NODE_AMENITY_PHARMACY },
+
+ /* Sport */
{ "sport" , "swimming", NODE_SPORT_SWIMMING },
{ "sport" , "golf", NODE_SPORT_GOLF },
{ "sport" , "tennis", NODE_SPORT_TENNIS },
{ "sport" , "multi", NODE_SPORT_OTHER },
{ "leisure", "sport_centre",NODE_SPORT_CENTER },
+ /* Tourism */
{ "tourism", "information", NODE_TOURISM_INFO },
{ "tourism", "camp_site", NODE_TOURISM_CAMP_SITE },
{ "tourism", "caravan_site",NODE_TOURISM_CARAVAN_SITE },
{ "tourism", "motel", NODE_TOURISM_MOTEL },
{ "tourism", "hostel", NODE_TOURISM_HOSTEL },
{ "tourism", "attraction", NODE_TOURISM_ATTRACTION },
+ { "tourism", "zoo", NODE_TOURISM_ATTRACTION },
+
+ { "historic", "ruins", NODE_TOURISM_ATTRACTION },
+ { "historic", "monument", NODE_TOURISM_ATTRACTION },
+ { "historic", "memorial", NODE_TOURISM_ATTRACTION },
+ { "historic", "museum", NODE_HISTORIC_MUSEUM },
+ { "historic", "castle", NODE_HISTORIC_CASTLE },
{ "railway", "station", NODE_RAILWAY_STATION },
{ "railway", "halt", NODE_RAILWAY_HALT },
{ "aeroway", "terminal", NODE_AIRPORT_TERMINAL },
-
+
+ /* Places */
{ "place", "city", NODE_PLACE_CITY },
{ "place", "town", NODE_PLACE_TOWN },
{ "place", "village", NODE_PLACE_VILLAGE },
{ "highway", "secondary_link",60,WAY_SECONDARY, FALSE, TRUE, FALSE, TRUE, TRUE },
{ "highway", "tertiary",60,WAY_TERTIARY, FALSE, FALSE, FALSE, TRUE, TRUE },
{ "highway", "unclassified",50,WAY_UNCLASSIFIED, FALSE, FALSE, FALSE, TRUE, TRUE },
+ { "highway", "byway",40,WAY_UNCLASSIFIED, FALSE, FALSE, FALSE, TRUE, TRUE },
{ "highway", "residential",40,WAY_RESIDENTIAL, FALSE, FALSE, FALSE, TRUE, TRUE },
{ "highway", "service",20,WAY_SERVICE, FALSE, FALSE, FALSE, TRUE, TRUE },
{ "highway", "track",20,WAY_TRACK, FALSE, FALSE, FALSE, TRUE, TRUE },
{ "highway", "unsurfaced",60,WAY_TRACK, FALSE, FALSE, FALSE, TRUE, TRUE },
+ { "highway", "minor",60,WAY_TRACK, FALSE, FALSE, FALSE, TRUE, TRUE },
{ "highway", "pedestrian",20,WAY_FOOTWAY, FALSE, FALSE, FALSE, FALSE, TRUE },
{ "highway", "footway",1,WAY_FOOTWAY, FALSE, FALSE, FALSE, FALSE, TRUE },
{ "highway", "steps",0,WAY_FOOTWAY, FALSE, FALSE, FALSE, FALSE, TRUE},
{ "waterway", "river",0,WAY_WATER, FALSE, FALSE, FALSE, FALSE, FALSE },
{ "waterway", "canal",0,WAY_WATER, FALSE, FALSE, FALSE, FALSE, FALSE },
{ "waterway", "stream",0,WAY_WATER, FALSE, FALSE, FALSE, FALSE, FALSE },
- { "building", "",0,WAY_UNWAYED, FALSE, FALSE, TRUE, FALSE, FALSE },
+ { "building", "*",0,WAY_UNWAYED, FALSE, FALSE, TRUE, FALSE, FALSE },
{ NULL, NULL, 0, WAY_UNWAYED, FALSE, FALSE, FALSE, FALSE, FALSE }
};
{
#ifdef VERBOSE
g_assert(w);
-g_printf("Way #%d(N:%d T:%d S:%d): %s [%s:%s:%s]\n",
+g_printf("Way #%d(N:%d T:%d S:%d IS: %d): %s [%s:%s:%s]\n",
w->id,
g_slist_length(w->nodes),
w->type,
w->data ? w->data->speed : 0,
+ w->data ? w->data->isin : 0,
w->data ? w->data->name ? w->data->name : "" : "",
w->flags & W_ONEWAY ? "-" : "=",
w->flags & W_ROUNDABOUT ? "O" : "-",
{
#ifdef VERBOSE
g_assert(n);
-g_printf("Node #%d: T:%d [%s]\n",
+g_printf("Node #%d: T:%d IS: %d [%s]\n",
n->id,
n->type,
+ n->data ? n->data->isin : 0,
n->data ? n->data->name : "");
#endif
}
db_insert_way(way *w)
{
GSList *iter;
-guint32 isin=0;
if (!w)
return FALSE;
db_insert_way_n2n(w, iter->data, iter->next->data);
}
-print_way(w);
-
if (w->id==0)
return FALSE;
-/* isin=osm_find_way_place(w); */
+if (w->data)
+ w->data->isin=osm_find_way_place(w);
+
+print_way(w);
sqlite3_bind_int(sql.insert_way_data, 1, w->id);
sqlite3_bind_int(sql.insert_way_data, 2, w->ncnt);
sqlite3_bind_int(sql.insert_way_data, 4, w->flags);
if (w->data) {
sqlite3_bind_int(sql.insert_way_data, 5, w->data->speed);
+ sqlite3_bind_int(sql.insert_way_data, 6, w->data->isin);
}
-sqlite3_bind_int(sql.insert_way_data, 6, isin);
sqlite3_step(sql.insert_way_data);
sqlite3_reset(sql.insert_way_data);
case NODE_PLACE_VILLAGE:
case NODE_PLACE_HAMLET:
t=g_hash_table_lookup(osm_place_region, ps);
- if (t) {
+ if (t)
return t->id;
- }
t=g_hash_table_lookup(osm_place_country, ps);
- if (t) {
+ if (t)
return t->id;
- }
break;
case NODE_PLACE_SUBURB:
t=g_hash_table_lookup(osm_place_city, ps);
- if (t) {
+ if (t)
return t->id;
- }
break;
case NODE_PLACE_ISLAND:
- default:
return 0;
break;
+ default:
+ t=g_hash_table_lookup(osm_place_city, ps);
+ if (t)
+ return t->id;
+ break;
}
place++;
}
guint32
osm_find_way_place(way *w)
{
-way *t;
gchar **isin;
gchar **place;
place=isin;
while (*place!=NULL) {
+ node *t;
gchar *ps;
+
ps=g_strstrip(*place);
+#ifdef VERBOSE
+ g_printf("Checking (%d) in [%s]\n",w->id, ps);
+#endif
+
t=g_hash_table_lookup(osm_place_city, ps);
- if (t) {
- print_way(t);
+ if (t)
return t->id;
- }
+ place++;
}
return 0;
}
/* Free the extra info, we don't need it anymore */
+#if 0
osm_free_node_data(n);
+#endif
return TRUE;
}
nlat=atof(get_attr_key_value(atts, "lat"));
nlon=atof(get_attr_key_value(atts, "lon"));
+ /* Check if node is used */
if (osm_node_check_box(nlat, nlon)==TRUE) {
cnode=osm_new_node(id, nlat, nlon);
osm_node_tags=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
osm_way_new_node(cway, ndref);
break;
case IN_KEY_TAG:
+ k=get_attr_key_value(atts, "k");
+ if (strcmp(k,"created_by")==0)
+ return;
+ if (strcmp(k,"source")==0)
+ return;
+
+ v=get_attr_key_value(atts, "v");
+#ifdef VERBOSE_KEYS
+ g_printf("TAG: K=[%s] V=[%s]\n", k, v);
+#endif
+
switch (tag_parent) {
case IS_NONE:
g_printf("Tag key/value pair but unknown owner\n");
return;
/* Insert key/value pairs into hash table */
- k=get_attr_key_value(atts, "k");
- if (strcmp(k,"created_by")==0)
- return;
- if (strcmp(k,"source")==0)
- return;
- v=get_attr_key_value(atts, "v");
-
-#ifdef VERBOSE_KEYS
- g_printf("NODE: K=[%s] V=[%s]\n", k, v);
-#endif
-
if (cnode==NULL) {
- g_printf("In node tags but current node is NULL\n");
+ g_printerr("In node tags but node is NULL!\n");
return;
}
g_hash_table_insert(osm_node_tags, g_strdup(k), g_strdup(v));
{
gint i;
- k=get_attr_key_value(atts, "k");
- if (strcmp(k,"created_by")==0)
- return;
- if (strcmp(k,"source")==0)
+ if (cway==NULL) {
+ g_printerr("In way tags but way is NULL!\n");
return;
- v=get_attr_key_value(atts, "v");
-
-#ifdef VERBOSE_KEYS
- g_printf("WAY: K=[%s] V=[%s]\n", k, v);
-#endif
-
- osm_new_way_data(cway);
- g_hash_table_insert(osm_way_tags, g_strdup(k), g_strdup(v));
-
- /* XXX: something faster than this should be used */
- if (strcasecmp(k, "name")==0)
- cway->data->name=g_strdup(v);
- else if (strcasecmp(k, "ref")==0)
- cway->data->ref=g_strdup(v);
- else if (strcasecmp(k, "int_ref")==0)
- cway->data->int_ref=g_strdup(v);
- else if (strcasecmp(k, "oneway")==0)
- cway->flags|=W_ONEWAY;
- else if (strcasecmp(k, "noexit")==0)
- cway->flags|=W_NOEXIT;
- else if (strcasecmp(k, "layer")==0)
- cway->data->layer=atoi(v);
- else if (strcasecmp(k, "speedlimit")==0)
- cway->data->speed=atoi(v);
- else if (strcasecmp(k, "maxspeed")==0)
- cway->data->speed=atoi(v);
- else if ((strcasecmp(k, "junction")==0) && (strcasecmp(v, "roundabout")==0)) {
- cway->flags|=W_ROUNDABOUT;
- cway->flags|=W_ONEWAY;
- } else if ((strcasecmp(k, "access")==0) && (strcasecmp(v, "private")==0)) {
- cway->flags|=W_NOACCESS;
- } else if ((strcasecmp(k, "junction")==0) && (strcasecmp(v, "mini_roundabout")==0)) {
- /* Just in case */
- cway->flags|=W_ROUNDABOUT;
- cway->flags|=W_ONEWAY;
- } else if (cway->type==WAY_UNWAYED) {
- for (i=0; wayinfo[i].k; i++) {
- if (strcasecmp (wayinfo[i].k, k)==0 && strcasecmp (v, wayinfo[i].v)==0) {
- if (wayinfo[i].link==TRUE)
- cway->flags|=W_LINK;
- if (wayinfo[i].area==TRUE)
- cway->flags|=W_AREA;
- if (wayinfo[i].oneway==TRUE)
- cway->flags|=W_ONEWAY;
- cway->type=wayinfo[i].type;
- if (cway->data->speed==0)
- cway->data->speed=wayinfo[i].defspeed;
- break;
- }
- }
- } else {
-#ifdef VERBOSE_UNHANDLED_WAY_TAGS
- g_printf("Unhandled tag: [%s == %s]\n", k, v);
-#endif
}
+ g_hash_table_insert(osm_way_tags, g_strdup(k), g_strdup(v));
+ osm_new_way_data(cway);
}
break;
}
cnode->data->name=NULL;
v=g_hash_table_lookup(osm_node_tags, "name");
if (v)
- cnode->data->name=g_strdup(v);
+ cnode->data->name=g_strstrip(g_strdup(v));
}
cnode->data->isin=0;
if (cnode->data->name) {
switch (cnode->type) {
case NODE_PLACE_COUNTRY:
+ g_printf("Country: [%s] (%d)\n", cnode->data->name, cnode->id);
g_hash_table_insert(osm_place_country, cnode->data->name, cnode);
break;
case NODE_PLACE_CITY:
case NODE_PLACE_TOWN:
+ g_printf("City: [%s] (%d)\n", cnode->data->name, cnode->id);
g_hash_table_insert(osm_place_city, cnode->data->name, cnode);
break;
case NODE_PLACE_SUBURB:
cnode=NULL;
break;
case IN_WAY_TAG:
+ if (way_cnt % 1024==0) {
+ g_printf("Ways: %d\n", way_cnt);
+ }
+
cway->nodes=g_slist_reverse(cway->nodes);
- print_way(cway);
+ for (i=0; wayinfo[i].k; i++) {
+ v=g_hash_table_lookup(osm_way_tags, wayinfo[i].k);
+ if (!v)
+ continue;
+ if (strcasecmp (v, wayinfo[i].v)==0) {
+ if (wayinfo[i].link==TRUE)
+ cway->flags|=W_LINK;
+ if (wayinfo[i].area==TRUE)
+ cway->flags|=W_AREA;
+ if (wayinfo[i].oneway==TRUE)
+ cway->flags|=W_ONEWAY;
+ cway->type=wayinfo[i].type;
+ if (cway->data->speed==0)
+ cway->data->speed=wayinfo[i].defspeed;
+ break;
+ }
+ }
+
+ v=g_hash_table_lookup(osm_way_tags, "name");
+ if (v)
+ cway->data->name=g_strdup(v);
+
+ v=g_hash_table_lookup(osm_way_tags, "ref");
+ if (v)
+ cway->data->ref=g_strdup(v);
+ v=g_hash_table_lookup(osm_way_tags, "int_ref");
+ if (v)
+ cway->data->int_ref=g_strdup(v);
+
+ v=g_hash_table_lookup(osm_way_tags, "oneway");
+ if (v)
+ cway->flags|=W_ONEWAY;
+ v=g_hash_table_lookup(osm_way_tags, "noexit");
+ if (v)
+ cway->flags|=W_NOEXIT;
+
+ v=g_hash_table_lookup(osm_way_tags, "speedlimit");
+ if (v)
+ cway->data->speed=atoi(v);
+ v=g_hash_table_lookup(osm_way_tags, "maxspeed");
+ if (v)
+ cway->data->speed=atoi(v);
#if 0
- v=g_hash_table_lookup(osm_node_tags, "is_in");
+ v=g_hash_table_lookup(osm_way_tags, "layer");
+ if (v)
+ cway->data->layer=atoi(v);
+#endif
+
+ v=g_hash_table_lookup(osm_way_tags, "junction");
+ if (v && strcasecmp(v,"roundabout")==0) {
+ cway->flags|=W_ROUNDABOUT;
+ cway->flags|=W_ONEWAY;
+ } else if (v && strcasecmp(v,"mini_roundabout")==0) {
+ cway->flags|=W_ROUNDABOUT;
+ cway->flags|=W_ONEWAY;
+ }
+ v=g_hash_table_lookup(osm_way_tags, "access");
+ if (v && (strcasecmp(v, "private")==0)) {
+ cway->flags|=W_NOACCESS;
+ }
+
+ print_way(cway);
+
+ v=g_hash_table_lookup(osm_way_tags, "is_in");
if (v) {
gchar **isin;
isin=g_strsplit(v, ",", 10);
- g_hash_table_insert(osm_node_isin, GINT_TO_POINTER(cnode->id), isin);
+ g_hash_table_insert(osm_way_isin, GINT_TO_POINTER(cway->id), isin);
}
-#endif
- /* XXX */
if (cway->data && cway->data->name==NULL && cway->data->ref==NULL &&
cway->data->int_ref==NULL && cway->data->layer==0 && cway->data->speed==0)
osm_free_way_data(cway);
if (cway->id!=0)
osm_way_add_to_list(cway);
- else
- way_cnt--;
-
- if (way_cnt % 32767==0) {
- g_printf("Ways: %d\n", way_cnt);
- }
cway=NULL;
g_hash_table_destroy(osm_way_tags);