]> err.no Git - mapper/blob - src/osm-db.c
include gi18n.h
[mapper] / src / osm-db.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 #include "config.h"
21
22 #include <unistd.h>
23 #include <string.h>
24 #include <strings.h>
25 #include <sys/types.h>
26 #include <math.h>
27 #include <glib.h>
28 #include <glib/gstdio.h>
29 #include <glib/gi18n.h>
30 #include <gtk/gtk.h>
31 #include <sqlite3.h>
32
33 #include "osm.h"
34 #include "latlon.h"
35 #include "osm-db.h"
36 #include "settings.h"
37
38 /* #define DEBUG_OSM */
39 /* #define DEBUG_OSM_TIME */
40 #define OSM_PLACE_CACHE_MAX_ITEMS (64)
41
42 #define OSM_DB_PROGRESS_NUM (20000)
43
44 /* Node search ranges */
45 #define OSM_RANGE_START (16384)
46 #define OSM_RANGE_STEP  (8192)
47 #define OSM_RANGE_STOP  (65535)
48
49 static sqlite3 *osmdb;
50 static gboolean osm_db_ok;
51
52 struct sql_select_stmt {
53         sqlite3_stmt *select_way;
54         sqlite3_stmt *select_way2;
55         sqlite3_stmt *select_way_next_seg;
56         sqlite3_stmt *select_way_prev_seg;
57
58         sqlite3_stmt *select_way_nodes;
59         sqlite3_stmt *select_way_name;
60         sqlite3_stmt *select_way_name_nls;
61         sqlite3_stmt *select_way_name_search;
62         sqlite3_stmt *select_way_ref;
63         sqlite3_stmt *select_place;
64         sqlite3_stmt *select_near_place;
65
66         sqlite3_stmt *select_node_next;
67         sqlite3_stmt *select_node_prev;
68 };
69 static struct sql_select_stmt sql;
70 static GTimer *dbt;
71 static GtkProgressBar *dbpw=NULL;
72
73 /* Cache hash tables */
74 static GHashTable *place_cache;
75
76 static guint way_dist_range=OSM_RANGE_WAY;
77
78 osm_way_node *osm_way_get_prev_node(osm_way *w);
79 osm_way_node *osm_way_get_next_node(osm_way *w);
80
81 /*****************************************************************************/
82
83 void
84 osm_set_way_range(guint sr)
85 {
86 way_dist_range=sr;
87 }
88
89 void
90 osm_set_way_range_from_speed(gfloat speed)
91 {
92 if (speed>54.0)
93         way_dist_range=OSM_RANGE_WAY*2;
94 else
95         way_dist_range=OSM_RANGE_WAY-lrint((speed/4)*1000);
96 }
97
98 /*****************************************************************************/
99
100 static int
101 osm_progress(void *ud)
102 {
103 if (!dbpw)
104         return 0;
105 gtk_progress_bar_pulse(dbpw);
106 gtk_main_iteration_do(FALSE);
107 return 0;
108 }
109
110 static void
111 osm_progress_hide(sqlite3 *db)
112 {
113 if (!dbpw)
114         return;
115 gtk_progress_bar_set_text(dbpw, "");
116 gtk_progress_bar_set_fraction(dbpw, 0.0);
117 sqlite3_progress_handler(db, OSM_DB_PROGRESS_NUM, NULL, NULL);
118 }
119
120 static void
121 osm_progress_show(sqlite3 *db)
122 {
123 if (!dbpw)
124         return;
125 gtk_progress_bar_set_text(dbpw, _("Searching..."));
126 sqlite3_progress_handler(db, OSM_DB_PROGRESS_NUM, osm_progress, NULL);
127 }
128
129 void
130 osm_progress_set_widget(sqlite3 *db, GtkProgressBar *w)
131 {
132 if (dbpw!=NULL && w==NULL)
133         osm_progress_hide(db);
134 dbpw=w;
135 if (w!=NULL)
136         osm_progress_show(db);
137 }
138
139 /*****************************************************************************/
140
141 gboolean
142 osm_db_prepare(sqlite3 *db)
143 {
144 /* Place */
145 /* Select nearest place inside lat,lon+-range */
146 if (sqlite3_prepare_v2(db, "select name,(($LAT-ilat)*($LAT-ilat))+(($LON-ilon)*($LON-ilon)) as dist,"
147                                         " ilat,ilon,places.nid,isin_p,isin_c "
148                                         " from places,nodes where type=$TYPE "
149                                         " and nodes.nid=places.nid "
150                                         " and ilat between $LAT-$RANGE and $LAT+$RANGE"
151                                         " and ilon between $LON-$RANGE and $LON+$RANGE order by dist limit 1",
152                     -1, &sql.select_near_place, NULL)!=SQLITE_OK)
153         return FALSE;
154
155 /* Select place name, distance, location, parent-place and type with given ID */
156 if (sqlite3_prepare_v2(db, "select name,(($LAT-ilat)*($LAT-ilat))+(($LON-ilon)*($LON-ilon)) as dist,"
157                                         " ilat,ilon,type,isin_p,isin_c "
158                                         " from places,nodes where "
159                                         " nodes.nid=places.nid "
160                                         " and places.nid=$NID order by dist limit 1",
161                     -1, &sql.select_place, NULL)!=SQLITE_OK)
162         return FALSE;
163
164 /* Ways */
165 /* Select nearest ways inside lat,lon+-range */
166 if (sqlite3_prepare_v2(db, "select w.wid,type,nodes,flags,"
167                                         "(($LAT-n.ilat)*($LAT-n.ilat))+(($LON-n.ilon)*($LON-n.ilon)) as d,wn.f,wn.t,n.ilat,n.ilon "
168                                         " from way as w,way_n2n as wn,nodes as n "
169                                         " where w.wid=wn.wid and wn.f=n.nid "
170                                         " and n.ilat between $LAT-$RANGE and $LAT+$RANGE "
171                                         " and n.ilon between $LON-$RANGE and $LON+$RANGE "
172                                         " and w.type between $WTS and $WTY " 
173                                         " order by d",
174                     -1, &sql.select_way2, NULL)!=SQLITE_OK)
175         return FALSE;
176
177 if (sqlite3_prepare_v2(db, "select w.wid,w.name as name,"
178                                         "(($LAT-ww.lat)*($LAT-ww.lat))+(($LON-ww.lon)*($LON-ww.lon)) as d,ww.lat,ww.lon "
179                                         " from way_names as w,way as ww where "
180                                         " ww.type between $WTS and $WTY and w.wid=ww.wid and w.name like $NAME "
181                                         " and ww.lat between $LAT-$RANGE and $LAT+$RANGE "
182                                         " and ww.lon between $LON-$RANGE and $LON+$RANGE "
183                                         " union "
184                                         " select w.wid,n.name as name,"
185                                         "(($LAT-ww.lat)*($LAT-ww.lat))+(($LON-ww.lon)*($LON-ww.lon)) as d,ww.lat,ww.lon "
186                                         " from way_names as w, way as ww,way_names_nls as n on w.wid=n.wid where "
187                                         " ww.type between $WTS and $WTY and w.wid=ww.wid and n.name like $NAME "
188                                         " and ww.lat between $LAT-$RANGE and $LAT+$RANGE "
189                                         " and ww.lon between $LON-$RANGE and $LON+$RANGE "
190                                         " order by name limit 100",
191                         -1, &sql.select_way_name_search, NULL)!=SQLITE_OK)
192         return FALSE;
193
194 if (sqlite3_prepare_v2(db, "select wn.t,ilat,ilon from way_n2n as wn,nodes where wid=? and wn.f=? and wn.t=nodes.nid limit 1",
195                     -1, &sql.select_way_next_seg, NULL)!=SQLITE_OK)
196         return FALSE;
197
198 if (sqlite3_prepare_v2(db, "select wn.f,ilat,ilon from way_n2n as wn,nodes where wid=? and wn.t=? and wn.f=nodes.nid limit 1",
199                     -1, &sql.select_way_prev_seg, NULL)!=SQLITE_OK)
200         return FALSE;
201
202 /* Way name */
203 if (sqlite3_prepare_v2(db, "select name from way_names where wid=?", -1, &sql.select_way_name, NULL)!=SQLITE_OK)
204         return FALSE;
205
206 /* Way ref and int_ref */
207 if (sqlite3_prepare_v2(db, "select ref,int_ref from way_ref where rid=?", -1, &sql.select_way_ref, NULL)!=SQLITE_OK)
208         return FALSE;
209
210 /* Get next, prev node + way information. For routing. */
211 if (sqlite3_prepare_v2(db, "select w.wid,w.type,w.flags,w.speed,n.nid,n.rlat,n.rlon,nn.f,nn.t,n.f,n.l "
212                         "from way as w, nodes as n, way_n2n as nn where w.wid=nn.wid and nn.f=n.nid and nn.f=?",
213                     -1, &sql.select_node_next, NULL)!=SQLITE_OK)
214         return FALSE;
215
216 if (sqlite3_prepare_v2(db, "select w.wid,w.type,w.flags,w.speed,n.nid,n.rlat,n.rlon,nn.f,nn.t,n.f,n.l "
217                         "from way as w, nodes as n, way_n2n as nn where w.wid=nn.wid and nn.f=n.nid and nn.t=?",
218                     -1, &sql.select_node_prev, NULL)!=SQLITE_OK)
219         return FALSE;
220
221 return TRUE;
222 }
223
224 void
225 osm_deinit(void)
226 {
227 if (osmdb!=NULL) {
228         sqlite3_finalize(sql.select_way_ref);
229         sqlite3_finalize(sql.select_way_name);
230         sqlite3_finalize(sql.select_way_next_seg);
231         sqlite3_finalize(sql.select_way_prev_seg);
232         sqlite3_finalize(sql.select_way_name_search);
233         sqlite3_finalize(sql.select_way2);
234         sqlite3_finalize(sql.select_place);
235         sqlite3_finalize(sql.select_near_place);
236 }
237 osmdb=NULL;
238 osm_db_ok=FALSE;
239 g_hash_table_destroy(place_cache);
240 g_timer_destroy(dbt);
241 }
242
243 gboolean
244 osm_init(sqlite3 **db)
245 {
246 osm_db_ok=FALSE;
247 place_cache=g_hash_table_new(g_direct_hash, g_direct_equal);
248 dbt=g_timer_new();
249
250 if (!db || !*db) {
251         osmdb=NULL;
252         return FALSE;
253 }
254
255 osmdb=*db;
256 if (osm_db_prepare(osmdb)==FALSE) {
257         g_printerr("Failed to prepare OSM SQL statements:");
258         g_printf("SQLITE: %s\n", sqlite3_errmsg(osmdb));
259         return FALSE;
260 }
261 osm_db_ok=TRUE;
262 return TRUE;
263 }
264
265 /*****************************************************************************/
266
267 osm_way_node *
268 osm_way_node_new(guint id, gint lat, gint lon, gint flags)
269 {
270 osm_way_node *n=g_slice_new(osm_way_node);
271
272 n->id=id;
273 n->lat=lat;
274 n->lon=lon;
275 n->flags=flags;
276 return n;
277 }
278
279 void
280 osm_way_node_free(osm_way_node *n)
281 {
282 if (n)
283         g_slice_free(osm_way_node, n);
284 }
285
286 /**
287  * Free way nodes list 
288  */
289 void
290 osm_way_nodes_free(osm_way *w)
291 {
292 GList *iter;
293
294 if (!w->nodes) 
295         return;
296
297 for (iter=w->nodes; iter!=NULL; iter=iter->next)
298         g_slice_free(osm_way_node, (osm_way_node*)iter->data);
299
300 g_list_free(w->nodes);
301 }
302
303 /**
304  * Free a osm_way structure
305  */
306 void
307 osm_way_free(osm_way *w)
308 {
309 if (!w)
310         return;
311 osm_way_nodes_free(w);
312 if (w->name)
313         g_free(w->name);
314 if (w->ref)
315         g_free(w->ref);
316 if (w->int_ref)
317         g_free(w->int_ref);
318 g_slice_free(osm_way, w);
319 }
320
321 /*****************************************************************************/
322
323 static void
324 osm_place_free(osm_place *p)
325 {
326 if (p->name)
327         g_free(p->name);
328 g_slice_free(osm_place, p);
329 }
330
331 static gboolean
332 osm_place_remove(gpointer k, gpointer v, gpointer ud)
333 {
334 osm_place_free((osm_place *)v);
335 return TRUE;
336 }
337
338 static osm_place *
339 osm_place_new(void)
340 {
341 return g_slice_new0(osm_place);
342 }
343
344 static osm_place *
345 osm_place_cache_lookup(guint32 id)
346 {
347 return g_hash_table_lookup(place_cache, GINT_TO_POINTER(id));
348 }
349
350 static void
351 osm_place_cache_add(osm_place *p)
352 {
353 if (osm_place_cache_lookup(p->id)==NULL)
354         g_hash_table_insert(place_cache, GINT_TO_POINTER(p->id), p);
355 }
356
357 static void
358 osm_place_cache_gc(void)
359 {
360 gint r;
361 r=g_hash_table_foreach_remove(place_cache, osm_place_remove, NULL);
362 }
363
364 static void
365 osm_place_update_distance(osm_place *p, gint lat, gint lon)
366 {
367 gdouble lam, lom;
368
369 lam=(gdouble)((lat-p->lat)*(lat-p->lat));
370 lom=(gdouble)((lon-p->lon)*(lon-p->lon));
371
372 p->dist=sqrt(lam+lom);
373 }
374
375 /**
376  * Get place with given id and distance to current location
377  */
378 gboolean
379 osm_place_get(guint32 id, gint lat, gint lon, osm_place **nr)
380 {
381 osm_place *n;
382
383 n=*nr;
384 n=osm_place_cache_lookup(id);
385 if (n) {
386         g_print("*P!\n");
387         osm_place_update_distance(n, lat, lon);
388         return TRUE;
389 }
390 n=NULL;
391
392 /* XXX: better place for this */
393 if (g_hash_table_size(place_cache)>OSM_PLACE_CACHE_MAX_ITEMS)
394         osm_place_cache_gc();
395
396 sqlite3_clear_bindings(sql.select_place);
397 sqlite3_reset(sql.select_place);
398
399 if (SQLITE_OK != sqlite3_bind_int(sql.select_place, 1, lat) ||
400     SQLITE_OK != sqlite3_bind_int(sql.select_place, 2, lon) ||
401     SQLITE_OK != sqlite3_bind_int(sql.select_place, 3, id)) {
402         g_printerr("Failed to bind values for place\n");
403         return FALSE;
404 }
405
406 if (SQLITE_ROW == sqlite3_step(sql.select_place)) {
407         const gchar *place;
408         guint32 dist;
409
410         n=osm_place_new();
411         place=sqlite3_column_text(sql.select_place, 0);
412         n->name=g_strdup(place);
413         dist=sqlite3_column_int(sql.select_place, 1);
414         n->dist=sqrt((double)dist);
415         n->lat=sqlite3_column_int(sql.select_place, 2);
416         n->lon=sqlite3_column_int(sql.select_place, 3);
417         n->type=sqlite3_column_int(sql.select_place, 4);
418         n->isin_p=sqlite3_column_int(sql.select_place, 5);
419 /*      n->isin_c=sqlite3_column_int(sql.select_place, 6); */
420         return TRUE;
421 }
422 return FALSE;
423 }
424
425 /**
426  * Search for the nearest place with given type
427  */
428 gboolean
429 osm_find_nearest_place(node_type_t type, gint lat, gint lon, osm_place **nr)
430 {
431 gint range;
432 osm_place *n=NULL;
433
434 switch (type) {
435         case NODE_PLACE_SUBURB:
436                 range=95000;
437         break;
438         case NODE_PLACE_CITY:
439         case NODE_PLACE_TOWN:
440                 range=250000;
441         break;
442         case NODE_PLACE_HAMLET:
443         case NODE_PLACE_VILLAGE:
444                 range=100000;
445         break;
446         default:
447                 range=90000;
448         break;
449 }
450
451 sqlite3_clear_bindings(sql.select_near_place);
452 sqlite3_reset(sql.select_near_place);
453
454 if (SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 1, lat) ||
455     SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 2, lon) ||
456     SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 3, type) ||
457     SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 4, range)) {
458         g_printerr("Failed to bind values for near place\n");
459         return FALSE;
460 }
461
462 n=osm_place_new();
463 n->isin_p=n->lat=n->lon=n->dist=0;
464 if (SQLITE_ROW == sqlite3_step(sql.select_near_place)) {
465         const gchar *place;
466         guint32 dist;
467
468         place=sqlite3_column_text(sql.select_near_place, 0);
469         n->name=g_strdup(place);
470         dist=sqlite3_column_int(sql.select_near_place, 1);
471         n->dist=sqrt((double)dist);
472         n->lat=sqlite3_column_int(sql.select_near_place, 2);
473         n->lon=sqlite3_column_int(sql.select_near_place, 3);
474         n->id=sqlite3_column_int(sql.select_near_place, 4);
475         n->isin_p=sqlite3_column_int(sql.select_near_place, 5);
476 /*      n->isin_c=sqlite3_column_int(sql.select_near_place, 6); */
477         n->type=type;
478
479         osm_place_cache_add(n);
480
481         *nr=n;
482         return TRUE;
483 }
484 *nr=n;
485 return FALSE;
486 }
487
488 /*
489  * Way helper 
490  *
491  */
492 static GList *
493 osm_find_nearest_way_nodes(gint lat, gint lon, guint range)
494 {
495 GList *ways=NULL;
496 osm_way *w;
497 gulong tms;
498 guint wc=0;
499
500 sqlite3_reset(sql.select_way2);
501 sqlite3_clear_bindings(sql.select_way2);
502
503 if (SQLITE_OK != sqlite3_bind_int(sql.select_way2, 1, lat) ||
504     SQLITE_OK != sqlite3_bind_int(sql.select_way2, 2, lon) ||
505     SQLITE_OK != sqlite3_bind_int(sql.select_way2, 3, range) ||
506     SQLITE_OK != sqlite3_bind_int(sql.select_way2, 4, WAY_ROAD_START) ||
507     SQLITE_OK != sqlite3_bind_int(sql.select_way2, 5, WAY_ROAD_END)) {
508         g_printerr("Failed to bind values for way\n");
509         return NULL;
510 }
511
512 #ifdef DEBUG_OSM_TIME
513 g_timer_start(dbt);
514 #endif
515
516 while (SQLITE_ROW == sqlite3_step(sql.select_way2)) {
517         guint32 dist;
518         gint lat, lon;
519
520         wc++;
521         w=g_slice_new0(osm_way);
522         w->id=sqlite3_column_int(sql.select_way2, 0);
523         w->type=sqlite3_column_int(sql.select_way2, 1);
524         w->nodecnt=sqlite3_column_int(sql.select_way2, 2);
525         w->flags=sqlite3_column_int(sql.select_way2, 3);
526         dist=sqlite3_column_int(sql.select_way2, 4);
527         w->dist=sqrt((gdouble)dist);
528         w->f=sqlite3_column_int(sql.select_way2, 5);
529         w->t=sqlite3_column_int(sql.select_way2, 6);
530
531         lat=sqlite3_column_int(sql.select_way2, 7);
532         lon=sqlite3_column_int(sql.select_way2, 8);
533
534         w->node_f=osm_way_node_new(w->f, lat, lon, 0);
535
536         ways=g_list_prepend(ways, w);
537 }
538
539 #ifdef DEBUG_OSM_TIME
540 g_timer_stop(dbt);
541 g_printf("Query took: %f sec, found: %d ways\n", g_timer_elapsed(dbt, &tms), wc);
542 #endif
543
544 return ways;
545 }
546
547 /*****************************************************************************/
548
549 GSList *
550 osm_get_route_node(guint nid, osm_node_direction d)
551 {
552 GSList *r=NULL;
553 osm_way *w;
554 guint wc=0;
555 sqlite3_stmt *psql=NULL;
556
557 switch (d) {
558         case OSM_NODE_NEXT:
559                 psql=sql.select_node_next;
560         break;
561         case OSM_NODE_PREV:
562                 psql=sql.select_node_prev;
563         break;
564         default:
565                 g_assert_not_reached();
566         break;
567 }
568
569 sqlite3_reset(psql);
570 sqlite3_clear_bindings(psql);
571
572 if (SQLITE_OK != sqlite3_bind_int(psql, 1, nid)) {
573         g_printerr("Failed to bind values for route node\n");
574         return NULL;
575 }
576
577 while (SQLITE_ROW == sqlite3_step(psql)) {
578         gdouble lat, lon;
579
580         wc++;
581         w=g_slice_new0(osm_way);
582         w->id=sqlite3_column_int(psql, 0);
583         w->type=sqlite3_column_int(psql, 1);
584         w->flags=sqlite3_column_int(psql, 2);
585         w->speed=sqlite3_column_int(psql, 3);
586
587         lat=sqlite3_column_double(psql, 5);
588         lon=sqlite3_column_double(psql, 6);
589
590         w->f=sqlite3_column_int(psql, 7);
591         w->t=sqlite3_column_int(psql, 8);
592 #if 0
593         w->node=
594         w->node->flags=sqlite3_column_int(psql, 9);
595         w->node->links=sqlite3_column_int(psql, 10);
596 #endif
597
598         r=g_slist_prepend(r, w);
599 }
600
601 return r;
602 }
603
604
605 /*****************************************************************************/
606 gboolean 
607 osm_way_distance(gint lat, gint lon, osm_way_node *f, osm_way_node *t, gdouble *d)
608 {
609 if (!f) {
610         return FALSE;
611 }
612
613 if (!t) {
614         return FALSE;
615 }
616
617 return distance_point_to_line((gdouble)lon, (gdouble)lat, (gdouble)f->lon, (gdouble)f->lat, (gdouble)t->lon, (gdouble)t->lat, d);
618 }
619
620 /**
621  * Search for the nearest way (road)
622  * - First search for ways with nearest node
623  * - If only one is returned then we are done.
624  * - If more than one, go trough the results:
625  *   - Load nodes for the way, check prev/next nodes
626  *   - Store result if closer than before
627  * - Return closest way
628  */
629
630 #define START_DIST (900000.0)
631
632 osm_way *
633 osm_find_nearest_way(gint lat, gint lon)
634 {
635 GList *iter;
636 GList *w=NULL;
637 guint range=OSM_RANGE_START;
638 osm_way *cw=NULL;
639 gdouble pdist=START_DIST, dist_n, dist_p;
640
641 while ((w=osm_find_nearest_way_nodes(lat, lon, range))==NULL && range<=OSM_RANGE_STOP) {
642         range+=OSM_RANGE_STEP;
643         g_printf("Trying with range: %d\n", range);
644 }
645 #ifdef DEBUG_OSM
646 g_printf("Found %d ways withing range %d\n", g_list_length(w), range);
647 #endif
648
649 if (g_list_length(w)==0)
650         return NULL;
651
652 for (iter=w; iter!=NULL; iter=iter->next) {
653         osm_way_node *wnn;
654         osm_way_node *wnp;
655         osm_way *way=(osm_way*)iter->data;
656
657 #ifdef DEBUG_OSM
658         g_printf("Way: %d (%d) has %d nodes, nearest is %d,%d\n", 
659                 way->id, way->type, way->nodecnt, way->f, way->t);
660 #endif
661
662         way->node_t=NULL;
663
664         wnn=osm_way_get_next_node(way);
665         if (osm_way_distance(lat, lon, way->node_f, wnn, &dist_n)==FALSE) {
666                 osm_way_node_free(wnn);
667                 dist_n=START_DIST;
668         } else if (dist_n<pdist) {
669                 pdist=dist_n;
670                 cw=way;
671                 way->distance=dist_n;
672                 way->node_t=wnn;
673                 g_printf("#1 distance: %f (%f)\n", dist_n, pdist);
674         }
675
676         wnp=osm_way_get_prev_node(way);
677         if (osm_way_distance(lat, lon, way->node_f, wnp, &dist_p)==FALSE) {
678                 osm_way_node_free(wnp);
679                 dist_p=START_DIST;
680         } else if (dist_p<pdist) {
681                 pdist=dist_p;
682                 cw=way;
683                 way->distance=dist_n;
684                 if (way->node_t) {
685                         osm_way_node_free(wnn);
686                 }
687                 way->node_t=wnp;
688                 g_printf("#2 distance: %f (%f)\n", dist_p, pdist);
689         }
690
691 #ifdef DEBUG_OSM
692         g_printf("Found close way, distance: %f %f (%f)\n", dist_n, dist_p, pdist);
693 #endif
694
695         if (!cw) {
696                 osm_way_free(way);
697                 way=NULL;
698         }
699 }
700
701 g_list_free(w);
702 if (cw==NULL)
703         return NULL;
704
705 osm_way_get_name(cw);
706 if (cw->type==WAY_MOTORWAY || cw->type==WAY_TRUNK || 
707         cw->type==WAY_PRIMARY || cw->type==WAY_SECONDARY ||
708         cw->type==WAY_TERTIARY) {
709                 osm_way_get_ref(cw);
710 }
711
712 #ifdef DEBUG_OSM
713 g_printf("BEST WAY(%d): %s [%s][%s]\n", 
714         cw->id, cw->name, cw->ref, cw->int_ref);
715 g_printf("\tType: %d Flags: %d Nodes: %d Dist: %f\n", 
716         cw->type, cw->flags, cw->nodecnt, cw->dist);
717 g_printf("\tNF: %d NT: %d Distance: %f\n", 
718         cw->f, 
719         cw->t, 
720         cw->distance);
721 #endif
722
723 return cw;
724 }
725
726 /* XXX: These two should be combined to save memory */
727 /**
728  * Get previous node/segment of given way node
729  *
730  */
731 osm_way_node *
732 osm_way_get_prev_node(osm_way *w)
733 {
734 sqlite3_reset(sql.select_way_prev_seg);
735 sqlite3_clear_bindings(sql.select_way_prev_seg);
736
737 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_prev_seg, 1, w->id) ||
738         SQLITE_OK != sqlite3_bind_int(sql.select_way_prev_seg, 2, w->f)  ) {
739         g_printerr("Failed to bind values for prev seg\n");
740         return NULL;
741 }
742
743 if (SQLITE_ROW == sqlite3_step(sql.select_way_prev_seg)) {
744         return osm_way_node_new(
745                 sqlite3_column_int(sql.select_way_prev_seg, 0),
746                 sqlite3_column_int(sql.select_way_prev_seg, 1),
747                 sqlite3_column_int(sql.select_way_prev_seg, 2),
748                 0);
749 }
750
751 return NULL;
752 }
753
754 /**
755  * Get next node/segment of given way node
756  *
757  */
758 osm_way_node *
759 osm_way_get_next_node(osm_way *w)
760 {
761 sqlite3_reset(sql.select_way_next_seg);
762 sqlite3_clear_bindings(sql.select_way_next_seg);
763
764 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_next_seg, 1, w->id) ||
765         SQLITE_OK != sqlite3_bind_int(sql.select_way_next_seg, 2, w->f)  ) {
766         g_printerr("Failed to bind values for next seg\n");
767         return NULL;
768 }
769
770 if (SQLITE_ROW == sqlite3_step(sql.select_way_next_seg)) {
771         return osm_way_node_new(
772                 sqlite3_column_int(sql.select_way_next_seg, 0),
773                 sqlite3_column_int(sql.select_way_next_seg, 1),
774                 sqlite3_column_int(sql.select_way_next_seg, 2),
775                 0);
776 }
777
778 return NULL;
779 }
780
781 /**
782  * Get list of nodes for given way
783  *
784  */
785 gboolean
786 osm_way_get_nodes(osm_way *w)
787 {
788 if (w->nodes!=NULL)
789         return TRUE;
790
791 sqlite3_reset(sql.select_way_nodes);
792 sqlite3_clear_bindings(sql.select_way_nodes);
793
794 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_nodes, 1, w->id)) {
795         g_printerr("Failed to bind values way nodes\n");
796         return FALSE;
797 }
798
799 while (SQLITE_ROW == sqlite3_step(sql.select_way_nodes)) {
800         osm_way_node *n;
801
802         n=g_slice_new(osm_way_node);
803         n->id=sqlite3_column_int(sql.select_way_nodes, 0);
804         n->lat=sqlite3_column_int(sql.select_way_nodes, 1);
805         n->lon=sqlite3_column_int(sql.select_way_nodes, 2);
806         w->nodes=g_list_append(w->nodes, n);
807 }
808
809 return (w->nodes==NULL) ? FALSE : TRUE;
810 }
811
812 /**
813  * Get way name
814  *
815  */
816 gboolean
817 osm_way_get_name(osm_way *w)
818 {
819 sqlite3_reset(sql.select_way_name);
820 sqlite3_clear_bindings(sql.select_way_name);
821
822 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_name, 1, w->id)) {
823         g_printerr("Failed to bind values for way name\n");
824         return FALSE;
825 }
826
827 if (SQLITE_ROW == sqlite3_step(sql.select_way_name)) {
828         const gchar *place;
829         place=sqlite3_column_text(sql.select_way_name, 0);
830         w->name=g_strdup(place);
831 }
832 return FALSE;
833 }
834
835 #if 0
836 gboolean
837 osm_way_get_name_nls(osm_way *w)
838 {
839 sqlite3_reset(sql.select_way_name_nls);
840 sqlite3_clear_bindings(sql.select_way_name_nls);
841
842 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_name_nls, 1, w->id) ||
843         SQLITE_OK != sqlite3_bind_) {
844         g_printerr("Failed to bind values for way name nls\n");
845         return FALSE;
846 }
847
848 if (SQLITE_ROW == sqlite3_step(sql.select_way_name_nls)) {
849         const gchar *place;
850         place=sqlite3_column_text(sql.select_way_name_nls, 0);
851         w->name=g_strdup(place);
852 }
853 return FALSE;
854 }
855 #endif
856
857
858 /**
859  * Get Way ref and int_ref
860  *
861  */
862 gboolean
863 osm_way_get_ref(osm_way *w)
864 {
865 sqlite3_reset(sql.select_way_ref);
866 sqlite3_clear_bindings(sql.select_way_ref);
867
868 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_ref, 1, w->id)) {
869         g_printerr("Failed to bind values for way ref\n");
870         return FALSE;
871 }
872
873 if (SQLITE_ROW == sqlite3_step(sql.select_way_ref)) {
874         const gchar *ref, *int_ref;
875         ref=sqlite3_column_text(sql.select_way_ref, 0);
876         int_ref=sqlite3_column_text(sql.select_way_ref, 1);
877         w->ref=g_strdup(ref);
878         w->int_ref=g_strdup(int_ref);
879 }
880 return FALSE;
881 }
882
883 /******************************************************************************/
884
885 /**
886  * Try to figure out where the given lat,lon is. Fills in the given struct,
887  * with street, secondary (suburb) and primary (city,town,village) location.
888  * Will try to minimize the amount of database access by skipping queries
889  * if we haven't moved or if we don't know where we are.
890  *
891  */
892 gboolean 
893 osm_get_location_data(gint lat, gint lon, gfloat heading, osm_location *map_loc)
894 {
895 gdouble dist;
896 gboolean check_place=FALSE;
897 gulong d;
898
899 if (map_loc->valid==FALSE) {
900         map_loc->lat=lat;
901         map_loc->lon=lon;
902         map_loc->valid=TRUE;
903         d=way_dist_range*5;
904 } else {
905         d=calculate_idistance(lat,lon,map_loc->lat,map_loc->lon);
906 }
907
908 /* Check if we are still near the same way as last time */
909 if (map_loc->street && osm_way_distance(lat, lon, map_loc->street->node_f, map_loc->street->node_t, &dist)==TRUE) {
910         /* We are probably on the same way as last time */
911         if ( (dist>(gdouble)way_dist_range) || (fabs(heading-map_loc->heading)>10.0)) {
912                 /* We have moved a large amount, check way again */
913                 g_printf("*** dist %f over range, checking again\n", dist);
914                 osm_way_free(map_loc->street);
915                 map_loc->street=osm_find_nearest_way(lat, lon);
916                 check_place=TRUE;
917                 map_loc->changed=TRUE;
918         } else {
919 #if 0
920                 g_printf("*** No change in location: %f %d\n", dist, way_dist_range);
921 #endif
922                 /* We are still on the same way as last time */
923                 check_place=FALSE;
924                 map_loc->changed=FALSE;
925         }
926         map_loc->lat=lat;
927         map_loc->lon=lon;
928 } else {
929         /* We didn't know our location, so check it, but only if we have moved */
930         if (d>way_dist_range) {
931                 g_print("*** Must check location\n");
932                 check_place=TRUE;
933                 osm_way_free(map_loc->street);
934                 map_loc->street=osm_find_nearest_way(lat, lon);
935 #if 0
936                 map_loc->lat=lat;
937                 map_loc->lon=lon;
938 #endif
939         } 
940
941         if (!map_loc->street) {
942                 g_print("*** Street not known\n");
943                 map_loc->nfcnt++;
944                 map_loc->changed=TRUE;
945         } else {
946                 g_print("*** Street known\n");
947                 map_loc->nfcnt=0;
948                 map_loc->changed=TRUE;
949                 check_place=TRUE;
950         }
951 }
952
953 if (map_loc->changed==TRUE) {
954         map_loc->heading=heading;
955 }
956
957 #if 0
958 g_printf("NFC: %d\n", map_loc->nfcnt);
959 g_printf("D: %ld %ld\n", d,(gulong)way_dist_range);
960 #endif
961
962 if (check_place==TRUE && d>way_dist_range*4) {
963         gboolean fs;
964
965         fs=osm_find_nearest_place(NODE_PLACE_SUBURB, lat, lon, &map_loc->secondary);
966         if (fs==TRUE && map_loc->secondary && map_loc->secondary->isin_p!=0) {
967                 if (osm_place_get(map_loc->secondary->isin_p, lat, lon, &(map_loc->primary))==FALSE) {
968                         if (osm_find_nearest_place(NODE_PLACE_CITY, lat, lon, &map_loc->primary)==TRUE)
969                                 g_printf("Near city: %s\n", map_loc->primary->name);
970                         else if (osm_find_nearest_place(NODE_PLACE_TOWN, lat, lon, &map_loc->primary)==TRUE)
971                                 g_printf("Near town: %s\n", map_loc->primary->name);
972                         else
973                                 g_printf("Unknown\n");
974                 } else {
975                         g_printf("In: %s\n", map_loc->primary ? map_loc->primary->name : "?");
976                 }
977         } else if (map_loc->street && map_loc->street->isin_p!=0) {
978                 if (osm_place_get(map_loc->street->isin_p, lat, lon, &map_loc->primary)==FALSE) {
979                         g_printf("Street location not know.\n");
980                 } else {
981                         g_printf("Street is in: %s\n", map_loc->primary ? map_loc->primary->name : "?");
982                 }
983         } else {
984                 if (osm_find_nearest_place(NODE_PLACE_CITY, lat, lon, &map_loc->primary)==TRUE)
985                         g_printf("Near city: %s\n", map_loc->primary->name);
986                 else if (osm_find_nearest_place(NODE_PLACE_TOWN, lat, lon, &map_loc->primary)==TRUE)
987                         g_printf("Near town: %s\n", map_loc->primary->name);
988                 else
989                         g_printf("Unknown\n");
990
991         }
992 }
993
994 return map_loc->street ? TRUE : FALSE;
995 }
996
997 /**
998  * osm_way_search
999  *
1000  * Search for a street(way) starting with given 'text', next given lat/lon
1001  *
1002  */
1003 gboolean
1004 osm_way_search(gdouble lat, gdouble lon, gchar *text, GtkListStore **store)
1005 {
1006 GtkTreeIter iter;
1007 gchar *ltext=NULL;
1008 guint rows=0;
1009 gchar tmp1[16], tmp2[16];
1010 gdouble range=6;
1011
1012 g_printf("Way Search: [%s] around %.6f %.6f\n", text, lat, lon);
1013
1014 ltext=g_strdup_printf("%s%%", text);
1015
1016 if (SQLITE_OK != sqlite3_bind_double(sql.select_way_name_search, 1, lat) ||
1017     SQLITE_OK != sqlite3_bind_double(sql.select_way_name_search, 2, lon) ||
1018     SQLITE_OK != sqlite3_bind_int(sql.select_way_name_search,    3, WAY_ROAD_START) ||
1019     SQLITE_OK != sqlite3_bind_int(sql.select_way_name_search,    4, WAY_ROAD_END) ||
1020     SQLITE_OK != sqlite3_bind_double(sql.select_way_name_search, 6, range) ||
1021         SQLITE_OK != sqlite3_bind_text(sql.select_way_name_search,   5, ltext, -1, SQLITE_TRANSIENT)) {
1022                 g_printerr("Failed to bind values for sql.select_way_name_search\n");
1023                 sqlite3_clear_bindings(sql.select_way_name_search);
1024                 g_free(ltext);
1025                 return FALSE;
1026 }
1027
1028 if (ltext)
1029         g_free(ltext);
1030
1031 *store = gtk_list_store_new(ITEM_NUM_COLUMNS, 
1032                                 G_TYPE_INT,             /* ID */
1033                                 G_TYPE_INT,             /*  */
1034                                 G_TYPE_DOUBLE,  /* Latitude */
1035                                 G_TYPE_DOUBLE,  /* Longitude */
1036                                 G_TYPE_DOUBLE,  /* Distance */
1037                                 G_TYPE_STRING,  /* Lat/Lon */
1038                                 G_TYPE_STRING,  /* Label */
1039                                 G_TYPE_STRING,  /* Desc. */
1040                                 G_TYPE_STRING,  /* Category */
1041                                 G_TYPE_STRING,  /* Dummy */
1042                                 G_TYPE_STRING); /* Dummy */
1043
1044 while (SQLITE_ROW == sqlite3_step(sql.select_way_name_search)) {
1045         gdouble rlat, rlon, dist;
1046
1047         rlat=sqlite3_column_double(sql.select_way_name_search, 3);
1048         rlon=sqlite3_column_double(sql.select_way_name_search, 4);
1049         lat_format(_degformat, rlat, tmp1);
1050         lon_format(_degformat, rlon, tmp2);
1051         dist=calculate_distance(lat, lon, rlat, rlon) * UNITS_CONVERT[_units];
1052
1053         gtk_list_store_append(*store, &iter);
1054         gtk_list_store_set(*store, &iter,
1055                 ITEM_ID, sqlite3_column_int(sql.select_way_name_search, 0),
1056                 ITEM_LAT, rlat,
1057                 ITEM_LON, rlon,
1058                 ITEM_DIST, dist,
1059                 ITEM_LATLON, g_strdup_printf("%s, %s", tmp1, tmp2),
1060                 ITEM_LABEL, sqlite3_column_text(sql.select_way_name_search, 1),
1061                 -1);
1062         rows++;
1063 }
1064
1065 g_printf("Found: %d items\n", rows);
1066
1067 sqlite3_reset(sql.select_way_name_search);
1068 sqlite3_clear_bindings(sql.select_way_name_search);
1069
1070 return TRUE;
1071 }
1072
1073