From c3a65d782495529bca3cded3a3c55ced427e01e9 Mon Sep 17 00:00:00 2001 From: Kaj-Michael Lang Date: Mon, 23 Jul 2007 02:57:49 +0300 Subject: [PATCH] Way search and display works. --- src/latlon.c | 9 +- src/map.c | 24 ++--- src/osm-db.c | 279 ++++++++++++++++++++++++++++++++++++++++++++++++--- src/osm-db.h | 2 +- src/osm.c | 6 +- src/osm.h | 16 ++- 6 files changed, 305 insertions(+), 31 deletions(-) diff --git a/src/latlon.c b/src/latlon.c index ea4b219..01f46d4 100644 --- a/src/latlon.c +++ b/src/latlon.c @@ -29,11 +29,18 @@ lon2mp_int(gdouble lon) return lrint(lon/180*LATLON_MAX); } +gint +calculate_idistance(gint lat1, gint lon1, gint lat2, gint lon2) +{ +return lrint(sqrt((double)((lat1-lat2)*(lat1-lat2)+(lon1-lon2)*(lon1-lon2)))); +} + /** * Calculate the distance between two lat/lon pairs. The distance is returned * in kilometer. */ -gfloat calculate_distance(gfloat lat1, gfloat lon1, gfloat lat2, gfloat lon2) +gfloat +calculate_distance(gfloat lat1, gfloat lon1, gfloat lat2, gfloat lon2) { gdouble dlat, dlon, slat, slon, a; diff --git a/src/map.c b/src/map.c index b75d1bf..5fa8820 100644 --- a/src/map.c +++ b/src/map.c @@ -1356,17 +1356,17 @@ static void map_draw_track(gint x, gint y) } void -map_set_place_information(osm_place *s, osm_place *mp, osm_place *sp, PoiInfo *p) +map_set_place_information(osm_way *s, osm_place *mp, osm_place *sp, PoiInfo *p) { gchar buffer[256]; snprintf(buffer, sizeof(buffer), "On %s%s%s%s%s%s%s", - s->name ? s->name : "Unknown street", + s ? s->name ? s->name : "unknown" : "?", (p && p->label) ? " near " : "", (p && p->label) ? p->label : "", sp->name ? " in " : "", sp->name ? sp->name : "", - mp->name ? " in City " : "", + mp->name ? " in " : "", mp->name ? mp->name : ""); gtk_label_set_label(GTK_LABEL(_info_banner), buffer); } @@ -1377,7 +1377,7 @@ static void map_print_int_latlon(gint x, gint y) gint ux, uy; gint ilat, ilon; gdouble lat,lon; -osm_place street; +osm_way *street; osm_place mplace; osm_place splace; PoiInfo *p; @@ -1389,23 +1389,21 @@ unit2latlon(ux, uy, lat, lon); ilat=lat2mp_int(lat); ilon=lon2mp_int(lon); -street.name=NULL; -street.isin=0; mplace.name=NULL; splace.name=NULL; g_printf("IntPos: %d , %d\n", ilat, ilon); -#if 0 -osm_find_nearest_way(ilat, ilon, &street); -#endif +street=osm_find_nearest_way(ilat, ilon); +if (street) + g_printf("WAY: %d %s %s\n", street->id, street->name, street->ref); p=poi_find_nearest(lat, lon); if (osm_find_nearest_place(NODE_PLACE_SUBURB, ilat, ilon, &splace)==TRUE) g_printf("Near suburb: %s (%d)\n", splace.name, splace.isin); -if (splace.isin!=0 && street.isin==0) { +if (splace.isin!=0) { if (osm_place_get(splace.isin, ilat, ilon, &mplace)==FALSE) { if (osm_find_nearest_place(NODE_PLACE_CITY, ilat, ilon, &mplace)==TRUE) g_printf("Near city: %s\n", mplace.name); @@ -1416,8 +1414,8 @@ if (splace.isin!=0 && street.isin==0) { } else { g_printf("In %s\n", mplace.name); } -} else if (street.isin!=0) { - if (osm_place_get(street.isin, ilat, ilon, &mplace)==FALSE) { +} else if (street && street->isin!=0) { + if (osm_place_get(street->isin, ilat, ilon, &mplace)==FALSE) { } else { g_printf("In %s\n", mplace.name); @@ -1432,7 +1430,7 @@ if (splace.isin!=0 && street.isin==0) { } -map_set_place_information(&street, &mplace, &splace, p); +map_set_place_information(street, &mplace, &splace, p); } gboolean map_cb_scroll_event(GtkWidget * widget, GdkEventScroll * event) diff --git a/src/osm-db.c b/src/osm-db.c index b410623..c7656ee 100644 --- a/src/osm-db.c +++ b/src/osm-db.c @@ -24,6 +24,8 @@ struct sql_select_stmt { }; static struct sql_select_stmt sql; +gboolean osm_way_get_nodes(osm_way *w); + gboolean osm_db_prepare(sqlite3 *db) { @@ -47,16 +49,16 @@ if (sqlite3_prepare_v2(db, "select name,(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LO -1, &sql.select_place, NULL)!=SQLITE_OK) return FALSE; -return TRUE; /* Ways */ /* Select neareset ways inside lat,lon+-range */ -if (sqlite3_prepare_v2(db, "select wid from way,way_seg,nodes," - "(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LON-lon)) as dist" +if (sqlite3_prepare_v2(db, "select wid,type,nodes,flags," + "(($LAT-lat)*($LAT-lat))+(($LON-lon)*($LON-lon)) as dist, num" + " from way,way_seg,nodes" " where wid=wsid and way_seg.node=nodes.nid " - " and nodes.lat between $LAT-$RANGE and $LAT+$RANGE " - " and nodes.lon between $LON-$RANGE and $LON+$RANGE " + " and lat between $LAT-$RANGE and $LAT+$RANGE " + " and lon between $LON-$RANGE and $LON+$RANGE " " order by dist", - -1, &sql.select_way_name, NULL)!=SQLITE_OK) + -1, &sql.select_way, NULL)!=SQLITE_OK) return FALSE; /* Select way nodes */ @@ -94,7 +96,7 @@ sqlite3_reset(sql.select_place); if (SQLITE_OK != sqlite3_bind_int(sql.select_place, 1, lat) || SQLITE_OK != sqlite3_bind_int(sql.select_place, 2, lon) || SQLITE_OK != sqlite3_bind_int(sql.select_place, 3, id)) { - g_printerr("Failed to bind values\n"); + g_printerr("Failed to bind values for place\n"); return FALSE; } @@ -104,8 +106,8 @@ if (SQLITE_ROW == sqlite3_step(sql.select_place)) { place=sqlite3_column_text(sql.select_place, 0); n->name=g_strdup(place); - n->dist=sqlite3_column_int(sql.select_place, 1); - n->dist=sqrt(n->dist); + dist=sqlite3_column_int(sql.select_place, 1); + n->dist=sqrt((double)dist); 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); @@ -147,7 +149,7 @@ if (SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 1, lat) || SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 2, lon) || SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 3, type) || SQLITE_OK != sqlite3_bind_int(sql.select_near_place, 4, range)) { - g_printerr("Failed to bind values\n"); + g_printerr("Failed to bind values for near place\n"); return FALSE; } @@ -162,8 +164,8 @@ if (SQLITE_ROW == sqlite3_step(sql.select_near_place)) { place=sqlite3_column_text(sql.select_near_place, 0); n->name=g_strdup(place); - n->dist=sqlite3_column_int(sql.select_near_place, 1); - n->dist=sqrt((double)n->dist); + dist=sqlite3_column_int(sql.select_near_place, 1); + n->dist=sqrt((double)dist); 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); @@ -176,6 +178,89 @@ if (SQLITE_ROW == sqlite3_step(sql.select_near_place)) { return FALSE; } +/* Way helper */ +static GList * +osm_find_nearest_way_nodes(gint lat, gint lon, guint range) +{ +GList *ways=NULL; +osm_way *w; + +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)) { + g_printerr("Failed to bind values for way\n"); + return NULL; +} + +while (SQLITE_ROW == sqlite3_step(sql.select_way)) { + guint32 dist; + + w=g_slice_new0(osm_way); + w->id=sqlite3_column_int(sql.select_way, 0); + w->type=sqlite3_column_int(sql.select_way, 1); + w->nodecnt=sqlite3_column_int(sql.select_way, 2); + w->flags=sqlite3_column_int(sql.select_way, 3); + dist=sqlite3_column_int(sql.select_way, 4); + w->dist=sqrt((gdouble)dist); + w->node_num=sqlite3_column_int(sql.select_way, 5); + ways=g_list_prepend(ways, w); +} + +return ways; +} + +static gdouble magnitude(gdouble x1, gdouble y1, gdouble x2, gdouble y2) +{ +gdouble x,y; +x=x2-x1; +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) +{ +gdouble lm,u; +gdouble ix,iy; +gdouble tmp,tx1,tx2,ty1,ty2; + +#if 0 +if (x1>x2) { + tx1=x2; + ty1=y2; + x2=x1; + y2=y1; + x1=tx1; + y1=ty1; +} +#endif + +lm=magnitude((gdouble)x1,(gdouble)y1,(gdouble)x2,(gdouble)y2); + +tmp=(gdouble)((x-x1)*(x2-x1))+((y-y1)*(y2-y1)); +u=tmp/(lm*lm); + +g_printf("DPL: tmp %f u %f lm %f\n", tmp, u, lm); + +g_printf("DPLX: (%d/%d) (%d %d)-(%d %d)\n", + x,y, + x1,y1, + x2,y2); + +if (u<0.0f || u>1.0f) + return FALSE; + +ix=(gdouble)x1+u*(gdouble)(x2-x1); +iy=(gdouble)y1+u*(gdouble)(y2-y1); + +*d=magnitude((gdouble)x,(gdouble)y, ix, iy); + +return TRUE; +} + /** * Search for the nearest way (road) * - First search for ways with nearest node @@ -188,7 +273,108 @@ return FALSE; osm_way * osm_find_nearest_way(gint lat, gint lon) { +GList *iter; +GList *w=NULL; +guint range=8192; +osm_way *cw=NULL; +while ((w=osm_find_nearest_way_nodes(lat, lon, range))==NULL && range<=65536) { + range=range<<1; + g_printf("Trying with range: %d\n", range); +} + +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; + + for (iter=w; iter!=NULL; iter=iter->next) { + osm_way_node *wnf; + osm_way_node *wnt; + + osm_way *way=(osm_way*)iter->data; + + g_printf("C*** 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 (way->nodes==0) { + g_printerr("Way with 0 nodes ? Skipping\n"); + continue; + } + + wnf=g_list_nth_data(way->nodes, way->node_num); + if (!wnf) + continue; + + g_printf("----EVAL-START:\n"); + if (way->node_num==way->nodecnt) { + g_print(" <- Last\n"); + wnt=g_list_nth_data(way->nodes, way->nodecnt-1); + if (!wnt) + continue; + if (distance_point_to_line(lon, lat, wnf->lon, wnf->lat, wnt->lon, wnt->lat, &pndist)==FALSE) + continue; + } else if (way->node_num==0) { + g_print(" First %d ->\n", wnf->num); + wnt=g_list_nth_data(way->nodes, 1); + if (!wnt) + continue; + if (distance_point_to_line(lon, lat, wnf->lon, wnf->lat, wnt->lon, wnt->lat, &pndist)==FALSE) + continue; + } else { + g_print(" <->\n"); + wnt=g_list_nth_data(way->nodes, way->node_num-1); + if (!wnt) + 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) + continue; + if (distance_point_to_line(lon, lat, wnf->lon, wnf->lat, wnt->lon, wnt->lat, &pndist)==FALSE) + continue; + } + } + g_printf("----EVAL-DONE: %d <-> %d\n", wnf->num, wnt->num); + + g_printf("WD: New: %f Prev:%f\n", pndist, pdist); + if (pndisttype==WAY_MOTORWAY || cw->type==WAY_TRUNK || + cw->type==WAY_PRIMARY || cw->type==WAY_SECONDARY || + cw->type==WAY_TERTIARY) { + osm_way_get_ref(cw); +} + +g_printf("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); + +return cw; } /** @@ -199,9 +385,78 @@ osm_way_get_nodes(osm_way *w) { if (w->nodes!=NULL) return TRUE; + +sqlite3_reset(sql.select_way_nodes); +sqlite3_clear_bindings(sql.select_way_nodes); + +if (SQLITE_OK != sqlite3_bind_int(sql.select_way_nodes, 1, w->id)) { + g_printerr("Failed to bind values way nodes\n"); + return FALSE; +} + +while (SQLITE_ROW == sqlite3_step(sql.select_way_nodes)) { + osm_way_node *n; + + n=g_slice_new(osm_way_node); + n->num=sqlite3_column_int(sql.select_way_nodes, 0); + n->lat=sqlite3_column_int(sql.select_way_nodes, 1); + n->lon=sqlite3_column_int(sql.select_way_nodes, 2); + w->nodes=g_list_append(w->nodes, n); +} + +return (w->nodes==NULL) ? FALSE : TRUE; +} + +gboolean +osm_way_get_name(osm_way *w) +{ +sqlite3_reset(sql.select_way_name); +sqlite3_clear_bindings(sql.select_way_name); + +if (SQLITE_OK != sqlite3_bind_int(sql.select_way_name, 1, w->id)) { + g_printerr("Failed to bind values for way name\n"); + return FALSE; +} + +if (SQLITE_ROW == sqlite3_step(sql.select_way_name)) { + const gchar *place; + place=sqlite3_column_text(sql.select_way_name, 0); + w->name=g_strdup(place); +} +return FALSE; +} + +gboolean +osm_way_get_ref(osm_way *w) +{ +sqlite3_reset(sql.select_way_ref); +sqlite3_clear_bindings(sql.select_way_ref); + +if (SQLITE_OK != sqlite3_bind_int(sql.select_way_ref, 1, w->id)) { + g_printerr("Failed to bind values for way ref\n"); + return FALSE; +} + +if (SQLITE_ROW == sqlite3_step(sql.select_way_ref)) { + const gchar *ref, *int_ref; + ref=sqlite3_column_text(sql.select_way_ref, 0); + int_ref=sqlite3_column_text(sql.select_way_ref, 1); + w->ref=g_strdup(ref); + w->int_ref=g_strdup(int_ref); +} +return FALSE; } void osm_way_free(osm_way *w) { +if (w->nodes) + g_list_free(w->nodes); +if (w->name) + g_free(w->name); +if (w->ref) + g_free(w->ref); +if (w->int_ref) + g_free(w->int_ref); +g_slice_free(osm_way, w); } diff --git a/src/osm-db.h b/src/osm-db.h index fe43e45..ef63d54 100644 --- a/src/osm-db.h +++ b/src/osm-db.h @@ -2,4 +2,4 @@ #include "osm.h" gboolean osm_find_nearest_place(node_type_t type, gint lat, gint lon, osm_place *n); - +osm_way *osm_find_nearest_way(gint lat, gint lon); diff --git a/src/osm.c b/src/osm.c index 6e5f268..331c20c 100644 --- a/src/osm.c +++ b/src/osm.c @@ -39,8 +39,8 @@ struct _node_data { typedef struct _node node; struct _node { guint32 id; - gfloat lat; - gfloat lon; + gdouble lat; + gdouble lon; node_data *data; }; @@ -697,7 +697,7 @@ node *t; node *r; gchar **isin; gchar **place; -gfloat dist; +gdouble dist; if (!n->data) return 0; diff --git a/src/osm.h b/src/osm.h index a1cff5c..a3dc6bc 100644 --- a/src/osm.h +++ b/src/osm.h @@ -119,9 +119,23 @@ struct _osm_place { typedef struct _osm_way osm_way; struct _osm_way { guint32 id; - gshort type; + guint type; guint flags; + guint nodecnt; + guint32 isin; + guint node_num; + gdouble dist; + gchar *name; + gchar *ref; + gchar *int_ref; GList *nodes; }; +typedef struct _osm_way_node osm_way_node; +struct _osm_way_node { + guint num; + gint lat; + gint lon; +}; + #endif -- 2.39.5