]> err.no Git - mapper/blobdiff - src/osm-db.c
Start to rewrite the GPS system to support location information from multiple sources.
[mapper] / src / osm-db.c
index df068eba402b9bb07d20d3ad6e522e47bf6eb930..be7537f00b1f5f34fbb1cddacbce9f42c7e87e27 100644 (file)
@@ -17,7 +17,7 @@
  * with this program; if not, write to the Free Software Foundation, Inc.,
  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  */
-#define _GNU_SOURCE
+#include "config.h"
 
 #include <unistd.h>
 #include <string.h>
 #include "latlon.h"
 #include "gps.h"
 #include "osm-db.h"
+#include "settings.h"
 
 /* #define DEBUG_OSM */
 /* #define DEBUG_OSM_TIME */
 #define OSM_PLACE_CACHE_MAX_ITEMS (64)
 
-#define OSM_DB_PROGRESS_NUM (10000)
+#define OSM_DB_PROGRESS_NUM (20000)
 
 /* Node search ranges */
 #define OSM_RANGE_START (16384)
 #define OSM_RANGE_STEP  (8192)
 #define OSM_RANGE_STOP  (65535)
 
+static sqlite3 *osmdb;
+static gboolean osm_db_ok;
+
 struct sql_select_stmt {
        sqlite3_stmt *select_way;
        sqlite3_stmt *select_way2;
@@ -54,16 +58,20 @@ struct sql_select_stmt {
        sqlite3_stmt *select_way_nodes;
        sqlite3_stmt *select_way_name;
        sqlite3_stmt *select_way_name_nls;
+       sqlite3_stmt *select_way_name_search;
        sqlite3_stmt *select_way_ref;
        sqlite3_stmt *select_place;
        sqlite3_stmt *select_near_place;
+
+       sqlite3_stmt *select_node_next;
+       sqlite3_stmt *select_node_prev;
 };
 static struct sql_select_stmt sql;
 static GTimer *dbt;
 static GtkProgressBar *dbpw=NULL;
 
 /* Cache hash tables */
-static GHashTable *_place_cache;
+static GHashTable *place_cache;
 
 static guint way_dist_range=OSM_RANGE_WAY;
 
@@ -104,7 +112,8 @@ osm_progress_hide(sqlite3 *db)
 {
 if (!dbpw)
        return;
-gtk_widget_hide(GTK_WIDGET(dbpw));
+gtk_progress_bar_set_text(dbpw, "");
+gtk_progress_bar_set_fraction(dbpw, 0.0);
 sqlite3_progress_handler(db, OSM_DB_PROGRESS_NUM, NULL, NULL);
 }
 
@@ -113,10 +122,7 @@ osm_progress_show(sqlite3 *db)
 {
 if (!dbpw)
        return;
-gtk_widget_show(GTK_WIDGET(dbpw));
-#if 0
-gtk_progress_bar_set_text(_progress_item, text);
-#endif
+gtk_progress_bar_set_text(dbpw, _("Searching..."));
 sqlite3_progress_handler(db, OSM_DB_PROGRESS_NUM, osm_progress, NULL);
 }
 
@@ -137,18 +143,18 @@ osm_db_prepare(sqlite3 *db)
 {
 /* 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,"
-                                       " lat,lon,places.nid,isin "
+if (sqlite3_prepare_v2(db, "select name,(($LAT-ilat)*($LAT-ilat))+(($LON-ilon)*($LON-ilon)) as dist,"
+                                       " ilat,ilon,places.nid,isin_p,isin_c "
                                        " from places,nodes where type=$TYPE "
                                        " and nodes.nid=places.nid "
-                                       " and lat between $LAT-$RANGE and $LAT+$RANGE"
-                                       " and lon between $LON-$RANGE and $LON+$RANGE order by dist limit 1",
+                                       " and ilat between $LAT-$RANGE and $LAT+$RANGE"
+                                       " and ilon between $LON-$RANGE and $LON+$RANGE order by dist limit 1",
                    -1, &sql.select_near_place, NULL)!=SQLITE_OK)
        return FALSE;
 
 /* Select place name, distance, location, parent-place and type with given ID */
-if (sqlite3_prepare_v2(db, "select name,(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LON-lon)) as dist,"
-                                       " lat,lon,type,isin "
+if (sqlite3_prepare_v2(db, "select name,(($LAT-ilat)*($LAT-ilat))+(($LON-ilon)*($LON-ilon)) as dist,"
+                                       " ilat,ilon,type,isin_p,isin_c "
                                        " from places,nodes where "
                                        " nodes.nid=places.nid "
                                        " and places.nid=$NID order by dist limit 1",
@@ -156,59 +162,106 @@ if (sqlite3_prepare_v2(db, "select name,(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LO
        return FALSE;
 
 /* Ways */
-/* Select neareset ways inside lat,lon+-range */
-if (sqlite3_prepare_v2(db, "select wid,type,nodes,flags,"
-                                       "(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LON-lon)) as d,f,t,lat,lon "
-                                       " from way as w,way_s2s as ws,nodes as n "
-                                       " where w.wid=ws.wsid and ws.f=n.nid "
-                                       " and n.lat between $LAT-$RANGE and $LAT+$RANGE "
-                                       " and n.lon between $LON-$RANGE and $LON+$RANGE "
+/* Select nearest ways inside lat,lon+-range */
+if (sqlite3_prepare_v2(db, "select w.wid,type,nodes,flags,"
+                                       "(($LAT-n.ilat)*($LAT-n.ilat))+(($LON-n.ilon)*($LON-n.ilon)) as d,wn.f,wn.t,n.ilat,n.ilon "
+                                       " from way as w,way_n2n as wn,nodes as n "
+                                       " where w.wid=wn.wid and wn.f=n.nid "
+                                       " and n.ilat between $LAT-$RANGE and $LAT+$RANGE "
+                                       " and n.ilon between $LON-$RANGE and $LON+$RANGE "
                                        " and w.type between $WTS and $WTY " 
                                        " order by d",
                    -1, &sql.select_way2, NULL)!=SQLITE_OK)
        return FALSE;
 
-if (sqlite3_prepare_v2(db, "select t,lat,lon from way_s2s,nodes where wsid=? and f=? and way_s2s.t=nodes.nid limit 1",
+if (sqlite3_prepare_v2(db, "select w.wid,w.name as name,"
+                                       "(($LAT-ww.lat)*($LAT-ww.lat))+(($LON-ww.lon)*($LON-ww.lon)) as d,ww.lat,ww.lon "
+                                       " from way_names as w,way as ww where "
+                                       " ww.type between $WTS and $WTY and w.wid=ww.wid and w.name like $NAME "
+                                       " and ww.lat between $LAT-$RANGE and $LAT+$RANGE "
+                                       " and ww.lon between $LON-$RANGE and $LON+$RANGE "
+                                       " union "
+                                       " select w.wid,n.name as name,"
+                                       "(($LAT-ww.lat)*($LAT-ww.lat))+(($LON-ww.lon)*($LON-ww.lon)) as d,ww.lat,ww.lon "
+                                       " from way_names as w, way as ww,way_names_nls as n on w.wid=n.wid where "
+                                       " ww.type between $WTS and $WTY and w.wid=ww.wid and n.name like $NAME "
+                                       " and ww.lat between $LAT-$RANGE and $LAT+$RANGE "
+                                       " and ww.lon between $LON-$RANGE and $LON+$RANGE "
+                                       " order by name limit 100",
+                       -1, &sql.select_way_name_search, NULL)!=SQLITE_OK)
+       return FALSE;
+
+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",
                    -1, &sql.select_way_next_seg, NULL)!=SQLITE_OK)
        return FALSE;
 
-if (sqlite3_prepare_v2(db, "select f,lat,lon from way_s2s,nodes where wsid=? and t=? and way_s2s.f=nodes.nid limit 1",
+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",
                    -1, &sql.select_way_prev_seg, NULL)!=SQLITE_OK)
        return FALSE;
 
 /* Way name */
-if (sqlite3_prepare_v2(db, "select name from way_names where wid=?",
-                   -1, &sql.select_way_name, NULL)!=SQLITE_OK)
-       return FALSE;
-#if 0
-if (sqlite3_prepare_v2(db, "select name from way_names_nls where wid=? and lang=?",
-                   -1, &sql.select_way_name, NULL)!=SQLITE_OK)
+if (sqlite3_prepare_v2(db, "select name from way_names where wid=?", -1, &sql.select_way_name, NULL)!=SQLITE_OK)
        return FALSE;
-#endif
 
 /* Way ref and int_ref */
-if (sqlite3_prepare_v2(db, "select ref,int_ref from way_ref where rid=?",
-                   -1, &sql.select_way_ref, NULL)!=SQLITE_OK)
+if (sqlite3_prepare_v2(db, "select ref,int_ref from way_ref where rid=?", -1, &sql.select_way_ref, NULL)!=SQLITE_OK)
        return FALSE;
 
-return TRUE;
-}
+/* Get next, prev node + way information. For routing. */
+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 "
+                       "from way as w, nodes as n, way_n2n as nn where w.wid=nn.wid and nn.f=n.nid and nn.f=?",
+                   -1, &sql.select_node_next, NULL)!=SQLITE_OK)
+       return FALSE;
+
+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 "
+                       "from way as w, nodes as n, way_n2n as nn where w.wid=nn.wid and nn.f=n.nid and nn.t=?",
+                   -1, &sql.select_node_prev, NULL)!=SQLITE_OK)
+       return FALSE;
 
-gboolean
-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);
+if (osmdb!=NULL) {
+       sqlite3_finalize(sql.select_way_ref);
+       sqlite3_finalize(sql.select_way_name);
+       sqlite3_finalize(sql.select_way_next_seg);
+       sqlite3_finalize(sql.select_way_prev_seg);
+       sqlite3_finalize(sql.select_way_name_search);
+       sqlite3_finalize(sql.select_way2);
+       sqlite3_finalize(sql.select_place);
+       sqlite3_finalize(sql.select_near_place);
+}
+osmdb=NULL;
+osm_db_ok=FALSE;
+g_hash_table_destroy(place_cache);
 g_timer_destroy(dbt);
 }
 
+gboolean
+osm_init(sqlite3 **db)
+{
+osm_db_ok=FALSE;
+place_cache=g_hash_table_new(g_direct_hash, g_direct_equal);
+dbt=g_timer_new();
+
+if (!db || !*db) {
+       osmdb=NULL;
+       return FALSE;
+}
+
+osmdb=*db;
+if (osm_db_prepare(osmdb)==FALSE) {
+       g_printerr("Failed to prepare OSM SQL statements:");
+       g_printf("SQLITE: %s\n", sqlite3_errmsg(osmdb));
+       return FALSE;
+}
+osm_db_ok=TRUE;
+return TRUE;
+}
+
 /*****************************************************************************/
 
 osm_way_node *
@@ -291,21 +344,21 @@ 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));
+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);
+       g_hash_table_insert(place_cache, GINT_TO_POINTER(p->id), p);
 }
 
 static void
 osm_place_cache_gc(void)
 {
 gint r;
-r=g_hash_table_foreach_remove(_place_cache, osm_place_remove, NULL);
+r=g_hash_table_foreach_remove(place_cache, osm_place_remove, NULL);
 }
 
 static void
