]> err.no Git - mapper/blob - src/osm-db-import.c
Print progress properly
[mapper] / src / osm-db-import.c
1 /*
2  * This file is part of mapper
3  *
4  * Copyright (C) 2007 Kaj-Michael Lang
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program; if not, write to the Free Software Foundation, Inc.,
18  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
19  */
20
21 /*
22  * Routines to read OSM planet XML file and store it in a sqlite3 database.
23  * Reads in all nodes (if used, skips nodes outside bounding box)
24  * Special POI nodes are stored in POI table.
25  * Place POI nodes are stored in place table.
26  *
27  * Ways are read in and their data (name, type, etc) are stored 
28  * in way, way_name and way_ref tables.
29  * 
30  * Nodes used by they ways are stored in way_n2n table.
31  *
32  */
33
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <string.h>
37 #include <strings.h>
38 #include <sys/types.h>
39 #include <sys/stat.h>
40 #include <fcntl.h>
41 #include <math.h>
42 #include <glib.h>
43 #include <glib/gstdio.h>
44 #include <sqlite3.h>
45 #include <expat.h>
46 #include <bzlib.h>
47
48 #include "osm.h"
49 #include "latlon.h"
50 #include "db.h"
51 #include "osm-db-import.h"
52
53 #if 0
54 #define VERBOSE
55 #endif
56 /* #define VERBOSE_KEYS */
57
58
59 /* Use g_convert to transliterate names.. my iconv seems to be fucked so this didn't work... */
60 /* #define TRANSLIT_NAMES */
61
62 #define FILE_BUFFER (128*1024)
63
64 static guint node_cnt=0;                /* Nodes */
65 static guint node_skip_cnt=0;   /* Skipped nodes */
66 static guint noded_cnt=0;               /* Nodes with (usable) data */
67 static guint way_cnt=0;                 /* Ways */
68 static guint way_names=0;               /* Ways with name */
69 static guint way_refs=0;                /* Ways with ref or int_ref */
70
71 static guint dbnode_cnt=0;
72 static guint dbnoded_cnt=0;
73 static guint dbway_cnt=0;
74
75 /* For threaded importing */
76 static GThread* import_thread=NULL;
77 static GSourceFunc osm_import_progress_cb=NULL;
78 static osm_import_data_req osm_import_req;
79 static guint import_sid=0;
80
81 static gboolean is_update=FALSE;
82 static XML_Parser xp;
83
84
85 /* XML tag IDs */
86 typedef enum {
87         START,
88         IN_OSM_TAG,
89         IN_NODE_TAG,
90         IN_WNODE_TAG,
91         IN_WAY_TAG,
92         IN_KEY_TAG,
93         IN_BOUND_TAG,
94         IN_RELATION_TAG,
95         IN_MEMBER_TAG,
96         END,
97         ERROR
98 } tag_state_t;
99
100 /* Parent tag type */
101 typedef enum {
102         IS_NONE,
103         IS_NODE,
104         IS_WAY,
105         IS_RELATION
106 } tag_parent_t;
107
108 /* Node types table */
109 /* XXX: Add support for parent category */
110 struct _nodeinfo {
111         gchar *k, *v;
112         node_type_t type;
113 } nodeinfo[] = {
114         { "amenity", "fuel",            NODE_AMENITY_FUEL },
115         { "amenity", "parking",         NODE_AMENITY_PARKING },
116
117         { "amenity", "pub",                     NODE_AMENITY_PUB },
118         { "amenity", "nightclub",       NODE_AMENITY_NIGHTCLUB },
119         { "amenity", "biergarten",      NODE_AMENITY_PUB },
120         { "amenity", "cafe",            NODE_AMENITY_CAFE },
121         { "amenity", "fast_food",       NODE_AMENITY_FOOD },
122         { "amenity", "restaurant",      NODE_AMENITY_RESTAURANT },
123
124         { "amenity", "telephone",       NODE_AMENITY_TELEPHONE },
125         { "amenity", "toilets",         NODE_AMENITY_WC },
126
127         { "amenity", "hospital",        NODE_AMENITY_HOSPITAL },
128         { "amenity", "doctors",         NODE_AMENITY_HOSPITAL },
129         { "amenity", "pharmacy",        NODE_AMENITY_PHARMACY },
130
131         { "amenity", "post_office",     NODE_AMENITY_POST },
132         { "amenity", "post_box",        NODE_AMENITY_POST_BOX },
133
134         { "amenity", "cinema",          NODE_AMENITY_CINEMA },
135         { "amenity", "theatre",         NODE_AMENITY_THEATRE },
136
137         { "amenity", "atm",                     NODE_AMENITY_ATM },
138         { "amenity", "bank",            NODE_AMENITY_BANK },
139
140         { "amenity", "police",          NODE_AMENITY_POLICE },
141         { "amenity", "speed_trap",      NODE_AMENITY_SPEEDCAM },
142         { "amenity", "speed_camera",    NODE_AMENITY_SPEEDCAM },
143         { "amenity", "speed camera",    NODE_AMENITY_SPEEDCAM },
144
145         { "amenity", "place_of_worship",NODE_AMENITY_POW },
146
147         { "amenity", "school",          NODE_AMENITY_SCHOOL },
148         { "amenity", "college",         NODE_AMENITY_COLLEGE },
149         { "amenity", "university",      NODE_AMENITY_COLLEGE },
150
151         { "amenity", "library", NODE_AMENITY_LIBRARY },
152         { "amenity", "townhall",        NODE_AMENITY_TOWNHALL },
153
154         { "amenity", "supermarket",     NODE_AMENITY_SHOP },
155         { "amenity", "shopping_centre", NODE_AMENITY_SHOP },
156         { "amenity", "shop",            NODE_AMENITY_SHOP },
157         { "amenity", "shops",           NODE_AMENITY_SHOP },
158         { "amenity", "shopping",        NODE_AMENITY_SHOP },
159         { "amenity", "shopping_mall",NODE_AMENITY_SHOP },
160         { "amenity", "cycle_shop",      NODE_AMENITY_SHOP },
161         { "amenity", "bike_shop",       NODE_AMENITY_SHOP },
162         { "amenity", "coffee_shop",     NODE_AMENITY_SHOP },
163         { "amenity", "indoor_shopping_centre",  NODE_AMENITY_SHOP },
164         { "amenity", "farm_shop",       NODE_AMENITY_SHOP },
165         { "amenity", "tea_shop",        NODE_AMENITY_SHOP },
166
167         /* Shops */
168         { "shop",        "supermarket", NODE_AMENITY_SHOP },
169         { "shop",        "bakery",              NODE_AMENITY_SHOP },
170         { "shop",        "alcohol",             NODE_AMENITY_SHOP }, 
171         { "shop",        "butcher",             NODE_AMENITY_SHOP },
172         { "shop",        "flowers",             NODE_AMENITY_SHOP },
173         { "shop",        "clothing",    NODE_AMENITY_SHOP },
174         { "shop",        "souvenir",    NODE_AMENITY_SHOP },
175         { "shop",        "bicycles",    NODE_AMENITY_SHOP },
176         { "shop",        "grocers",             NODE_AMENITY_SHOP },
177         { "shop",        "newsagents",  NODE_AMENITY_SHOP },
178         { "shop",        "convenience", NODE_AMENITY_SHOP },
179         { "shop",        "bakers",              NODE_AMENITY_SHOP },
180         { "shop",        "garden_centre",NODE_AMENITY_SHOP },
181         { "shop",        "photography", NODE_AMENITY_SHOP },
182         { "shop",        "general_store",NODE_AMENITY_SHOP },
183         { "shop",        "food",                NODE_AMENITY_SHOP },
184         { "shop",        "drinks",              NODE_AMENITY_SHOP },
185         { "shop",        "sex",                 NODE_AMENITY_SHOP_ADULT },
186         { "shop",        "pharmacy",    NODE_AMENITY_PHARMACY },
187
188         /* Sport */
189         { "sport"  , "swimming",        NODE_SPORT_SWIMMING },
190         { "sport"  , "golf",            NODE_SPORT_GOLF },
191         { "sport"  , "tennis",          NODE_SPORT_TENNIS },
192         { "sport"  , "football",        NODE_SPORT_FOOTBALL },
193         { "sport"  , "soccer",          NODE_SPORT_SOCCER },
194         { "sport"  , "baskteball",      NODE_SPORT_BASKETBALL },
195         { "sport"  , "rugby",           NODE_SPORT_RUGBY },
196         { "sport"  , "skating",         NODE_SPORT_SKATING },
197         { "sport"  , "hockey",          NODE_SPORT_HOCKEY },
198         { "sport"  , "skateboard",      NODE_SPORT_SKATEBOARD },
199         { "sport"  , "bowling",         NODE_SPORT_BOWLING },
200         { "sport"  , "10pin",           NODE_SPORT_BOWLING },
201         { "sport"  , "motor",           NODE_SPORT_MOTOR },
202         { "sport"  , "shooting_range",NODE_SPORT_SHOOTING },
203         { "sport"  , "paintball",       NODE_SPORT_PAINTBALL },
204         { "sport"  , "horse_racing",NODE_SPORT_HORSES },
205         { "sport"  , "horse",           NODE_SPORT_HORSES },
206         { "sport"  , "horses",          NODE_SPORT_HORSES },
207         { "sport"  , "dog_racing",      NODE_SPORT_DOG },
208         { "sport"  , "pelota",          NODE_SPORT_PELOTA },
209         { "sport"  , "racquet",         NODE_SPORT_RACQUET },
210         { "sport"  , "equestrian",      NODE_SPORT_HORSES },
211         { "sport"  , "baseball",        NODE_SPORT_BASEBALL },
212         { "sport"  , "cricket",         NODE_SPORT_CRICKET },
213         { "sport"  , "croquet",         NODE_SPORT_CROQUET },
214         { "sport"  , "cycling",         NODE_SPORT_CYCLING },
215         { "sport"  , "bowls",           NODE_SPORT_BOWLS },
216         { "sport"  , "athletics",       NODE_SPORT_ATHLETICS },
217         { "sport"  , "gymnastics",      NODE_SPORT_GYMNASTICS },
218         { "sport"  , "multi",           NODE_SPORT_OTHER },
219         { "leisure", "sport_centre",NODE_SPORT_CENTER },
220
221         /* Tourism */
222         { "tourism", "information",     NODE_TOURISM_INFO },
223         { "tourism", "camp_site",       NODE_TOURISM_CAMP_SITE },
224         { "tourism", "caravan_site",NODE_TOURISM_CARAVAN_SITE },
225         { "tourism", "picnic_site",     NODE_TOURISM_PICNIC_SITE },
226         { "tourism", "theme_park",      NODE_TOURISM_THEME_PARK },
227         { "tourism", "hotel",           NODE_TOURISM_HOTEL },
228         { "tourism", "motel",           NODE_TOURISM_MOTEL },
229         { "tourism", "hostel",          NODE_TOURISM_HOSTEL },
230         { "tourism", "attraction",      NODE_TOURISM_ATTRACTION },
231         { "tourism", "zoo",                     NODE_TOURISM_ATTRACTION },
232
233         { "historic", "ruins",          NODE_TOURISM_ATTRACTION },
234         { "historic", "monument",       NODE_TOURISM_ATTRACTION },
235         { "historic", "memorial",       NODE_TOURISM_ATTRACTION },
236         { "historic", "museum",         NODE_HISTORIC_MUSEUM },
237         { "historic", "castle",         NODE_HISTORIC_CASTLE },
238
239         { "railway", "station",         NODE_RAILWAY_STATION },
240         { "railway", "halt",            NODE_RAILWAY_HALT },
241
242         { "aeroway", "terminal",        NODE_AIRPORT_TERMINAL },
243
244         /* Places */    
245         { "place", "city",                      NODE_PLACE_CITY },
246         { "place", "town",                      NODE_PLACE_TOWN },
247         { "place", "village",           NODE_PLACE_VILLAGE },
248         { "place", "hamlet",            NODE_PLACE_HAMLET },
249         { "place", "locality",          NODE_PLACE_LOCALITY },
250         { "place", "suburb",            NODE_PLACE_SUBURB },
251         { "place", "island",            NODE_PLACE_ISLAND },
252
253         { "highway", "traffic_signals", NODE_TRAFFIC_SIGNALS },
254         { "highway", "motorway_junction",       NODE_JUNCTION },
255         { "highway", "services",        NODE_AMENITY_PARKING },
256         { "highway", "toll_booth",      NODE_TOLLBOOTH },
257         { "highway", "gate",            NODE_GATE },
258
259         { NULL, NULL, NODE_PLAIN }
260 };
261
262 /* Array to get id number and defaults for ways of different types */
263 struct _wayinfo {
264         gchar *k, *v;
265         guint defspeed;
266         way_type_t type;
267         gboolean oneway, link, area, car, foot;
268 } wayinfo[] = {
269         { "highway", "motorway",120,WAY_MOTORWAY,               TRUE, FALSE, FALSE, TRUE, FALSE },
270         { "highway", "motorway_link",120,WAY_MOTORWAY,  TRUE, TRUE, FALSE, TRUE, FALSE },
271         { "highway", "trunk",100,WAY_TRUNK,                             FALSE, FALSE, FALSE, TRUE, FALSE },
272         { "highway", "trunk_link",100,WAY_TRUNK,                FALSE, TRUE, FALSE, TRUE, FALSE },
273         { "highway", "primary",80,WAY_PRIMARY,                  FALSE, FALSE, FALSE, TRUE, TRUE },
274         { "highway", "primary_link",60,WAY_PRIMARY,             FALSE, TRUE, FALSE, TRUE, TRUE },
275         { "highway", "secondary",80,WAY_SECONDARY,              FALSE, FALSE, FALSE, TRUE, TRUE },
276         { "highway", "secondary_link",60,WAY_SECONDARY, FALSE, TRUE, FALSE, TRUE, TRUE },
277         { "highway", "tertiary",60,WAY_TERTIARY,                FALSE, FALSE, FALSE, TRUE, TRUE },
278         { "highway", "unclassified",50,WAY_UNCLASSIFIED,        FALSE, FALSE, FALSE, TRUE, TRUE },
279         { "highway", "byway",40,WAY_UNCLASSIFIED,       FALSE, FALSE, FALSE, TRUE, TRUE },
280         { "highway", "residential",40,WAY_RESIDENTIAL,  FALSE, FALSE, FALSE, TRUE, TRUE },
281         { "highway", "service",20,WAY_SERVICE,                  FALSE, FALSE, FALSE, TRUE, TRUE },
282         { "highway", "track",20,WAY_TRACK,                              FALSE, FALSE, FALSE, TRUE, TRUE },
283         { "highway", "unsurfaced",60,WAY_TRACK,                 FALSE, FALSE, FALSE, TRUE, TRUE },
284         { "highway", "minor",60,WAY_TRACK,                      FALSE, FALSE, FALSE, TRUE, TRUE },
285         { "highway", "pedestrian",20,WAY_FOOTWAY,               FALSE, FALSE, FALSE, FALSE, TRUE },
286         { "highway", "footway",1,WAY_FOOTWAY,                   FALSE, FALSE, FALSE, FALSE, TRUE },
287         { "highway", "steps",0,WAY_FOOTWAY,                             FALSE, FALSE, FALSE, FALSE, TRUE},
288         { "highway", "bridleway",10,WAY_FOOTWAY,                FALSE, FALSE, FALSE, FALSE, TRUE },
289         { "highway", "cycleway",10,WAY_CYCLEWAY,                FALSE, FALSE, FALSE, FALSE, TRUE },
290         { "railway", "rail",0,WAY_RAIL,                                 FALSE, FALSE, FALSE, FALSE, FALSE },
291         { "aeroway", "runway",0,WAY_RUNWAY,                             FALSE, FALSE, FALSE, FALSE, FALSE },
292         { "aeroway", "taxiway",0,WAY_TAXIWAY,                   FALSE, FALSE, FALSE, FALSE, FALSE },
293         { "natural", "water",0,WAY_WATER,                               FALSE, FALSE, TRUE, FALSE, FALSE },
294         { "waterway", "river",0,WAY_WATER,                              FALSE, FALSE, FALSE, FALSE, FALSE },
295         { "waterway", "canal",0,WAY_WATER,                              FALSE, FALSE, FALSE, FALSE, FALSE },
296         { "waterway", "stream",0,WAY_WATER,                             FALSE, FALSE, FALSE, FALSE, FALSE },
297         { "building", "*",0,WAY_UNWAYED,                                FALSE, FALSE, TRUE, FALSE, FALSE },
298         { NULL, NULL, 0, WAY_UNWAYED, FALSE, FALSE, FALSE, FALSE, FALSE }
299 };
300
301 static sqlite3 *db;
302 tag_parent_t tag_parent=IS_NONE;
303
304 static GHashTable *osm_nodes;
305 static GHashTable *osm_node_tags;
306 static GHashTable *osm_way_tags;
307 static GSList *osm_ways;
308 static GSList *osm_poi;
309
310 static GHashTable *osm_place_country;
311 static GHashTable *osm_place_region;
312 static GHashTable *osm_place_city;
313 static GHashTable *osm_place_suburb;
314 static GHashTable *osm_place_village;
315 static GHashTable *osm_node_isin;
316 static GHashTable *osm_way_isin;
317
318 static node *cnode=NULL;
319 static way *cway=NULL;
320
321 struct sql_stmt {
322         sqlite3_stmt *insert_poi;
323         sqlite3_stmt *delete_osm_poi;
324
325         sqlite3_stmt *insert_node;
326         sqlite3_stmt *delete_nodes;
327         sqlite3_stmt *select_node;
328         sqlite3_stmt *update_node;
329
330         sqlite3_stmt *insert_way_data;
331         sqlite3_stmt *insert_way_ref;
332         sqlite3_stmt *insert_way_pc;
333         sqlite3_stmt *insert_way_name;
334         sqlite3_stmt *insert_way_names_nls;
335         sqlite3_stmt *insert_way_n2n;
336         sqlite3_stmt *delete_way;
337         sqlite3_stmt *delete_way_n2n;
338         sqlite3_stmt *delete_way_name;
339         sqlite3_stmt *delete_way_names_nls;
340         sqlite3_stmt *delete_way_ref;
341         sqlite3_stmt *delete_way_pc;
342
343         sqlite3_stmt *insert_place;
344         sqlite3_stmt *delete_place;
345 };
346 static struct sql_stmt sql;
347
348
349 static struct map_bbox bbox;
350 static gboolean use_bbox;
351
352 static void osm_free_way_data(way *w);
353 static void print_way(way *w);
354
355 static gboolean osm_db_prepare(sqlite3 *db);
356 static gboolean db_insert_node(node *n);
357 static guint32 osm_find_way_place(way *w, node_type_t nt);
358
359 /****************************************************/
360 /* Functions */
361 /****************************************************/
362
363 static void
364 db_finalize(void)
365 {
366 sqlite3_finalize(sql.insert_poi);
367 sqlite3_finalize(sql.delete_osm_poi);
368
369 sqlite3_finalize(sql.insert_node);
370 sqlite3_finalize(sql.select_node);
371 sqlite3_finalize(sql.delete_nodes);
372 sqlite3_finalize(sql.update_node);
373
374 sqlite3_finalize(sql.insert_place);
375 sqlite3_finalize(sql.delete_place);
376
377 sqlite3_finalize(sql.delete_way);
378 sqlite3_finalize(sql.insert_way_data);
379
380 sqlite3_finalize(sql.delete_way_name);
381 sqlite3_finalize(sql.insert_way_name);
382
383 sqlite3_finalize(sql.delete_way_n2n);
384 sqlite3_finalize(sql.insert_way_n2n);
385
386 sqlite3_finalize(sql.delete_way_pc);
387 sqlite3_finalize(sql.insert_way_pc);
388
389 sqlite3_finalize(sql.delete_way_names_nls);
390 sqlite3_finalize(sql.insert_way_names_nls);
391 }
392
393 static gboolean
394 osm_db_prepare(sqlite3 *db)
395 {
396 /* Way nodes */
397 sqlite3_prepare_v2(db, "insert or replace into nodes (nid,ilat,ilon,rlat,rlon,l,f) values (?,?,?,?,?,0,?)", -1, &sql.insert_node, NULL);
398 sqlite3_prepare_v2(db, "select ilat,ilon,l from nodes where nid=?", -1, &sql.select_node, NULL);
399 sqlite3_prepare_v2(db, "delete from nodes", -1, &sql.delete_nodes, NULL);
400 sqlite3_prepare_v2(db, "update nodes set l=l+1 where nid=?", -1, &sql.update_node, NULL);
401
402 /* Places */
403 sqlite3_prepare_v2(db, "insert or replace into places (nid,type,name,isin_c,isin_p) values (?, ?, ?, ?, ?)", -1, &sql.insert_place, NULL);
404 sqlite3_prepare_v2(db, "delete from places", -1, &sql.delete_place, NULL);
405
406 /* POI nodes */
407 if (sqlite3_prepare_v2(db, "insert or replace into poi (osm_id, lat, lon, label, cat_id, public, source, priority, isin_c, isin_p, desc, url, postal_code) "
408                                            " values (?, ?, ?, ?, ?, 1, 1, ?, ?, ?, ?, ?, ?)", -1, &sql.insert_poi, NULL)!=SQLITE_OK)
409         g_printf("SQL: %s\n", sqlite3_errmsg(db));
410
411 sqlite3_prepare_v2(db, "delete from poi where osm_id>0 and source=1", -1, &sql.delete_osm_poi, NULL);
412
413 /* Ways */
414 sqlite3_prepare_v2(db, "insert or replace into way (wid,nodes,type,flags,speed,isin_c,isin_p,lat,lon) values (?, ?, ?, ?, ?, ?, ?, ?, ?)", -1, &sql.insert_way_data, NULL);
415 sqlite3_prepare_v2(db, "delete from way", -1, &sql.delete_way, NULL);
416
417 /* Way nodes */
418 sqlite3_prepare_v2(db, "insert into way_n2n (wid,f,t) values (?,?,?)", -1, &sql.insert_way_n2n, NULL);
419 sqlite3_prepare_v2(db, "delete from way_n2n where wid=?", -1, &sql.delete_way_n2n, NULL);
420
421 /* Way names */
422 sqlite3_prepare_v2(db, "insert or replace into way_names (wid,name,norm) values (?, ?, ?)",  -1, &sql.insert_way_name, NULL);
423 sqlite3_prepare_v2(db, "delete from way_names", -1, &sql.delete_way_name, NULL);
424
425 /* Way postal codes */
426 sqlite3_prepare_v2(db, "insert or replace into way_pc (wid,pc) values (?, ?)",  -1, &sql.insert_way_pc, NULL);
427 sqlite3_prepare_v2(db, "delete from way_pc", -1, &sql.delete_way_pc, NULL);
428
429 /* Other language names for ways */
430 sqlite3_prepare_v2(db, "insert into way_names_nls (wid,lang,name, norm) values (?, ?, ?, ?)",  -1, &sql.insert_way_names_nls, NULL);
431 sqlite3_prepare_v2(db, "delete from way_names_nls where wid=?", -1, &sql.delete_way_names_nls, NULL);
432
433 /* Way ref and int_ref */
434 sqlite3_prepare_v2(db, "insert or replace into way_ref (rid,ref,int_ref) values (?, ?, ?)", -1, &sql.insert_way_ref, NULL);
435 sqlite3_prepare_v2(db, "delete from way_ref", -1, &sql.delete_way_ref, NULL);
436
437 return TRUE;
438 }
439
440 /********************************************************************/
441
442 static void
443 print_way(way *w)
444 {
445 #ifdef VERBOSE
446 g_assert(w);
447 g_printf("Way #%d(N:%d T:%d S:%d IS: %d/%d): %s [%s:%s:%s]\n", 
448                 w->id,  
449                 g_slist_length(w->nodes), 
450                 w->type,
451                 w->data ? w->data->speed : 0,
452                 w->data ? w->data->isin_c : -1,
453                 w->data ? w->data->isin_p : -1,
454                 w->data ? w->data->name ? w->data->name : "" : "", 
455                 w->flags & W_ONEWAY ? "-" : "=", 
456                 w->flags & W_ROUNDABOUT ? "O" : "-", 
457                 w->flags & W_LINK ? "|" : " ");
458 #endif
459 }
460
461 static void
462 print_node(node *n)
463 {
464 #ifdef VERBOSE
465 g_assert(n);
466 g_printf("Node #%d: T:%d IS: %d/%d [%s]\n",
467         n->id,
468         n->type,
469         n->data ? n->data->isin_c : -1,
470         n->data ? n->data->isin_p : -1,
471         n->data ? n->data->name : "");
472 #endif
473 }
474
475 /********************************************************************/
476
477 static gboolean
478 db_insert_node(node *n)
479 {
480 gint32 lat, lon;
481
482 g_assert(n);
483
484 lat=lat2mp_int(n->lat);
485 lon=lon2mp_int(n->lon);
486
487 sqlite3_bind_int(sql.insert_node, 1, n->id);
488
489 /* Projected and integerized lat/lot */
490 sqlite3_bind_int(sql.insert_node, 2, lat);
491 sqlite3_bind_int(sql.insert_node, 3, lon);
492 /* Original */
493 sqlite3_bind_double(sql.insert_node, 4, n->lat);
494 sqlite3_bind_double(sql.insert_node, 5, n->lon);
495 sqlite3_bind_int(sql.insert_node, 6, n->type);
496
497 db_exec(db, sql.insert_node);
498
499 return TRUE;
500 }
501
502 static gboolean
503 db_insert_place(node *n)
504 {
505 g_assert(n);
506 if (!n->data)
507         return FALSE;
508 if (!n->data->name)
509         return FALSE;
510 sqlite3_bind_int(sql.insert_place, 1, n->id);
511 sqlite3_bind_int(sql.insert_place, 2, n->type);
512 sqlite3_bind_text(sql.insert_place, 3, n->data->name, -1, SQLITE_TRANSIENT);
513 sqlite3_bind_int(sql.insert_place, 4, n->data->isin_p);
514 sqlite3_bind_int(sql.insert_place, 5, n->data->isin_c);
515
516 return db_exec(db,sql.insert_place);
517 }
518
519 static gboolean
520 db_insert_poi(node *n)
521 {
522 g_assert(n);
523 sqlite3_bind_int(sql.insert_poi, 1, n->id);
524 sqlite3_bind_double(sql.insert_poi, 2, n->lat);
525 sqlite3_bind_double(sql.insert_poi, 3, n->lon);
526 if (n->data->name)
527         sqlite3_bind_text(sql.insert_poi, 4, n->data->name, -1, SQLITE_TRANSIENT);
528 else
529         sqlite3_bind_text(sql.insert_poi, 4, "", -1, SQLITE_TRANSIENT);
530 sqlite3_bind_int(sql.insert_poi, 5, n->type);
531 sqlite3_bind_int(sql.insert_poi, 6, n->type/100);
532 sqlite3_bind_int(sql.insert_poi, 7, n->data->isin_c);
533 sqlite3_bind_int(sql.insert_poi, 8, n->data->isin_p);
534
535 if (n->data->desc)
536         sqlite3_bind_text(sql.insert_poi, 9, n->data->desc, -1, SQLITE_TRANSIENT);
537 if (n->data->url)
538         sqlite3_bind_text(sql.insert_poi, 10, n->data->url, -1, SQLITE_TRANSIENT);
539 if (n->data->postal_code)
540         sqlite3_bind_text(sql.insert_poi, 11, n->data->postal_code, -1, SQLITE_TRANSIENT);
541
542 return db_exec(db,sql.insert_poi);
543 }
544
545 /**
546  * Update node usage count
547  */
548 static gboolean
549 db_update_node_links(node *n)
550 {
551 g_assert(n);
552 sqlite3_bind_int(sql.update_node, 1, n->id);
553
554 return db_exec(db,sql.update_node);
555 }
556
557 /**
558  * Insert way,node1,node2 triplet
559  */
560 static gboolean
561 db_insert_way_n2n(way *w, node *nf, node *nt)
562 {
563 if (!w) {
564         g_printf("NULL WAY\n");
565         return FALSE;
566 }
567
568 if (!nf) {
569         g_printf("NULL NODE 1\n");
570         return FALSE;
571 }
572
573 if (!nt) {
574         g_printf("NULL NODE 2\n");
575         return FALSE;
576 }
577
578 sqlite3_bind_int(sql.insert_way_n2n, 1, w->id);
579 sqlite3_bind_int(sql.insert_way_n2n, 2, nf->id);
580 sqlite3_bind_int(sql.insert_way_n2n, 3, nt->id);
581
582 #ifdef VERBOSE_N2N
583 g_printf("%d [%d - %d]\n", w->id, nf->id, nt->id);
584 #endif
585
586 db_exec(db,sql.insert_way_n2n);
587 db_update_node_links(nf);
588 db_update_node_links(nt);
589 return TRUE;
590 }
591
592 /**
593  * Insert way ref and int_ref
594  */
595 static gboolean 
596 db_insert_way_ref(way *w)
597 {
598 if (!w->data)
599         return TRUE;
600
601 if (!w->data->ref && !w->data->int_ref)
602         return TRUE;
603
604 way_refs++;
605
606 sqlite3_bind_int(sql.insert_way_ref, 1, w->id);
607 if (w->data->ref)
608         sqlite3_bind_text(sql.insert_way_ref, 2, w->data->ref, -1, SQLITE_TRANSIENT);
609 if (w->data->int_ref)
610         sqlite3_bind_text(sql.insert_way_ref, 3, w->data->int_ref, -1, SQLITE_TRANSIENT);
611
612 return db_exec(db,sql.insert_way_ref);
613 }
614
615 /**
616  * Insert way name
617  */
618 static gboolean
619 db_insert_way_name(way *w)
620 {
621 if (!w->data)
622         return TRUE;
623 if (!w->data->name)
624         return TRUE;
625
626 way_names++;
627
628 sqlite3_bind_int(sql.insert_way_name, 1, w->id);
629 sqlite3_bind_text(sql.insert_way_name, 2, w->data->name, -1, SQLITE_TRANSIENT);
630
631 #ifdef TRANSLIT_NAMES
632 {
633         gchar *norm;
634         norm=g_convert(w->data->name, -1, "ASCII//TRANSLIT//IGNORE", "utf8", NULL, NULL, NULL);
635         if (norm && strcmp(w->data->name, norm)!=0) {
636                 sqlite3_bind_text(sql.insert_way_name, 3, norm, -1, SQLITE_TRANSIENT);
637         }
638         if (norm)
639                 g_free(norm);
640 }
641 #endif
642
643 return db_exec(db,sql.insert_way_name);
644 }
645
646 static gboolean
647 db_delete_way_names_nls(way *w)
648 {
649 sqlite3_bind_int(sql.delete_way_names_nls, 1, w->id);
650 return db_exec(db,sql.delete_way_names_nls);
651 }
652
653 static gboolean 
654 db_insert_way_pc(way *w)
655 {
656 if (!w->data)
657         return TRUE;
658 if (!w->data->postal_code)
659         return TRUE;
660
661 sqlite3_bind_int(sql.insert_way_pc, 1, w->id);
662 sqlite3_bind_text(sql.insert_way_pc, 2, w->data->postal_code, -1, SQLITE_TRANSIENT);
663
664 return db_exec(db,sql.insert_way_pc);
665 }
666
667 static gboolean
668 db_delete_way_pc(way *w)
669 {
670 sqlite3_bind_int(sql.delete_way_pc, 1, w->id);
671 return db_exec(db,sql.delete_way_pc);
672 }
673
674 static void
675 db_insert_way_names_nls_cb(gpointer key, gpointer value, gpointer user_data)
676 {
677 way *w=(way *)user_data;
678
679 sqlite3_bind_int(sql.insert_way_names_nls, 1, w->id);
680 sqlite3_bind_text(sql.insert_way_names_nls, 2, (gchar *)key, -1, SQLITE_TRANSIENT);
681 sqlite3_bind_text(sql.insert_way_names_nls, 3, (gchar *)value, -1, SQLITE_TRANSIENT);
682 #ifdef TRANSLIT_NAMES
683 {
684         gchar *norm;
685         norm=g_convert((gchar *value), -1, "ASCII//TRANSLIT//IGNORE", "utf8", NULL, NULL, NULL);
686         if (norm && strcmp((gchar *)value, norm)!=0) {
687                 sqlite3_bind_text(sql.insert_way_names_nls, 4, norm, -1, SQLITE_TRANSIENT);
688         }
689         if (norm)
690                 g_free(norm);
691 }
692 #endif
693 db_exec(db,sql.insert_way_names_nls);
694 }
695
696 static void
697 db_insert_way_names_nls(way *w)
698 {
699 if (!w->data)
700         return;
701 if (!w->data->names)
702         return;
703
704 g_hash_table_foreach(w->data->names, db_insert_way_names_nls_cb, w);
705 }
706
707 /**
708  * Insert all data for the given way
709  * - name
710  * - ref
711  * - nodes
712  * 
713  */
714 static gboolean
715 db_insert_way(way *w)
716 {
717 GSList *iter;
718 guint ncnt;
719 node *wmn;
720
721 if (!w)
722         return FALSE;
723
724 /* Skip things we don't use (yet) */
725 if (w->type==WAY_UNWAYED || w->type>WAY_ROAD_END)
726         return TRUE;
727
728 /* Insert nodes */
729 for (iter=w->nodes; iter!=NULL; iter=iter->next) {
730         if (!iter->next)
731                 break;
732         db_insert_way_n2n(w, iter->data, iter->next->data);
733 }
734
735 if (w->id==0)
736         return FALSE;
737
738 if (w->data) {
739         w->data->isin_p=osm_find_way_place(w, NODE_PLACE_CITY);
740         w->data->isin_c=osm_find_way_place(w, NODE_PLACE_COUNTRY);
741 }
742
743 print_way(w);
744
745 sqlite3_bind_int(sql.insert_way_data, 1, w->id);
746 sqlite3_bind_int(sql.insert_way_data, 2, w->ncnt);
747 sqlite3_bind_int(sql.insert_way_data, 3, w->type);
748 sqlite3_bind_int(sql.insert_way_data, 4, w->flags);
749 if (w->data) {
750         sqlite3_bind_int(sql.insert_way_data, 5, w->data->speed);
751         sqlite3_bind_int(sql.insert_way_data, 6, w->data->isin_c);
752         sqlite3_bind_int(sql.insert_way_data, 7, w->data->isin_p);
753 }
754
755 /* Get middle node, use it as a rough way location */
756 ncnt=g_slist_length(w->nodes);
757 if (ncnt>1) {
758         wmn=g_slist_nth_data(w->nodes, ncnt/2);
759         if (wmn) {
760                 sqlite3_bind_double(sql.insert_way_data, 8, wmn->lat);
761                 sqlite3_bind_double(sql.insert_way_data, 9, wmn->lon);
762         } else {
763                 g_printerr("Failed to get way middlepoint node for location information!\n");
764         }
765 }
766
767 db_exec(db,sql.insert_way_data);
768
769 db_insert_way_ref(w);
770 db_insert_way_name(w);
771 db_insert_way_names_nls(w);
772 db_insert_way_pc(w);
773
774 osm_free_way_data(w);
775 return TRUE;
776 }
777
778 /********************************************************************/
779
780 static gchar *
781 get_attr_key_value(const gchar **p, gchar *key)
782 {
783 gchar **d;
784
785 d=p;
786 while (*d!=NULL) {
787         if (strncmp(*d, key, strlen(key))==0) {
788                 d++;
789                 return *d;
790         }
791         d++;
792         d++;
793 }
794 return NULL;
795 }
796
797 static tag_state_t 
798 check_tag(const gchar *tag)
799 {
800 if (strcmp(tag,"node")==0) return IN_NODE_TAG;
801 else if (strcmp(tag,"nd")==0) return IN_WNODE_TAG;
802 else if (strcmp(tag,"way")==0) return IN_WAY_TAG;
803 else if (strcmp(tag,"tag")==0) return IN_KEY_TAG;
804 else if (strcmp(tag,"osm")==0) return IN_OSM_TAG;
805 else if (strcmp(tag,"bound")==0) return IN_BOUND_TAG;
806 else if (strcmp(tag,"relation")==0) return IN_RELATION_TAG;
807 else if (strcmp(tag,"member")==0) return IN_MEMBER_TAG;
808 else return ERROR;
809 }
810
811 static void
812 find_nls_names(gpointer key, gpointer value, gpointer user_data)
813 {
814 gchar *k, *v;
815 gchar *tmp;
816 GHashTable *nls;
817
818 k=(gchar *)key;
819 v=(gchar *)value;
820 nls=(GHashTable *)user_data;
821
822 /* Check if it is a name key, return if not. */
823 if (g_str_has_prefix(k, "name:")==FALSE)
824         return;
825
826 tmp=g_strrstr(k, ":");
827 if (!tmp)
828         return;
829 tmp++; /* skip : */
830 if (*tmp==0)
831         return;
832 g_hash_table_insert(nls, g_strdup(tmp), g_strdup(v));
833 #ifdef VERBOSE
834 g_printf("NLS(%s): [%s]\n", tmp, v);
835 #endif
836 }
837
838 /********************************************************************/
839
840 static void
841 node_print (node *n)
842 {
843 g_assert(n);
844 if (n->data) {
845         g_printf("N: %d [%f:%f][%s](%d)\n", 
846                 n->id, n->lat, n->lon, 
847                 n->data->name ? n->data->name : "-", 
848                 n->type);
849 } else {
850         g_printf("N: %d [%f:%f]\n",
851                 n->id, n->lat, n->lon);
852 }
853 }
854
855 #ifdef DEBUG
856 static void 
857 dump_array(const gchar **p)
858 {
859 char **d;
860
861 d=p;
862 while (*d!=NULL) {
863         g_printf("[%s]", *d);
864         d++;
865 }
866 g_print("\n");
867 }
868 #endif
869
870 static inline gboolean
871 osm_node_check_box(gdouble nlat, gdouble nlon)
872 {
873 if (use_bbox==FALSE)
874         return TRUE;
875 return (nlat > bbox.lat_min && nlat < bbox.lat_max && nlon > bbox.lon_min && nlon < bbox.lon_max) ? TRUE : FALSE;
876 }
877
878 static void
879 osm_new_node_data(node *n)
880 {
881 if (n==NULL) 
882         return;
883 if (n->data!=NULL) 
884         return;
885 n->data=g_slice_new(node_data);
886 n->data->name=NULL;
887 n->data->url=NULL;
888 n->data->desc=NULL;
889 n->data->postal_code=NULL;
890 n->type=NODE_PLAIN;
891 noded_cnt++;
892 }
893
894 static void
895 osm_free_node_data(node *n)
896 {
897 g_assert(n);
898 g_assert(n->data);
899 if (n->data->name)
900         g_free(n->data->name);
901 if (n->data->url)
902         g_free(n->data->url);
903 if (n->data->desc)
904         g_free(n->data->desc);
905 if (n->data->postal_code)
906         g_free(n->data->postal_code);
907 g_slice_free(node_data, n->data);
908 n->data=NULL;
909 noded_cnt--;
910 }
911
912 static node *
913 osm_new_node(gint id, gdouble lat, gdouble lon)
914 {
915 node *n=NULL;
916
917 n=g_slice_new(node);
918 g_assert(n);
919 n->id=id;
920 n->lat=lat;
921 n->lon=lon;
922 n->data=(node_data *)NULL;
923 return n;
924 }
925
926 static void
927 osm_free_node(node *n)
928 {
929 g_assert(n);
930 g_slice_free(node, n);
931 }
932
933 static node *
934 osm_find_node(guint32 nid)
935 {
936 node *n;
937
938 g_assert(osm_nodes);
939 return g_hash_table_lookup(osm_nodes, GINT_TO_POINTER(nid));
940 }
941
942 static void
943 osm_new_way_data(way *w)
944 {
945 if (w==NULL) 
946         return;
947 if (w->data!=NULL) 
948         return;
949
950 w->data=g_slice_new(way_data);
951 w->data->name=NULL;
952 w->data->names=NULL;
953 w->data->ref=NULL;
954 w->data->int_ref=NULL;
955 w->data->postal_code=NULL;
956 w->data->layer=0;
957 w->data->speed=0;
958 }
959
960 static void
961 osm_free_way_data(way *w)
962 {
963 g_assert(w);
964 if (!w->data)
965         return;
966 if (w->data->name)
967         g_free(w->data->name);
968 if (w->data->ref)
969         g_free(w->data->ref);
970 if (w->data->int_ref)
971         g_free(w->data->int_ref);
972 g_slice_free(way_data, w->data);
973 w->data=NULL;
974 }
975
976 static way *
977 osm_new_way(gint id)
978 {
979 way *w;
980
981 w=g_slice_new(way);
982 g_assert(w);
983 w->id=id;
984 w->nodes=NULL;
985 w->type=WAY_UNWAYED;
986 w->data=NULL;
987 w->ncnt=0;
988 w->flags=0;
989
990 /* Add to list of ways */
991 return w;
992 }
993
994 static void
995 osm_free_way(way *w)
996 {
997 if (w->nodes)
998         g_slist_free(w->nodes);
999 g_slice_free(way, w);
1000 }
1001
1002 static void
1003 osm_way_add_to_list(way *w)
1004 {
1005 g_assert(w);
1006 osm_ways=g_slist_prepend(osm_ways, w);
1007 }
1008
1009 static void
1010 osm_way_new_node(way *w, gint nid)
1011 {
1012 node *n;
1013
1014 g_assert(w);
1015 n=osm_find_node(nid);
1016 w->nodes=g_slist_prepend(w->nodes, n);
1017 w->ncnt++;
1018 }
1019
1020 /**
1021  * Search the place hash table for the location of the node.
1022  *
1023  */
1024 static guint32 
1025 osm_find_node_place(node *n)
1026 {
1027 node *t;
1028 gchar **isin;
1029 gchar **place;
1030
1031 if (!n->data)
1032         return 0;
1033
1034 isin=g_hash_table_lookup(osm_node_isin, GINT_TO_POINTER(n->id));
1035
1036 if (!isin)
1037         return 0;
1038
1039 place=isin;
1040 while (*place!=NULL) {
1041         gchar *ps;
1042         ps=g_strstrip(*place);
1043 #ifdef VERBOSE
1044         g_printf("Checking (%d) [%s] in [%s]\n",n->type, n->data->name, ps);
1045 #endif
1046         switch (n->type) {
1047         case NODE_PLACE_CITY:
1048         case NODE_PLACE_TOWN:
1049         case NODE_PLACE_VILLAGE:
1050         case NODE_PLACE_HAMLET:
1051                 t=g_hash_table_lookup(osm_place_region, ps);
1052                 if (t)
1053                         return t->id;
1054                 t=g_hash_table_lookup(osm_place_country, ps);
1055                 if (t)
1056                         return t->id;
1057         break;
1058         case NODE_PLACE_SUBURB:
1059         case NODE_PLACE_LOCALITY:
1060                 t=g_hash_table_lookup(osm_place_city, ps);
1061                 if (t)
1062                         return t->id;
1063         break;
1064         case NODE_PLACE_ISLAND:
1065                 return 0;
1066         break;
1067         default:
1068                 t=g_hash_table_lookup(osm_place_city, ps);
1069                 if (t)
1070                         return t->id;
1071         break;
1072         }
1073         place++;
1074 }
1075
1076 return 0;
1077 }
1078
1079 static guint32
1080 osm_find_way_place(way *w, node_type_t nt)
1081 {
1082 gchar **isin;
1083 gchar **place;
1084
1085 isin=g_hash_table_lookup(osm_way_isin, GINT_TO_POINTER(w->id));
1086 if (!isin)
1087         return 0;
1088
1089 place=isin;
1090 while (*place!=NULL) {
1091         node *t;
1092         gchar *ps;
1093
1094         ps=g_strstrip(*place);
1095
1096 #ifdef VERBOSE
1097         g_printf("Checking (%d) in [%s]\n",w->id, ps);
1098 #endif
1099 switch (nt) {
1100         case NODE_PLACE_CITY:
1101         case NODE_PLACE_TOWN:
1102         case NODE_PLACE_VILLAGE:
1103         case NODE_PLACE_HAMLET:
1104         case NODE_PLACE_LOCALITY:
1105                 t=g_hash_table_lookup(osm_place_city, ps);
1106                 if (t)
1107                         return t->id;
1108         break;
1109         case NODE_PLACE_COUNTRY:
1110                 t=g_hash_table_lookup(osm_place_country, ps);
1111                 if (t)
1112                         return t->id;
1113         break;
1114         default:
1115                 g_assert_not_reached();
1116         break;
1117         }
1118         place++;
1119 }
1120
1121 return 0;
1122 }
1123
1124 /***********************************************************************/
1125
1126 static void
1127 osm_node_save_node(gint key, gpointer value, gpointer user_data)
1128 {
1129 node *n=(node *)value;
1130
1131 dbnode_cnt++;
1132 db_insert_node(n);
1133 if (dbnode_cnt % 20000==0)
1134         g_printf("\rNodes: %f%% (%u/%u)\n",
1135                 ((float)dbnode_cnt/(float)(node_cnt-node_skip_cnt))*100,
1136                 dbnode_cnt, node_cnt);
1137 }
1138
1139 /**
1140  * Check node type and insert as POI or Place
1141  * Discard extra data after insert.
1142  */
1143 static gboolean
1144 osm_node_save_poi(node *n, gpointer user_data)
1145 {
1146 if (!n) {
1147         g_printerr("ERROR: null poi\n");
1148         return FALSE;
1149 }
1150
1151 if (!n->data) {
1152         g_printerr("POI node with no data ?\n");
1153         return FALSE;
1154 }
1155
1156 n->data->isin_p=osm_find_node_place(n);
1157 n->data->isin_c=0;
1158
1159 if (n->type>NODE_POI_START && n->type<NODE_POI_END) {
1160         print_node(n);
1161         db_insert_poi(n);
1162         osm_free_node_data(n);
1163 } else if (n->type>NODE_PLACE_START && n->type<NODE_PLACE_END) {
1164         print_node(n);
1165         db_insert_place(n);
1166 } else {
1167         osm_free_node_data(n);
1168         return FALSE;
1169 }
1170
1171 return TRUE;
1172 }
1173
1174 static gboolean
1175 osm_planet_poi_clear_nodes(void)
1176 {
1177 g_print("Removing old OSM POIs...\n");
1178 db_transaction_begin(db);
1179 sqlite3_step(sql.delete_osm_poi);
1180 sqlite3_step(sql.delete_place);
1181 return db_transaction_commit(db);
1182 }
1183
1184 static gboolean
1185 osm_planet_poi_save_nodes(void)
1186 {
1187 g_print("Storing new POIs...\n");
1188 db_transaction_begin(db);
1189 g_slist_foreach(osm_poi, osm_node_save_poi, NULL);
1190 g_slist_free(osm_poi);
1191 return db_transaction_commit(db);
1192 }
1193
1194 /*********************************************************************/
1195
1196 static void
1197 osm_planet_clear_nodes(void)
1198 {
1199 g_print("Clearing old nodes\n");
1200 sqlite3_step(sql.delete_nodes);
1201 }
1202
1203 static gboolean
1204 osm_planet_save_nodes(void)
1205 {
1206 g_print("Storing nodes...\n");
1207 db_transaction_begin(db);
1208 g_hash_table_foreach(osm_nodes, osm_node_save_node, NULL);
1209 return db_transaction_commit(db);
1210 }
1211
1212 /*********************************************************************/
1213
1214 static void
1215 osm_way_save(way *value, gpointer user_data)
1216 {
1217 dbway_cnt++;
1218 db_insert_way(value);
1219 if (dbway_cnt % 15000==0 && dbway_cnt>0) {
1220                 g_printf("\rWays: %f%% (%u/%u)\n",
1221                         (((float)dbway_cnt/(float)way_cnt)*100),
1222                         dbway_cnt, way_cnt);
1223                 print_way(value);
1224 }
1225 }
1226
1227 static void
1228 osm_planet_clear_ways(void)
1229 {
1230 g_print("Clearing old data\n");
1231 sqlite3_step(sql.delete_way);
1232 sqlite3_step(sql.delete_way_name);
1233 sqlite3_step(sql.delete_way_ref);
1234 sqlite3_step(sql.delete_way_n2n);
1235 }
1236
1237 static gboolean
1238 osm_planet_save_ways(void)
1239 {
1240 g_print("Inserting new ways\n");
1241 db_transaction_begin(db);
1242 g_slist_foreach(osm_ways, osm_way_save, NULL);
1243 return db_transaction_commit(db);
1244 }
1245
1246 /*********************************************************************/
1247
1248 static void
1249 osm_planet_save_all_nodes(void)
1250 {
1251 g_printf("Saving planet nodes to database:\n");
1252
1253 osm_planet_poi_clear_nodes();
1254 osm_planet_poi_save_nodes();
1255
1256 if (!is_update) {
1257         osm_planet_clear_nodes();
1258         osm_planet_clear_ways();
1259 }
1260 osm_planet_save_nodes();
1261 }
1262
1263 static void
1264 osm_planet_save_all_ways(void)
1265 {
1266 g_printf("Saving planet way to database:\n");
1267
1268 osm_planet_save_ways();
1269 }
1270
1271 /***********************************************************************/
1272
1273 static void
1274 _osm_tag_start(void *userData, const char *name, const char **atts)
1275 {
1276 tag_state_t t;
1277 gchar *k, *v;
1278 guint32 id, ndref;
1279 gdouble nlat, nlon;
1280
1281 t=check_tag(name);
1282 switch (t) {
1283         case IN_OSM_TAG:
1284                 g_printf("Starting...\n");
1285         break;
1286         case IN_NODE_TAG:
1287                 tag_parent=IS_NODE;
1288                 node_cnt++;
1289
1290                 id=atoi(get_attr_key_value(atts, "id"));
1291                 nlat=atof(get_attr_key_value(atts, "lat"));
1292                 nlon=atof(get_attr_key_value(atts, "lon"));
1293
1294                 cnode=osm_new_node(id, nlat, nlon);
1295                 osm_node_tags=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1296         break;
1297         case IN_WAY_TAG:
1298                 tag_parent=IS_WAY;
1299                 way_cnt++;
1300                 id=atoi(get_attr_key_value(atts, "id"));
1301                 cway=osm_new_way(id);
1302                 osm_way_tags=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1303         break;
1304         case IN_WNODE_TAG:
1305                 ndref=atoi(get_attr_key_value(atts, "ref"));
1306                 if (use_bbox==TRUE) {
1307                         if (osm_find_node(ndref)==NULL) {
1308                                 cway->id=0;
1309                                 return;
1310                         }
1311                 }
1312                 osm_way_new_node(cway, ndref);
1313         break;
1314         case IN_KEY_TAG:
1315                 k=get_attr_key_value(atts, "k");
1316                 if (strcmp(k,"created_by")==0)
1317                         return;
1318                 if (strcmp(k,"source")==0)
1319                         return;
1320
1321                 v=get_attr_key_value(atts, "v");
1322 #ifdef VERBOSE_KEYS
1323                 g_printf("TAG: K=[%s] V=[%s]\n", k, v);
1324 #endif
1325
1326                 switch (tag_parent) {
1327                 case IS_NONE:
1328                         g_printf("Tag key/value pair but unknown owner\n");
1329                 break;
1330                 case IS_NODE:
1331                 {
1332                         if (!osm_node_tags)
1333                                 return;
1334
1335                         /* Insert key/value pairs into hash table */
1336                         if (cnode==NULL) {
1337                                 g_printerr("In node tags but node is NULL!\n");
1338                                 return;
1339                         }
1340                         g_hash_table_insert(osm_node_tags, g_strdup(k), g_strdup(v));
1341                 }
1342                 break;
1343                 case IS_WAY: 
1344                 {
1345                         if (cway==NULL) {
1346                                 g_printerr("In way tags but way is NULL!\n");
1347                                 return;
1348                         }
1349                         g_hash_table_insert(osm_way_tags, g_strdup(k), g_strdup(v));
1350                         osm_new_way_data(cway);
1351                 }
1352                 break;
1353                 case IS_RELATION:
1354
1355                 break;
1356                 }
1357         break;
1358         case IN_BOUND_TAG:
1359                 /* Ignore for now */
1360                 g_printf("Ignoring bound tag\n");
1361         break;
1362         case IN_RELATION_TAG:
1363                 tag_parent=IS_RELATION;
1364
1365         break;
1366         case IN_MEMBER_TAG:
1367
1368         break;
1369         default:
1370                 tag_parent=IS_NONE;
1371                 g_printf("Unknown tag: %s\n", name);
1372         break;
1373 }
1374 }
1375
1376 static void
1377 _osm_tag_end(void *userData, const char *name)
1378 {
1379 tag_state_t t;
1380 gchar *v;
1381 guint i;
1382 t=check_tag(name);
1383 switch (t) {
1384         case IN_NODE_TAG:
1385
1386                 if (node_cnt % 25000==0) {
1387                         g_printf("Nodes: %u of %u, POIs: %u, Outside box: %u\n", 
1388                                 node_cnt-node_skip_cnt, node_cnt, noded_cnt, node_skip_cnt);
1389                 }
1390
1391                 if (!osm_node_tags)
1392                         return;
1393
1394                 osm_new_node_data(cnode);
1395
1396                 for (i=0; nodeinfo[i].k; i++) {
1397                         v=g_hash_table_lookup(osm_node_tags, nodeinfo[i].k);
1398                         if (!v)
1399                                 continue;
1400                         if (strcasecmp (v, nodeinfo[i].v)==0) {
1401                                 cnode->type=nodeinfo[i].type;
1402                                 break;
1403                         }
1404                 }
1405
1406                 /* Check if node is inside bounding box, if not skip it. 
1407                  * But keep it if it's something we might need for other nodes:
1408                  * - Places (for is_in)
1409                  * - ...
1410                  */
1411                 if ((osm_node_check_box(cnode->lat, cnode->lon)==FALSE) && 
1412                                 (cnode->type<NODE_PLACE_START)) {
1413                         osm_free_node_data(cnode);
1414                         osm_free_node(cnode);
1415                         g_hash_table_destroy(osm_node_tags);
1416                         node_skip_cnt++;
1417                         return;
1418                 }
1419
1420                 g_hash_table_insert(osm_nodes, GINT_TO_POINTER(cnode->id), cnode);
1421
1422                 if (cnode->type!=NODE_PLAIN) {
1423                         cnode->data->name=NULL;
1424                         v=g_hash_table_lookup(osm_node_tags, "name");
1425                         if (v)
1426                                 cnode->data->name=g_strstrip(g_utf8_normalize(v, -1, G_NORMALIZE_ALL_COMPOSE));
1427                         v=g_hash_table_lookup(osm_node_tags, "note");
1428                         if (v)
1429                                 cnode->data->desc=g_strstrip(g_strdup(v));
1430                         v=g_hash_table_lookup(osm_node_tags, "postal_code");
1431                         if (v)
1432                                 cnode->data->postal_code=g_strstrip(g_strdup(v));
1433
1434                         /* Links */
1435                         v=g_hash_table_lookup(osm_node_tags, "url");
1436                         if (v) {
1437                                 cnode->data->url=g_strstrip(g_strdup(v));
1438                         } else {
1439                                 v=g_hash_table_lookup(osm_node_tags, "wikipedia");
1440                                 if (v && strncmp(v,"http:", 5)==0) 
1441                                         cnode->data->url=g_strstrip(g_strdup(v));
1442                         }
1443                 }
1444
1445                 cnode->data->isin_c=0;
1446                 cnode->data->isin_p=0;
1447                 v=g_hash_table_lookup(osm_node_tags, "is_in");
1448                 if (v) {
1449                         gchar **isin;                           
1450                         isin=g_strsplit(v, ",", 10);
1451                         g_hash_table_insert(osm_node_isin, GINT_TO_POINTER(cnode->id), isin);
1452                 }
1453
1454                 if (cnode->type==NODE_PLAIN) {
1455                         osm_free_node_data(cnode);
1456                 } else {
1457                         osm_poi=g_slist_prepend(osm_poi, cnode);
1458                         if (cnode->data->name) {
1459                                 switch (cnode->type) {
1460                                 case NODE_PLACE_COUNTRY:
1461                                         g_hash_table_insert(osm_place_country, cnode->data->name, cnode);
1462                                 break;
1463                                 case NODE_PLACE_CITY:
1464                                 case NODE_PLACE_TOWN:
1465                                         g_hash_table_insert(osm_place_city, cnode->data->name, cnode);
1466                                 break;
1467                                 case NODE_PLACE_SUBURB:
1468                                         g_hash_table_insert(osm_place_suburb, cnode->data->name, cnode);
1469                                 break;
1470                                 case NODE_PLACE_VILLAGE:
1471                                 case NODE_PLACE_HAMLET:
1472                                 case NODE_PLACE_LOCALITY:
1473                                         g_hash_table_insert(osm_place_village, cnode->data->name, cnode);
1474                                 break;
1475                                 case NODE_PLACE_ISLAND:
1476                                         /* Ignore for now */
1477                                 break;
1478                                 default:;
1479                                 }
1480                         }
1481                 }
1482                 g_hash_table_destroy(osm_node_tags);
1483                 cnode=NULL;
1484         break;
1485         case IN_WAY_TAG:
1486                 if (way_cnt % 1024==0) {
1487                         g_printf("\rWays: %d\n", way_cnt);
1488                 }
1489
1490                 cway->nodes=g_slist_reverse(cway->nodes);
1491
1492                 for (i=0; wayinfo[i].k; i++) {
1493                         v=g_hash_table_lookup(osm_way_tags, wayinfo[i].k);
1494                         if (!v)
1495                                 continue;
1496                         if (strcasecmp (v, wayinfo[i].v)==0) {
1497                                 if (wayinfo[i].link==TRUE)
1498                                         cway->flags|=W_LINK;
1499                                 if (wayinfo[i].area==TRUE)
1500                                         cway->flags|=W_AREA;
1501                                 if (wayinfo[i].oneway==TRUE)
1502                                         cway->flags|=W_ONEWAY;
1503                                 cway->type=wayinfo[i].type;
1504                                 if (cway->data->speed==0)
1505                                         cway->data->speed=wayinfo[i].defspeed;
1506                                 break;
1507                         }
1508                 }
1509
1510                 v=g_hash_table_lookup(osm_way_tags, "name");
1511                 if (v) {
1512                         cway->data->name=g_utf8_normalize(v, -1, G_NORMALIZE_ALL_COMPOSE);
1513                         /* Try to find other language names */
1514                         cway->data->names=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, g_free);
1515                         g_hash_table_foreach(osm_way_tags, find_nls_names, cway->data->names);
1516                         if (g_hash_table_size(cway->data->names)==0) {
1517                                 g_hash_table_destroy(cway->data->names);
1518                                 cway->data->names=NULL;
1519                         }
1520                 }
1521
1522                 v=g_hash_table_lookup(osm_way_tags, "ref");
1523                 if (v)
1524                         cway->data->ref=g_strdup(v);
1525                 v=g_hash_table_lookup(osm_way_tags, "int_ref");
1526                 if (v)
1527                         cway->data->int_ref=g_strdup(v);
1528
1529                 v=g_hash_table_lookup(osm_way_tags, "postal_code");
1530                 if (v)
1531                         cway->data->postal_code=g_strdup(v);
1532
1533                 /* XXX: somehow handle the silly -1 'reversed' oneway */
1534                 v=g_hash_table_lookup(osm_way_tags, "oneway");
1535                 if (v)
1536                         cway->flags|=W_ONEWAY;
1537
1538                 v=g_hash_table_lookup(osm_way_tags, "noexit");
1539                 if (v)
1540                         cway->flags|=W_NOEXIT;
1541                 
1542                 v=g_hash_table_lookup(osm_way_tags, "speedlimit");
1543                 if (v)
1544                         cway->data->speed=atoi(v);
1545                 v=g_hash_table_lookup(osm_way_tags, "maxspeed");
1546                 if (v)
1547                         cway->data->speed=atoi(v);
1548
1549 #if 0
1550                 v=g_hash_table_lookup(osm_way_tags, "layer");
1551                 if (v)
1552                         cway->data->layer=atoi(v);
1553 #endif
1554
1555                 v=g_hash_table_lookup(osm_way_tags, "junction");
1556                 if (v && strcasecmp(v,"roundabout")==0) {
1557                         cway->flags|=W_ROUNDABOUT;
1558                         cway->flags|=W_ONEWAY;
1559                 } else if (v && strcasecmp(v,"mini_roundabout")==0) {
1560                         cway->flags|=W_ROUNDABOUT;
1561                         cway->flags|=W_ONEWAY;
1562                 }
1563
1564                 /* XXX: Should check keys */
1565                 v=g_hash_table_lookup(osm_way_tags, "access");
1566                 if (v && (strcasecmp(v, "private")==0)) {
1567                         cway->flags|=W_NOACCESS;
1568                 }
1569
1570                 print_way(cway);
1571
1572                 v=g_hash_table_lookup(osm_way_tags, "is_in");
1573                 if (v) {
1574                         gchar **isin;                           
1575                         isin=g_strsplit(v, ",", 10);
1576                         g_hash_table_insert(osm_way_isin, GINT_TO_POINTER(cway->id), isin);
1577                 }
1578
1579                 if (cway->data && cway->data->name==NULL && cway->data->ref==NULL &&
1580                         cway->data->int_ref==NULL && cway->data->layer==0 && cway->data->speed==0)
1581                         osm_free_way_data(cway);
1582
1583                 if (cway->id!=0)
1584                         osm_way_add_to_list(cway);
1585                 else 
1586                         osm_free_way(cway);
1587
1588                 cway=NULL;
1589                 g_hash_table_destroy(osm_way_tags);
1590         break;
1591         case IN_BOUND_TAG:
1592                 /* */
1593         break;
1594         case IN_OSM_TAG:
1595                 g_printf("\nPlanet loaded.\n");
1596         break;
1597         default:;
1598 }
1599 }
1600
1601 /************************************************************************/
1602
1603 static void
1604 storage_init(void)
1605 {
1606 osm_nodes=g_hash_table_new(g_direct_hash, g_direct_equal);
1607
1608 osm_place_country=g_hash_table_new(g_str_hash, g_str_equal);
1609 osm_place_city=g_hash_table_new(g_str_hash, g_str_equal);
1610 osm_place_suburb=g_hash_table_new(g_str_hash, g_str_equal);
1611 osm_place_village=g_hash_table_new(g_str_hash, g_str_equal);
1612 osm_place_region=g_hash_table_new(g_str_hash, g_str_equal);
1613 osm_node_isin=g_hash_table_new(g_direct_hash, g_direct_equal);
1614 osm_way_isin=g_hash_table_new(g_direct_hash, g_direct_equal);
1615 }
1616
1617 static void
1618 storage_free(void)
1619 {
1620 g_hash_table_destroy(osm_nodes);
1621
1622 g_hash_table_destroy(osm_place_country);
1623 g_hash_table_destroy(osm_place_city);
1624 g_hash_table_destroy(osm_place_suburb);
1625 g_hash_table_destroy(osm_place_village);
1626 g_hash_table_destroy(osm_place_region);
1627 g_hash_table_destroy(osm_node_isin);
1628 }
1629
1630 /************************************************************************/
1631
1632 static gint
1633 print_fail(const gchar *msg, gint ret)
1634 {
1635 g_printerr("ERROR: %s\n", msg);
1636 return ret;
1637 }
1638
1639 /************************************************************************/
1640
1641 static void
1642 print_memory_usage(void)
1643 {
1644 g_print("Memory usage per item:\n");
1645 g_printf("Node  size: %d\n", (gint)sizeof(node));
1646 g_printf("NodeD size: %d\n", (gint)sizeof(node_data));
1647 g_printf("Way   size: %d\n", (gint)sizeof(way));
1648 g_printf("WayD  size: %d\n", (gint)sizeof(way_data));
1649 }
1650
1651 /************************************************************************
1652  * Public inteface
1653  ************************************************************************/
1654
1655 void
1656 osm_planet_parser_init(void)
1657 {
1658 xp=XML_ParserCreate(NULL);
1659 XML_SetElementHandler(xp, _osm_tag_start, _osm_tag_end);
1660 storage_init();
1661 }
1662
1663 void
1664 osm_planet_parser_deinit(void)
1665 {
1666 XML_ParserFree(xp);
1667 storage_free();
1668 }
1669
1670 gboolean
1671 osm_planet_parse_buffer(gchar *buffer, size_t r)
1672 {
1673 if (XML_Parse(xp, buffer, r, r>0 ? 0:1) == XML_STATUS_ERROR) {
1674         g_printerr("Parse error at line %d:\n%s\n",
1675                 (gint)XML_GetCurrentLineNumber(xp),
1676                 XML_ErrorString(XML_GetErrorCode(xp)));
1677         return FALSE;
1678 }
1679 return TRUE;
1680 }
1681
1682 gboolean 
1683 osm_planet_parse_file(gchar *pfile)
1684 {
1685 FILE *f;
1686 BZFILE *b;
1687 int bzerror;
1688 int r;
1689 gchar buffer[FILE_BUFFER];
1690 gboolean res=TRUE;
1691
1692 f=fopen(pfile, "r");
1693 if (!f) {
1694         perror("fopen failed\n");
1695         return FALSE;
1696 }
1697
1698 b=BZ2_bzReadOpen(&bzerror, f, 0, 0, NULL, 0);
1699 if (bzerror != BZ_OK) {
1700         g_printf("BZ2_bzReadOpen failed\n");
1701         BZ2_bzReadClose(&bzerror, b);
1702         return FALSE;
1703 }
1704
1705 do {
1706         r=BZ2_bzRead(&bzerror, b, buffer, FILE_BUFFER);
1707         if ((bzerror!=BZ_STREAM_END) && (bzerror!=BZ_OK)) {
1708                 res=FALSE;
1709                 break;
1710         }
1711         if (!osm_planet_parse_buffer(buffer, r)) {
1712                 res=FALSE;
1713                 break;
1714         }
1715 } while (bzerror==BZ_OK);
1716
1717 BZ2_bzReadClose(&bzerror, b);
1718 fclose(f);
1719 return res;
1720 }
1721
1722 /**
1723  * Set up bounding box for import.
1724  *
1725  */
1726 void
1727 osm_import_set_bbox(gboolean use_bb, gdouble latmin, gdouble lonmin, gdouble latmax, gdouble lonmax)
1728 {
1729 use_bbox=use_bb;
1730 bbox.lat_min=latmin;
1731 bbox.lon_min=lonmin;
1732 bbox.lat_max=latmax;
1733 bbox.lon_max=lonmax;
1734 g_printf("Skipping data outside of box: %f,%f - %f,%f\n",
1735         bbox.lat_min, bbox.lon_min,     bbox.lat_max, bbox.lon_max);
1736 }
1737
1738 static void
1739 osm_print_import_stats(void)
1740 {
1741 g_printf("Total nodes %d, POIs: %d and Ways %d.\n",     node_cnt, noded_cnt, way_cnt);
1742 g_printf("Cities/Towns: %d\n", g_hash_table_size(osm_place_city));
1743 g_printf("Villages/Hamlets: %d\n", g_hash_table_size(osm_place_village));
1744 g_printf("Suburbs: %d\n", g_hash_table_size(osm_place_suburb));
1745 g_printf("Nodes: %d\n", g_hash_table_size(osm_nodes));
1746 }
1747
1748 /**
1749  * Simple helper to do all preparations and importing from planet -> database
1750  *
1751  */
1752 gboolean
1753 osm_import(const gchar *planet, const gchar *database)
1754 {
1755 if (db_connect(&db, database)!=TRUE) {
1756         g_printerr("Database open failed: %s", database);
1757         return FALSE;
1758 }
1759
1760 if (!osm_db_create(db)) {
1761         g_printerr("Failed to create osm tables or indexes\n");
1762         return FALSE;
1763 }
1764
1765 if (!osm_db_prepare(db)) {
1766         g_printerr("Failed to prepare sql statements\n");
1767         return FALSE;
1768 }
1769
1770 osm_planet_parser_init();
1771
1772 if (osm_planet_parse_file(planet)==FALSE) {
1773         g_printerr("Failed to parse file: %s\n", planet);
1774         return FALSE;
1775 }
1776
1777 osm_print_import_stats();
1778
1779 osm_planet_save_all_nodes();
1780 osm_planet_save_all_ways();
1781 osm_planet_parser_deinit();
1782 db_finalize();
1783 db_close(&db);
1784 g_printf("All done.\n");
1785 return TRUE;
1786 }
1787
1788 static gpointer 
1789 osm_import_thread(gpointer user_data)
1790 {
1791 gboolean r;
1792 osm_import_data_req *req=(osm_import_data_req *)user_data;
1793
1794 g_assert(req);
1795 g_assert(req->planet);
1796 g_assert(req->db);
1797
1798 osm_import_progress_cb=req->progress_cb!=NULL ? req->progress_cb : NULL;
1799
1800 r=osm_import(req->planet, req->db);
1801 g_debug("OSM import result: %d", r);
1802
1803 g_free(req->planet);
1804 g_free(req->db);
1805
1806 if (req->done_cb!=NULL)
1807         g_idle_add(req->done_cb, GINT_TO_POINTER(r==TRUE ? 0 : 1));
1808
1809 return r==TRUE ? 0 : 1;
1810 }
1811
1812 /**
1813  * Helper to start an import in the background using a thread.
1814  *
1815  * Two callback can be given, one for progress feedback and one when the operation is done.
1816  * Done callback must call the join function.
1817  * Only one import thread can run at a time.
1818  *
1819  */
1820 gboolean 
1821 osm_import_bg(const gchar *planet, const gchar *database, GSourceFunc progress_cb, GSourceFunc done_cb)
1822 {
1823 GError *error=NULL;
1824
1825 g_return_val_if_fail(import_thread==NULL, FALSE);
1826
1827 osm_import_req.planet=g_strdup(planet);
1828 osm_import_req.db=g_strdup(database);
1829 osm_import_req.progress_cb=progress_cb;
1830 osm_import_req.done_cb=done_cb;
1831
1832 import_thread=g_thread_create(osm_import_thread, &osm_import_req, TRUE, &error);
1833 if (import_thread==NULL) {
1834         g_free(osm_import_req.planet);
1835         g_free(osm_import_req.db);
1836         g_printerr("Import thread creation failed.\n");
1837         return FALSE;
1838 }
1839 if (osm_import_progress_cb!=NULL)
1840         import_sid=g_timeout_add(1000, osm_import_progress_cb, NULL);
1841 return TRUE;
1842 }
1843
1844 gint
1845 osm_import_join_bg(void)
1846 {
1847 gint ret;
1848 g_assert(import_thread!=NULL);
1849
1850 if (import_sid!=0)
1851         g_source_remove(import_sid);
1852 ret=g_thread_join(import_thread);
1853 import_thread=NULL;
1854 return ret;
1855 }