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