@@ -337,7 +390,7 @@ if (n) {
 n=NULL;
 
 /* XXX: better place for this */
-if (g_hash_table_size(_place_cache)>OSM_PLACE_CACHE_MAX_ITEMS)
+if (g_hash_table_size(place_cache)>OSM_PLACE_CACHE_MAX_ITEMS)
        osm_place_cache_gc();
 
 sqlite3_clear_bindings(sql.select_place);
@@ -362,7 +415,8 @@ if (SQLITE_ROW == sqlite3_step(sql.select_place)) {
        n->lat=sqlite3_column_int(sql.select_place, 2);
        n->lon=sqlite3_column_int(sql.select_place, 3);
        n->type=sqlite3_column_int(sql.select_place, 4);
-       n->isin=sqlite3_column_int(sql.select_place, 5);
+       n->isin_p=sqlite3_column_int(sql.select_place, 5);
+/*     n->isin_c=sqlite3_column_int(sql.select_place, 6); */
        return TRUE;
 }
 return FALSE;
@@ -406,7 +460,7 @@ if (SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 1, lat) ||
 }
 
 n=osm_place_new();
-n->isin=n->lat=n->lon=n->dist=0;
+n->isin_p=n->lat=n->lon=n->dist=0;
 if (SQLITE_ROW == sqlite3_step(sql.select_near_place)) {
        const gchar *place;
        guint32 dist;
@@ -418,7 +472,8 @@ if (SQLITE_ROW == sqlite3_step(sql.select_near_place)) {
        n->lat=sqlite3_column_int(sql.select_near_place, 2);
        n->lon=sqlite3_column_int(sql.select_near_place, 3);
        n->id=sqlite3_column_int(sql.select_near_place, 4);
-       n->isin=sqlite3_column_int(sql.select_near_place, 5);
+       n->isin_p=sqlite3_column_int(sql.select_near_place, 5);
+/*     n->isin_c=sqlite3_column_int(sql.select_near_place, 6); */
        n->type=type;
 
        osm_place_cache_add(n);
@@ -491,40 +546,63 @@ return ways;
 
 /*****************************************************************************/
 
-static inline gdouble 
-magnitude(gdouble x1, gdouble y1, gdouble x2, gdouble y2)
+GSList *
+osm_get_route_node(guint nid, osm_node_direction d)
 {
-gdouble x,y;
-x=x2-x1;
-y=y2-y1;
+GSList *r=NULL;
+osm_way *w;
+guint wc=0;
+sqlite3_stmt *psql=NULL;
+
+switch (d) {
+       case OSM_NODE_NEXT:
+               psql=sql.select_node_next;
+       break;
+       case OSM_NODE_PREV:
+               psql=sql.select_node_prev;
+       break;
+       default:
+               g_assert_not_reached();
+       break;
+}
 
-return sqrt((x*x)+(y*y));
+sqlite3_reset(psql);
+sqlite3_clear_bindings(psql);
+
+if (SQLITE_OK != sqlite3_bind_int(psql, 1, nid)) {
+       g_printerr("Failed to bind values for route node\n");
+       return NULL;
 }
 
-static 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;
+while (SQLITE_ROW == sqlite3_step(psql)) {
+       gdouble lat, lon;
 
-lm=magnitude(x1,y1,x2,y2);
-if (lm==0.0f)
-       return FALSE;
+       wc++;
+       w=g_slice_new0(osm_way);
+       w->id=sqlite3_column_int(psql, 0);
+       w->type=sqlite3_column_int(psql, 1);
+       w->flags=sqlite3_column_int(psql, 2);
+       w->speed=sqlite3_column_int(psql, 3);
 
-tmp=((x-x1)*(x2-x1))+((y-y1)*(y2-y1));
-u=tmp/(lm*lm);
+       lat=sqlite3_column_double(psql, 5);
+       lon=sqlite3_column_double(psql, 6);
 
-if (u<0.0f || u>1.0f)
-       return FALSE;
-ix=x1+u*(x2-x1);
-iy=y1+u*(y2-y1);
-*d=magnitude(x,y, ix, iy);
-return TRUE;
+       w->f=sqlite3_column_int(psql, 7);
+       w->t=sqlite3_column_int(psql, 8);
+#if 0
+       w->node=
+       w->node->flags=sqlite3_column_int(psql, 9);
+       w->node->links=sqlite3_column_int(psql, 10);
+#endif
+
+       r=g_slist_prepend(r, w);
 }
 
+return r;
+}
+
+
+/*****************************************************************************/
 gboolean 
 osm_way_distance(gint lat, gint lon, osm_way_node *f, osm_way_node *t, gdouble *d)
 {
@@ -830,7 +908,7 @@ if (map_loc->valid==FALSE) {
 /* Check if we are still near the same way as last time */
 if (map_loc->street && osm_way_distance(lat, lon, map_loc->street->node_f, map_loc->street->node_t, &dist)==TRUE) {
        /* We are probably on the same way as last time */
-       if ( (dist>(gdouble)way_dist_range) || (fabs(_gps.heading-map_loc->heading)>10.0)) {
+       if ( (dist>(gdouble)way_dist_range) || (fabs(_gps->data.heading-map_loc->heading)>10.0)) {
                /* We have moved a large amount, check way again */
                g_printf("*** dist %f over range, checking again\n", dist);
                osm_way_free(map_loc->street);
@@ -873,8 +951,8 @@ if (map_loc->street && osm_way_distance(lat, lon, map_loc->street->node_f, map_l
 }
 
 if (map_loc->changed==TRUE) {
-       map_loc->heading=_gps.heading;
-       map_loc->speed=_gps.speed;
+       map_loc->heading=_gps->data.heading;
+       map_loc->speed=_gps->data.speed;
 }
 
 #if 0
@@ -886,8 +964,8 @@ if (check_place==TRUE && d>way_dist_range*4) {
        gboolean fs;
 
        fs=osm_find_nearest_place(NODE_PLACE_SUBURB, lat, lon, &map_loc->secondary);
-       if (fs==TRUE && map_loc->secondary && map_loc->secondary->isin!=0) {
-               if (osm_place_get(map_loc->secondary->isin, lat, lon, &(map_loc->primary))==FALSE) {
+       if (fs==TRUE && map_loc->secondary && map_loc->secondary->isin_p!=0) {
+               if (osm_place_get(map_loc->secondary->isin_p, lat, lon, &(map_loc->primary))==FALSE) {
                        if (osm_find_nearest_place(NODE_PLACE_CITY, lat, lon, &map_loc->primary)==TRUE)
                                g_printf("Near city: %s\n", map_loc->primary->name);
                        else if (osm_find_nearest_place(NODE_PLACE_TOWN, lat, lon, &map_loc->primary)==TRUE)
@@ -897,8 +975,8 @@ if (check_place==TRUE && d>way_dist_range*4) {
                } else {
                        g_printf("In: %s\n", map_loc->primary ? map_loc->primary->name : "?");
                }
-       } else if (map_loc->street && map_loc->street->isin!=0) {
-               if (osm_place_get(map_loc->street->isin, lat, lon, &map_loc->primary)==FALSE) {
+       } else if (map_loc->street && map_loc->street->isin_p!=0) {
+               if (osm_place_get(map_loc->street->isin_p, lat, lon, &map_loc->primary)==FALSE) {
                        g_printf("Street location not know.\n");
                } else {
                        g_printf("Street is in: %s\n", map_loc->primary ? map_loc->primary->name : "?");
@@ -916,3 +994,81 @@ if (check_place==TRUE && d>way_dist_range*4) {
 
 return map_loc->street ? TRUE : FALSE;
 }
+
+/**
+ * osm_way_search
+ *
+ * Search for a street(way) starting with given 'text', next given lat/lon
+ *
+ */
+gboolean
+osm_way_search(gdouble lat, gdouble lon, gchar *text, GtkListStore **store)
+{
+GtkTreeIter iter;
+gchar *ltext=NULL;
+guint rows=0;
+gchar tmp1[16], tmp2[16];
+gdouble range=6;
+
+g_printf("Way Search: [%s] around %.6f %.6f\n", text, lat, lon);
+
+ltext=g_strdup_printf("%s%%", text);
+
+if (SQLITE_OK != sqlite3_bind_double(sql.select_way_name_search, 1, lat) ||
+    SQLITE_OK != sqlite3_bind_double(sql.select_way_name_search, 2, lon) ||
+    SQLITE_OK != sqlite3_bind_int(sql.select_way_name_search,   3, WAY_ROAD_START) ||
+    SQLITE_OK != sqlite3_bind_int(sql.select_way_name_search,    4, WAY_ROAD_END) ||
+    SQLITE_OK != sqlite3_bind_double(sql.select_way_name_search, 6, range) ||
+       SQLITE_OK != sqlite3_bind_text(sql.select_way_name_search,   5, ltext, -1, SQLITE_TRANSIENT)) {
+               g_printerr("Failed to bind values for sql.select_way_name_search\n");
+               sqlite3_clear_bindings(sql.select_way_name_search);
+               g_free(ltext);
+               return FALSE;
+}
+
+if (ltext)
+       g_free(ltext);
+
+*store = gtk_list_store_new(ITEM_NUM_COLUMNS, 
+                               G_TYPE_INT,             /* ID */
+                               G_TYPE_INT,             /*  */
+                               G_TYPE_DOUBLE,  /* Latitude */
+                               G_TYPE_DOUBLE,  /* Longitude */
+                               G_TYPE_DOUBLE,  /* Distance */
+                               G_TYPE_STRING,  /* Lat/Lon */
+                               G_TYPE_STRING,  /* Label */
+                               G_TYPE_STRING,  /* Desc. */
+                               G_TYPE_STRING,  /* Category */
+                               G_TYPE_STRING,  /* Dummy */
+                               G_TYPE_STRING); /* Dummy */
+
+while (SQLITE_ROW == sqlite3_step(sql.select_way_name_search)) {
+       gdouble rlat, rlon, dist;
+
+       rlat=sqlite3_column_double(sql.select_way_name_search, 3);
+       rlon=sqlite3_column_double(sql.select_way_name_search, 4);
+       lat_format(_degformat, rlat, tmp1);
+       lon_format(_degformat, rlon, tmp2);
+       dist=calculate_distance(lat, lon, rlat, rlon) * UNITS_CONVERT[_units];
+
+       gtk_list_store_append(*store, &iter);
+       gtk_list_store_set(*store, &iter,
+               ITEM_ID, sqlite3_column_int(sql.select_way_name_search, 0),
+               ITEM_LAT, rlat,
+               ITEM_LON, rlon,
+               ITEM_DIST, dist,
+               ITEM_LATLON, g_strdup_printf("%s, %s", tmp1, tmp2),
+               ITEM_LABEL, sqlite3_column_text(sql.select_way_name_search, 1),
+               -1);
+       rows++;
+}
+
+g_printf("Found: %d items\n", rows);
+
+sqlite3_reset(sql.select_way_name_search);
+sqlite3_clear_bindings(sql.select_way_name_search);
+
+return TRUE;
+}
+
+