]> err.no Git - mapper/blob - src/osm-db.c
Remove warnings
[mapper] / src / osm-db.c
1 #define _GNU_SOURCE
2
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <string.h>
6 #include <strings.h>
7 #include <sys/types.h>
8 #include <sys/stat.h>
9 #include <fcntl.h>
10 #include <math.h>
11 #include <glib.h>
12 #include <glib/gstdio.h>
13 #include <sqlite3.h>
14 #include <expat.h>
15
16 #include "osm.h"
17 #include "latlon.h"
18
19 struct sql_select_stmt {
20         sqlite3_stmt *select_way;
21         sqlite3_stmt *select_way_nodes;
22         sqlite3_stmt *select_way_name;
23         sqlite3_stmt *select_way_ref;
24         sqlite3_stmt *select_place;
25         sqlite3_stmt *select_near_place;
26 };
27 static struct sql_select_stmt sql;
28
29 gboolean osm_way_get_nodes(osm_way *w);
30 gboolean osm_way_get_name(osm_way *w);
31 gboolean osm_way_get_ref(osm_way *w);
32
33 gboolean
34 osm_db_prepare(sqlite3 *db)
35 {
36 /* Place */
37 /* Select nearest place inside lat,lon+-range */
38 if (sqlite3_prepare_v2(db, "select name,(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LON-lon)) as dist,"
39                                         " lat,lon,places.nid,isin "
40                                         " from places,nodes where type=$TYPE "
41                                         " and nodes.nid=places.nid "
42                                         " and lat between $LAT-$RANGE and $LAT+$RANGE"
43                                         " and lon between $LON-$RANGE and $LON+$RANGE order by dist limit 1",
44                     -1, &sql.select_near_place, NULL)!=SQLITE_OK)
45         return FALSE;
46 /* Select place name, distance, location, parent-place and type with given ID */
47
48 if (sqlite3_prepare_v2(db, "select name,(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LON-lon)) as dist,"
49                                         " lat,lon,type,isin "
50                                         " from places,nodes where "
51                                         " nodes.nid=places.nid "
52                                         " and places.nid=$NID order by dist limit 1",
53                     -1, &sql.select_place, NULL)!=SQLITE_OK)
54         return FALSE;
55
56 /* Ways */
57 /* Select neareset ways inside lat,lon+-range */
58 if (sqlite3_prepare_v2(db, "select wid,type,nodes,flags,"
59                                         "(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LON-lon)) as dist, num"
60                                         " from way,way_seg,nodes"
61                                         " where wid=wsid and way_seg.node=nodes.nid "
62                                         " and lat between $LAT-$RANGE and $LAT+$RANGE "
63                                         " and lon between $LON-$RANGE and $LON+$RANGE "
64                                         " order by dist",
65                     -1, &sql.select_way, NULL)!=SQLITE_OK)
66         return FALSE;
67
68 /* Select way nodes */
69 if (sqlite3_prepare_v2(db, "select num,lat,lon from way_seg,nodes where wsid=? and way_seg.node=nodes.nid order by num",
70                     -1, &sql.select_way_nodes, NULL)!=SQLITE_OK)
71         return FALSE;
72
73 /* Way name and ref */
74 if (sqlite3_prepare_v2(db, "select name from way_names where wid=?",
75                     -1, &sql.select_way_name, NULL)!=SQLITE_OK)
76         return FALSE;
77
78 if (sqlite3_prepare_v2(db, "select ref,int_ref from way_ref where rid=?",
79                     -1, &sql.select_way_ref, NULL)!=SQLITE_OK)
80         return FALSE;
81
82 return TRUE;
83 }
84
85 gboolean
86 osm_init()
87 {
88 return TRUE;
89 }
90
91 /**
92  * Free way nodes list 
93  */
94 void
95 osm_way_nodes_free(osm_way *w)
96 {
97 GList *iter;
98
99 if (!w->nodes) 
100         return;
101
102 for (iter=w->nodes; iter!=NULL; iter=iter->next)
103         g_slice_free(osm_way_node, (osm_way_node*)iter->data);
104
105 g_list_free(w->nodes);
106 }
107
108 /**
109  * Free a osm_way structure
110  */
111 void
112 osm_way_free(osm_way *w)
113 {
114 if (!w)
115         return;
116 osm_way_nodes_free(w);
117 if (w->name)
118         g_free(w->name);
119 if (w->ref)
120         g_free(w->ref);
121 if (w->int_ref)
122         g_free(w->int_ref);
123 g_slice_free(osm_way, w);
124 }
125
126 /**
127  * Get place with given id and distance to current location
128  */
129 gboolean
130 osm_place_get(guint32 id, gint lat, gint lon, osm_place *n)
131 {
132 sqlite3_clear_bindings(sql.select_place);
133 sqlite3_reset(sql.select_place);
134
135 if (SQLITE_OK != sqlite3_bind_int(sql.select_place, 1, lat) ||
136     SQLITE_OK != sqlite3_bind_int(sql.select_place, 2, lon) ||
137     SQLITE_OK != sqlite3_bind_int(sql.select_place, 3, id)) {
138         g_printerr("Failed to bind values for place\n");
139         return FALSE;
140 }
141
142 if (SQLITE_ROW == sqlite3_step(sql.select_place)) {
143         const gchar *place;
144         guint32 dist;
145
146         place=sqlite3_column_text(sql.select_place, 0);
147         n->name=g_strdup(place);
148         dist=sqlite3_column_int(sql.select_place, 1);
149         n->dist=sqrt((double)dist);
150         n->lat=sqlite3_column_int(sql.select_place, 2);
151         n->lon=sqlite3_column_int(sql.select_place, 3);
152         n->type=sqlite3_column_int(sql.select_place, 4);
153         n->isin=sqlite3_column_int(sql.select_place, 5);
154         return TRUE;
155 }
156 return FALSE;
157 }
158
159 /**
160  * Search for the nearest place, type
161  */
162 gboolean
163 osm_find_nearest_place(node_type_t type, gint lat, gint lon, osm_place *n)
164 {
165 gint range;
166
167 switch (type) {
168         case NODE_PLACE_SUBURB:
169                 range=95000;
170         break;
171         case NODE_PLACE_CITY:
172         case NODE_PLACE_TOWN:
173                 range=250000;
174         break;
175         case NODE_PLACE_HAMLET:
176         case NODE_PLACE_VILLAGE:
177                 range=100000;
178         break;
179         default:
180                 range=90000;
181         break;
182 }
183
184 sqlite3_clear_bindings(sql.select_near_place);
185 sqlite3_reset(sql.select_near_place);
186
187 if (SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 1, lat) ||
188     SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 2, lon) ||
189     SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 3, type) ||
190     SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 4, range)) {
191         g_printerr("Failed to bind values for near place\n");
192         return FALSE;
193 }
194
195 if (n->name) {
196         g_free(n->name);
197         n->name=NULL;
198 }
199 n->isin=n->lat=n->lon=n->dist=0;
200 if (SQLITE_ROW == sqlite3_step(sql.select_near_place)) {
201         const gchar *place;
202         guint32 dist;
203
204         place=sqlite3_column_text(sql.select_near_place, 0);
205         n->name=g_strdup(place);
206         dist=sqlite3_column_int(sql.select_near_place, 1);
207         n->dist=sqrt((double)dist);
208         n->lat=sqlite3_column_int(sql.select_near_place, 2);
209         n->lon=sqlite3_column_int(sql.select_near_place, 3);
210         n->id=sqlite3_column_int(sql.select_near_place, 4);
211         n->isin=sqlite3_column_int(sql.select_near_place, 5);
212         n->type=type;
213
214         return TRUE;
215 }
216 return FALSE;
217 }
218
219 /* Way helper */
220 static GList *
221 osm_find_nearest_way_nodes(gint lat, gint lon, guint range)
222 {
223 GList *ways=NULL;
224 osm_way *w;
225
226 sqlite3_reset(sql.select_way);
227 sqlite3_clear_bindings(sql.select_way);
228
229 if (SQLITE_OK != sqlite3_bind_int(sql.select_way, 1, lat) ||
230     SQLITE_OK != sqlite3_bind_int(sql.select_way, 2, lon) ||
231     SQLITE_OK != sqlite3_bind_int(sql.select_way, 3, range)) {
232         g_printerr("Failed to bind values for way\n");
233         return NULL;
234 }
235
236 while (SQLITE_ROW == sqlite3_step(sql.select_way)) {
237         guint32 dist;
238
239         w=g_slice_new0(osm_way);
240         w->id=sqlite3_column_int(sql.select_way, 0);
241         w->type=sqlite3_column_int(sql.select_way, 1);
242         w->nodecnt=sqlite3_column_int(sql.select_way, 2);
243         w->flags=sqlite3_column_int(sql.select_way, 3);
244         dist=sqlite3_column_int(sql.select_way, 4);
245         w->dist=sqrt((gdouble)dist);
246         w->node_num=sqlite3_column_int(sql.select_way, 5);
247         ways=g_list_prepend(ways, w);
248 }
249
250 return ways;
251 }
252
253 static gdouble magnitude(gdouble x1, gdouble y1, gdouble x2, gdouble y2)
254 {
255 gdouble x,y;
256 x=x2-x1;
257 y=y2-y1;
258
259 return sqrt((x*x)+(y*y));
260 }
261
262 gboolean distance_point_to_line(gint x, gint y, gint x1, gint y1, gint x2, gint y2, gdouble *d)
263 {
264 gdouble lm,u,tmp;
265 gdouble ix,iy;
266
267 lm=magnitude((gdouble)x1,(gdouble)y1,(gdouble)x2,(gdouble)y2);
268  
269 tmp=(gdouble)((x-x1)*(x2-x1))+((y-y1)*(y2-y1));
270 u=tmp/(lm*lm);
271
272 if (u<0.0f || u>1.0f)
273         return FALSE;
274  
275 ix=(gdouble)x1+u*(gdouble)(x2-x1);
276 iy=(gdouble)y1+u*(gdouble)(y2-y1);
277  
278 *d=magnitude((gdouble)x,(gdouble)y, ix, iy);
279  
280 return TRUE;
281 }
282
283 gboolean osm_way_distance(gint lat, gint lon, osm_way_node *f, osm_way_node *t, gdouble *d)
284 {
285 if (!f || !t)
286         return FALSE;
287
288 return distance_point_to_line(lon, lat, f->lon, f->lat, t->lon, t->lat, d);
289 }
290
291 /**
292  * Search for the nearest way (road)
293  * - First search for ways with nearest node
294  * - If only one is returned then we are done.
295  * - If more than one, go trough the results:
296  *   - Load nodes for the way, check prev/next nodes
297  *   - Store result if closer than before
298  * - Return closest way
299  */
300 osm_way *
301 osm_find_nearest_way(gint lat, gint lon)
302 {
303 GList *iter;
304 GList *w=NULL;
305 guint range=8192;
306 osm_way *cw=NULL;
307
308 while ((w=osm_find_nearest_way_nodes(lat, lon, range))==NULL && range<=65536) {
309         range=range<<1;
310         g_printf("Trying with range: %d\n", range);
311 }
312
313 g_printf("Found ways: %d\n", g_list_length(w));
314
315 switch (g_list_length(w)) {
316         case 0:
317                 return NULL;
318         break;
319         default:
320         {
321                 gdouble pdist=900000.0, pndist=9000000.0;
322
323                 for (iter=w; iter!=NULL; iter=iter->next) {
324                         osm_way_node *wnf;
325                         osm_way_node *wnt;
326
327                         osm_way *way=(osm_way*)iter->data;
328
329                         g_printf("WAY %d (%d) HAS %d NODES, nearest is %d\n", 
330                                 way->id, way->type, way->nodecnt, way->node_num);
331
332                         if (osm_way_get_nodes(way)==FALSE)
333                                 continue;
334
335                         if (way->nodes==0) {
336                                 g_printerr("Way with 0 nodes ? Skipping\n");
337                                 continue;
338                         }
339
340                         wnf=g_list_nth_data(way->nodes, way->node_num);
341                         if (!wnf) {
342                                 osm_way_free(way);
343                                 continue;
344                         }
345
346                         if ( (way->node_num==way->nodecnt) || (way->node_num==0)) {
347                                 wnt=g_list_nth_data(way->nodes, way->node_num==way->nodecnt ? way->nodecnt-1 : 1);
348                                 if (osm_way_distance(lat, lon, wnf, wnt, &pndist)==FALSE) {
349                                         osm_way_free(way);
350                                         continue;
351                                 }
352                         } else {
353                                 wnt=g_list_nth_data(way->nodes, way->node_num-1);
354                                 if (osm_way_distance(lat, lon, wnf, wnt, &pndist)==FALSE) {
355                                         wnt=g_list_nth_data(way->nodes, way->node_num+1);
356                                         if (osm_way_distance(lat, lon, wnf, wnt, &pndist)==FALSE) {
357                                                 osm_way_free(way);
358                                                 continue;
359                                         }
360                                 }
361                         }
362
363                         if (pndist<pdist) {
364                                 g_printf("Found close way, distance: %f (Previous distance: %f)\n", pndist, pdist);
365                                 pdist=pndist;
366                                 way->node_f=wnf;
367                                 way->node_t=wnt;
368                                 way->distance=pndist;
369                                 cw=way;
370                         } else {
371                                 g_printf("Way is not closer, freeing\n");
372                                 osm_way_free(way);
373                                 way=NULL;
374                         }
375                 }
376         }
377         break;
378 }
379
380 g_list_free(w);
381 if (cw==NULL)
382         return NULL;
383
384 osm_way_get_name(cw);
385 if (cw->type==WAY_MOTORWAY || cw->type==WAY_TRUNK || 
386         cw->type==WAY_PRIMARY || cw->type==WAY_SECONDARY ||
387         cw->type==WAY_TERTIARY) {
388                 osm_way_get_ref(cw);
389 }
390
391 g_printf("BEST WAY(%d): %s (%s,%s)\n", 
392         cw->id, cw->name, cw->ref, cw->int_ref);
393 g_printf("\tT: %d F: %d N: %d D: %f\n", 
394         cw->type, cw->flags, cw->nodecnt, cw->dist);
395 g_printf("\tNF: %d NT: %d DT %f\n", 
396         cw->node_f->num, 
397         cw->node_t->num, cw->distance);
398
399 return cw;
400 }
401
402 /**
403  * Get list of nodes for given way
404  */
405 gboolean
406 osm_way_get_nodes(osm_way *w)
407 {
408 if (w->nodes!=NULL)
409         return TRUE;
410
411 sqlite3_reset(sql.select_way_nodes);
412 sqlite3_clear_bindings(sql.select_way_nodes);
413
414 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_nodes, 1, w->id)) {
415         g_printerr("Failed to bind values way nodes\n");
416         return FALSE;
417 }
418
419 while (SQLITE_ROW == sqlite3_step(sql.select_way_nodes)) {
420         osm_way_node *n;
421
422         n=g_slice_new(osm_way_node);
423         n->num=sqlite3_column_int(sql.select_way_nodes, 0);
424         n->lat=sqlite3_column_int(sql.select_way_nodes, 1);
425         n->lon=sqlite3_column_int(sql.select_way_nodes, 2);
426         w->nodes=g_list_append(w->nodes, n);
427 }
428
429 return (w->nodes==NULL) ? FALSE : TRUE;
430 }
431
432 gboolean
433 osm_way_get_name(osm_way *w)
434 {
435 sqlite3_reset(sql.select_way_name);
436 sqlite3_clear_bindings(sql.select_way_name);
437
438 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_name, 1, w->id)) {
439         g_printerr("Failed to bind values for way name\n");
440         return FALSE;
441 }
442
443 if (SQLITE_ROW == sqlite3_step(sql.select_way_name)) {
444         const gchar *place;
445         place=sqlite3_column_text(sql.select_way_name, 0);
446         w->name=g_strdup(place);
447 }
448 return FALSE;
449 }
450
451 gboolean
452 osm_way_get_ref(osm_way *w)
453 {
454 sqlite3_reset(sql.select_way_ref);
455 sqlite3_clear_bindings(sql.select_way_ref);
456
457 if (SQLITE_OK != sqlite3_bind_int(sql.select_way_ref, 1, w->id)) {
458         g_printerr("Failed to bind values for way ref\n");
459         return FALSE;
460 }
461
462 if (SQLITE_ROW == sqlite3_step(sql.select_way_ref)) {
463         const gchar *ref, *int_ref;
464         ref=sqlite3_column_text(sql.select_way_ref, 0);
465         int_ref=sqlite3_column_text(sql.select_way_ref, 1);
466         w->ref=g_strdup(ref);
467         w->int_ref=g_strdup(int_ref);
468 }
469 return FALSE;
470 }
471