]> err.no Git - mapper/blobdiff - src/osm-db.c
Remove useless includes
[mapper] / src / osm-db.c
index 184023b173877b182f618b84d6b1ab49b1789596..3702ef1d37bb6c0863e4536d7dd64875741d457a 100644 (file)
@@ -1,18 +1,19 @@
 #define _GNU_SOURCE
 
-#include <stdio.h>
 #include <unistd.h>
 #include <string.h>
 #include <strings.h>
 #include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
 #include <math.h>
 #include <glib.h>
+#include <glib/gstdio.h>
 #include <sqlite3.h>
-#include <expat.h>
 
 #include "osm.h"
+#include "latlon.h"
+
+/* #define DEBUG_OSM */
+#define OSM_PLACE_CACHE_MAX_ITEMS 40
 
 struct sql_select_stmt {
        sqlite3_stmt *select_way;
@@ -25,10 +26,30 @@ struct sql_select_stmt {
 static struct sql_select_stmt sql;
 
 gboolean osm_way_get_nodes(osm_way *w);
+gboolean osm_way_get_name(osm_way *w);
+gboolean osm_way_get_ref(osm_way *w);
+
+static GTimer *dbt;
+
+/* Cache hash tables */
+static GHashTable *_place_cache;
+
+/*****************************************************************************/
+
+int
+osm_progress(void *ud)
+{
+g_print(".");
+return 0;
+}
 
 gboolean
 osm_db_prepare(sqlite3 *db)
 {
+#ifdef DEBUG
+sqlite3_progress_handler(db, 1000, osm_progress, NULL);
+#endif
+
 /* Place */
 /* Select nearest place inside lat,lon+-range */
 if (sqlite3_prepare_v2(db, "select name,(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LON-lon)) as dist,"
@@ -57,6 +78,7 @@ if (sqlite3_prepare_v2(db, "select wid,type,nodes,flags,"
                                        " where wid=wsid and way_seg.node=nodes.nid "
                                        " and lat between $LAT-$RANGE and $LAT+$RANGE "
                                        " and lon between $LON-$RANGE and $LON+$RANGE "
+                                       " and type between $WTS and $WTY " 
                                        " order by dist",
                    -1, &sql.select_way, NULL)!=SQLITE_OK)
        return FALSE;
@@ -79,11 +101,22 @@ return TRUE;
 }
 
 gboolean
-osm_init()
+osm_init(void)
 {
+_place_cache=g_hash_table_new(g_direct_hash, g_direct_equal);
+dbt=g_timer_new();
 return TRUE;
 }
 
+void
+osm_deinit(void)
+{
+g_hash_table_destroy(_place_cache);
+g_timer_destroy(dbt);
+}
+
+/*****************************************************************************/
+
 /**
  * Free way nodes list 
  */
@@ -119,12 +152,80 @@ if (w->int_ref)
 g_slice_free(osm_way, w);
 }
 
+/*****************************************************************************/
+
+static void
+osm_place_free(osm_place *p)
+{
+if (p->name)
+       g_free(p->name);
+g_slice_free(osm_place, p);
+}
+
+static gboolean
+osm_place_remove(gpointer k, gpointer v, gpointer ud)
+{
+osm_place_free((osm_place *)v);
+return TRUE;
+}
+
+static osm_place *
+osm_place_new(void)
+{
+return g_slice_new0(osm_place);
+}
+
+static osm_place *
+osm_place_cache_lookup(guint32 id)
+{
+return g_hash_table_lookup(_place_cache, GINT_TO_POINTER(id));
+}
+
+static void
+osm_place_cache_add(osm_place *p)
+{
+if (osm_place_cache_lookup(p->id)==NULL)
+       g_hash_table_insert(_place_cache, GINT_TO_POINTER(p->id), p);
+}
+
+static void
+osm_place_cache_gc(void)
+{
+gint r;
+g_printf("*** Clearing place cache\n");
+r=g_hash_table_foreach_remove(_place_cache, osm_place_remove, NULL);
+g_printf("*** Removed %d items\n", r);
+}
+
+static void
+osm_place_update_distance(osm_place *p, gint lat, gint lon)
+{
+gdouble lam, lom;
+
+lam=(gdouble)((lat-p->lat)*(lat-p->lat));
+lom=(gdouble)((lon-p->lon)*(lon-p->lon));
+
+p->dist=sqrt(lam+lom);
+}
+
 /**
  * Get place with given id and distance to current location
  */
 gboolean
 osm_place_get(guint32 id, gint lat, gint lon, osm_place *n)
 {
+n=osm_place_cache_lookup(id);
+if (n) {
+       g_printf("*** Place cache hit!\n");
+       osm_place_update_distance(n, lat, lon);
+       return TRUE;
+}
+n=NULL;
+
+/* XXX: better place for this */
+if (g_hash_table_size(_place_cache)>OSM_PLACE_CACHE_MAX_ITEMS)
+       osm_place_cache_gc();
+
 sqlite3_clear_bindings(sql.select_place);
 sqlite3_reset(sql.select_place);
 
@@ -139,6 +240,7 @@ if (SQLITE_ROW == sqlite3_step(sql.select_place)) {
        const gchar *place;
        guint32 dist;
 
+       n=osm_place_new();
        place=sqlite3_column_text(sql.select_place, 0);
        n->name=g_strdup(place);
        dist=sqlite3_column_int(sql.select_place, 1);
@@ -156,9 +258,10 @@ return FALSE;
  * Search for the nearest place, type
  */
 gboolean
-osm_find_nearest_place(node_type_t type, gint lat, gint lon, osm_place *n)
+osm_find_nearest_place(node_type_t type, gint lat, gint lon, osm_place **nr)
 {
 gint range;
+osm_place *n=NULL;
 
 switch (type) {
        case NODE_PLACE_SUBURB:
@@ -188,10 +291,7 @@ if (SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 1, lat) ||
        return FALSE;
 }
 
-if (n->name) {
-       g_free(n->name);
-       n->name=NULL;
-}
+n=osm_place_new();
 n->isin=n->lat=n->lon=n->dist=0;
 if (SQLITE_ROW == sqlite3_step(sql.select_near_place)) {
        const gchar *place;
@@ -207,8 +307,12 @@ if (SQLITE_ROW == sqlite3_step(sql.select_near_place)) {
        n->isin=sqlite3_column_int(sql.select_near_place, 5);
        n->type=type;
 
+       osm_place_cache_add(n);
+
+       *nr=n;
        return TRUE;
 }
+*nr=n;
 return FALSE;
 }
 
@@ -218,20 +322,27 @@ osm_find_nearest_way_nodes(gint lat, gint lon, guint range)
 {
 GList *ways=NULL;
 osm_way *w;
+gulong tms;
+gint wc=0;
 
 sqlite3_reset(sql.select_way);
 sqlite3_clear_bindings(sql.select_way);
 
 if (SQLITE_OK != sqlite3_bind_int(sql.select_way, 1, lat) ||
     SQLITE_OK != sqlite3_bind_int(sql.select_way, 2, lon) ||
-    SQLITE_OK != sqlite3_bind_int(sql.select_way, 3, range)) {
+    SQLITE_OK != sqlite3_bind_int(sql.select_way, 3, range) ||
+    SQLITE_OK != sqlite3_bind_int(sql.select_way, 4, WAY_ROAD_START) ||
+    SQLITE_OK != sqlite3_bind_int(sql.select_way, 5, WAY_ROAD_END)) {
        g_printerr("Failed to bind values for way\n");
        return NULL;
 }
 
+g_timer_start(dbt);
+
 while (SQLITE_ROW == sqlite3_step(sql.select_way)) {
        guint32 dist;
 
+       wc++;
        w=g_slice_new0(osm_way);
        w->id=sqlite3_column_int(sql.select_way, 0);
        w->type=sqlite3_column_int(sql.select_way, 1);
@@ -243,10 +354,13 @@ while (SQLITE_ROW == sqlite3_step(sql.select_way)) {
        ways=g_list_prepend(ways, w);
 }
 
+g_timer_stop(dbt);
+g_printf("Query took: %f sec, found: %d ways\n", g_timer_elapsed(dbt, &tms), wc);
+
 return ways;
 }
 
-static gdouble magnitude(gdouble x1, gdouble y1, gdouble x2, gdouble y2)
+inline gdouble magnitude(gdouble x1, gdouble y1, gdouble x2, gdouble y2)
 {
 gdouble x,y;
 x=x2-x1;
@@ -255,27 +369,37 @@ y=y2-y1;
 return sqrt((x*x)+(y*y));
 }
 
-gboolean distance_point_to_line(gint x, gint y, gint x1, gint y1, gint x2, gint y2, gdouble *d)
+gboolean distance_point_to_line(gdouble x, gdouble y, gdouble x1, gdouble y1, gdouble x2, gdouble y2, gdouble *d)
 {
 gdouble lm,u,tmp;
 gdouble ix,iy;
 
-lm=magnitude((gdouble)x1,(gdouble)y1,(gdouble)x2,(gdouble)y2);
-tmp=(gdouble)((x-x1)*(x2-x1))+((y-y1)*(y2-y1));
+lm=magnitude(x1,y1,x2,y2);
+if (lm==0.0f)
+       return FALSE;
+
+tmp=((x-x1)*(x2-x1))+((y-y1)*(y2-y1));
 u=tmp/(lm*lm);
 
 if (u<0.0f || u>1.0f)
        return FALSE;
  
-ix=(gdouble)x1+u*(gdouble)(x2-x1);
-iy=(gdouble)y1+u*(gdouble)(y2-y1);
+ix=x1+u*(x2-x1);
+iy=y1+u*(y2-y1);
  
-*d=magnitude((gdouble)x,(gdouble)y, ix, iy);
+*d=magnitude(x,y, ix, iy);
  
 return TRUE;
 }
 
+gboolean osm_way_distance(gint lat, gint lon, osm_way_node *f, osm_way_node *t, gdouble *d)
+{
+if (!f || !t)
+       return FALSE;
+
+return distance_point_to_line((gdouble)lon, (gdouble)lat, (gdouble)f->lon, (gdouble)f->lat, (gdouble)t->lon, (gdouble)t->lat, d);
+}
+
 /**
  * Search for the nearest way (road)
  * - First search for ways with nearest node
@@ -292,6 +416,7 @@ GList *iter;
 GList *w=NULL;
 guint range=8192;
 osm_way *cw=NULL;
+gdouble pdist=900000.0, pndist=9000000.0;
 
 while ((w=osm_find_nearest_way_nodes(lat, lon, range))==NULL && range<=65536) {
        range=range<<1;
@@ -300,81 +425,61 @@ while ((w=osm_find_nearest_way_nodes(lat, lon, range))==NULL && range<=65536) {
 
 g_printf("Found ways: %d\n", g_list_length(w));
 
-switch (g_list_length(w)) {
-       case 0:
-               return NULL;
-       break;
-       case 1:
-               cw=w->data;
-       break;
-       default:
-       {
-               gint dist=900000, ndist;
-               gdouble pdist=900000.0, pndist=9000000.0;
+if (g_list_length(w)==0)
+       return NULL;
 
-               for (iter=w; iter!=NULL; iter=iter->next) {
-                       osm_way_node *wnf;
-                       osm_way_node *wnt;
+for (iter=w; iter!=NULL; iter=iter->next) {
+       osm_way_node *wnf;
+       osm_way_node *wnt;
+       osm_way *way=(osm_way*)iter->data;
 
-                       osm_way *way=(osm_way*)iter->data;
+#ifdef DEBUG_OSM
+       g_printf("WAY %d (%d) HAS %d NODES, nearest is %d\n", 
+               way->id, way->type, way->nodecnt, way->node_num);
+#endif
 
-                       g_printf("WAY %d (%d) HAS %d NODES, nearest is %d\n", 
-                               way->id, way->type, way->nodecnt, way->node_num);
+       if (osm_way_get_nodes(way)==FALSE)
+               continue;
 
-                       if (osm_way_get_nodes(way)==FALSE)
-                               continue;
+       if (way->nodes==0) {
+               g_printerr("Way with 0 nodes ? Skipping\n");
+               continue;
+       }
 
-                       if (way->nodes==0) {
-                               g_printerr("Way with 0 nodes ? Skipping\n");
-                               continue;
-                       }
+       wnf=g_list_nth_data(way->nodes, way->node_num);
+       if (!wnf) {
+               osm_way_free(way);
+               continue;
+       }
 
-                       wnf=g_list_nth_data(way->nodes, way->node_num);
-                       if (!wnf) {
+       if ((way->node_num==way->nodecnt) || (way->node_num==0)) {
+               wnt=g_list_nth_data(way->nodes, way->node_num==way->nodecnt ? way->nodecnt-1 : 1);
+               if (osm_way_distance(lat, lon, wnf, wnt, &pndist)==FALSE) {
+                       osm_way_free(way);
+                       continue;
+               }
+       } else {
+               wnt=g_list_nth_data(way->nodes, way->node_num-1);
+               if (osm_way_distance(lat, lon, wnf, wnt, &pndist)==FALSE) {
+                       wnt=g_list_nth_data(way->nodes, way->node_num+1);
+                       if (osm_way_distance(lat, lon, wnf, wnt, &pndist)==FALSE) {
                                osm_way_free(way);
                                continue;
                        }
-
-                       if ( (way->node_num==way->nodecnt) || (way->node_num==0)) {
-                               wnt=g_list_nth_data(way->nodes, way->node_num==way->nodecnt ? way->nodecnt-1 : 1);
-                               if (!wnt) {
-                                       osm_way_free(way);
-                                       continue;
-                               }
-                               if (distance_point_to_line(lon, lat, wnf->lon, wnf->lat, wnt->lon, wnt->lat, &pndist)==FALSE) {
-                                       osm_way_free(way);
-                                       continue;
-                               }
-                       } else {
-                               wnt=g_list_nth_data(way->nodes, way->node_num-1);
-                               if (!wnt) {
-                                       osm_way_free(way);
-                                       continue;
-                               }
-                               if (distance_point_to_line(lon, lat, wnf->lon, wnf->lat, wnt->lon, wnt->lat, &pndist)==FALSE) {
-                                       wnt=g_list_nth_data(way->nodes, way->node_num+1);
-                                       if (!wnt) {
-                                               osm_way_free(way);
-                                               continue;
-                                       }
-                                       if (distance_point_to_line(lon, lat, wnf->lon, wnf->lat, wnt->lon, wnt->lat, &pndist)==FALSE) {
-                                               osm_way_free(way);
-                                               continue;
-                                       }
-                               }
-                       }
-
-                       if (pndist<pdist) {
-                               g_printf("Found close way, distance: %f (Previous distance: %f)\n", pndist, pdist);
-                               pdist=pndist;
-                               cw=way;
-                       } else {
-                               g_printf("Way is not closer, freeing\n");
-                               osm_way_free(way);
-                       }
                }
        }
-       break;
+
+       if (pndist<pdist) {
+               g_printf("Found close way, distance: %f (Previous distance: %f)\n", pndist, pdist);
+               pdist=pndist;
+               way->node_f=wnf;
+               way->node_t=wnt;
+               way->distance=pndist;
+               cw=way;
+       } else {
+               osm_way_free(way);
+               way=NULL;
+       }
 }
 
 g_list_free(w);
@@ -388,10 +493,15 @@ if (cw->type==WAY_MOTORWAY || cw->type==WAY_TRUNK ||
                osm_way_get_ref(cw);
 }
 
-g_printf("BEST WAY: %d %d %d %d: %s %s %s\n", 
-       cw->id, cw->type, cw->flags,
-       cw->nodes, cw->dist, cw->name, 
-       cw->ref, cw->int_ref);
+#ifdef DEBUG_OSM
+g_printf("BEST WAY(%d): %s (%s,%s)\n", 
+       cw->id, cw->name, cw->ref, cw->int_ref);
+g_printf("\tT: %d F: %d N: %d D: %f\n", 
+       cw->type, cw->flags, cw->nodecnt, cw->dist);
+g_printf("\tNF: %d NT: %d DT %f\n", 
+       cw->node_f->num, 
+       cw->node_t->num, cw->distance);
+#endif
 
 return cw;
 }