From f28ed689c5383218be6ae90879d70cc036161ff1 Mon Sep 17 00:00:00 2001 From: martin-s Date: Mon, 1 Jun 2009 16:07:39 +0000 Subject: [PATCH] Add:Core:Work on housenumber search git-svn-id: https://navit.svn.sourceforge.net/svnroot/navit/trunk@2300 ffa7fe5e-494d-0410-b361-a75ebd5db220 --- navit/navit/attr_def.h | 5 + navit/navit/gui/gtk/destination.c | 2 +- navit/navit/gui/gtk/gui_gtk_window.c | 10 + navit/navit/gui/internal/gui_internal.c | 54 ++- navit/navit/item.h | 1 + navit/navit/map/binfile/binfile.c | 14 +- navit/navit/map/mg/map.c | 195 +++++++--- navit/navit/map/mg/mg.h | 38 +- navit/navit/map/mg/street.c | 655 +++++++++++++++++++++++++++++--- navit/navit/map/mg/town.c | 3 +- navit/navit/map/mg/tree.c | 3 +- navit/navit/search.c | 345 +++++++++++++++-- navit/navit/search.h | 25 +- 13 files changed, 1196 insertions(+), 154 deletions(-) diff --git a/navit/navit/attr_def.h b/navit/navit/attr_def.h index e3375ef..a9ec194 100644 --- a/navit/navit/attr_def.h +++ b/navit/navit/attr_def.h @@ -231,6 +231,11 @@ ATTR(email) ATTR(url) ATTR(profilename) ATTR(projectionname) +ATTR(town_or_district_name) +ATTR(postal) +ATTR(postal_mask) +ATTR(house_number_first) +ATTR(house_number_last) ATTR2(0x0003ffff,type_string_end) ATTR2(0x00040000,type_special_begin) ATTR(order) diff --git a/navit/navit/gui/gtk/destination.c b/navit/navit/gui/gtk/destination.c index b65cba5..4db7b76 100644 --- a/navit/navit/gui/gtk/destination.c +++ b/navit/navit/gui/gtk/destination.c @@ -264,7 +264,7 @@ static void changed(GtkWidget *widget, struct search_param *search) else gtk_list_store_set(search->liststore,&iter,0,"",-1); if (res->town) { - gtk_list_store_set(search->liststore,&iter,1,res->town->postal,-1); + gtk_list_store_set(search->liststore,&iter,1,res->town->common.postal,-1); gtk_list_store_set(search->liststore,&iter,2,res->town->name,-1); gtk_list_store_set(search->liststore,&iter,3,res->town->district,-1); } else { diff --git a/navit/navit/gui/gtk/gui_gtk_window.c b/navit/navit/gui/gtk/gui_gtk_window.c index 05e2129..bad44b6 100644 --- a/navit/navit/gui/gtk/gui_gtk_window.c +++ b/navit/navit/gui/gtk/gui_gtk_window.c @@ -143,6 +143,16 @@ keypress(GtkWidget *widget, GdkEventKey *event, struct gui_priv *this) transform_set_distance(t, (transform_get_distance(t)+5)); navit_draw(this->nav); break; + case 'z': + t=navit_get_trans(this->nav); + transform_set_hog(t, (transform_get_hog(t)+1)); + navit_draw(this->nav); + break; + case 'h': + t=navit_get_trans(this->nav); + transform_set_hog(t, (transform_get_hog(t)-1)); + navit_draw(this->nav); + break; case 't': { struct coord *p; diff --git a/navit/navit/gui/internal/gui_internal.c b/navit/navit/gui/internal/gui_internal.c index bd9d6a1..16695ff 100644 --- a/navit/navit/gui/internal/gui_internal.c +++ b/navit/navit/gui/internal/gui_internal.c @@ -353,6 +353,8 @@ static void gui_internal_populate_route_table(struct gui_priv * this, struct navit * navit); static void gui_internal_search_idle_end(struct gui_priv *this); static void gui_internal_search(struct gui_priv *this, char *what, char *type, int flags); +static void gui_internal_search_house_number(struct gui_priv *this, struct widget *widget, void *data); +static void gui_internal_search_house_number_in_street(struct gui_priv *this, struct widget *widget, void *data); static void gui_internal_search_street(struct gui_priv *this, struct widget *widget, void *data); static void gui_internal_search_street_in_town(struct gui_priv *this, struct widget *widget, void *data); static void gui_internal_search_town(struct gui_priv *this, struct widget *wm, void *data); @@ -2038,6 +2040,7 @@ gui_internal_cmd_position(struct gui_priv *this, struct widget *wm, void *data) int display_view_on_map=(wm->data != (void *)1); int display_items=(wm->data == (void *)1); int display_streets=(wm->data == (void *)3); + int display_house_numbers=1; if (wm->data == (void *)4) { gui_internal_search_town_in_country(this, wm); return; @@ -2075,6 +2078,14 @@ gui_internal_cmd_position(struct gui_priv *this, struct widget *wm, void *data) wc->item=wm->item; wc->selection_id=wm->selection_id; } + if (display_house_numbers) { + gui_internal_widget_append(w, + wc=gui_internal_button_new_with_callback(this, _("House numbers"), + image_new_xs(this, "gui_active"), gravity_left_center|orientation_horizontal|flags_fill, + gui_internal_search_house_number_in_street, wm)); + wc->item=wm->item; + wc->selection_id=wm->selection_id; + } if (display_attributes) { struct map_rect *mr; struct item *item; @@ -2340,17 +2351,20 @@ gui_internal_search_idle(struct gui_priv *this, char *wm_name, struct widget *se if (! strcmp(wm_name,"Country")) { name=res->country->name; - item=&res->country->item; + item=&res->country->common.item; text=g_strdup_printf("%s", res->country->name); } if (! strcmp(wm_name,"Town")) { name=res->town->name; - item=&res->town->item; - text=g_strdup(name); + item=&res->town->common.item; + if (res->town->name && res->town->district) + text=g_strdup_printf("%s%s%s (%s)", res->town->common.postal_mask ? res->town->common.postal_mask : "", res->town->common.postal_mask ? " ":"", res->town->name, res->town->district); + else + text=g_strdup_printf("%s%s%s", res->town->common.postal ? res->town->common.postal_mask : "", res->town->common.postal_mask ? " ":"", res->town->name); } if (! strcmp(wm_name,"Street")) { name=res->street->name; - item=&res->street->item; + item=&res->street->common.item; text=g_strdup_printf("%s %s", res->town->name, res->street->name); } #if 0 @@ -2414,9 +2428,11 @@ gui_internal_search_changed(struct gui_priv *this, struct widget *wm, void *data if (! strcmp(wm->name,"Country")) search_attr.type=attr_country_all; if (! strcmp(wm->name,"Town")) - search_attr.type=attr_town_name; + search_attr.type=attr_town_or_district_name; if (! strcmp(wm->name,"Street")) search_attr.type=attr_street_name; + if (! strcmp(wm->name,"House number")) + search_attr.type=attr_house_number; search_attr.u.str=wm->text; search_list_search(this->sl, &search_attr, 1); gui_internal_search_idle_start(this, wm->name, search_list, param); @@ -2695,6 +2711,12 @@ gui_internal_search(struct gui_priv *this, char *what, char *type, int flags) gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "gui_select_town"))); wb->state |= STATE_SENSITIVE; wb->func = gui_internal_back; + wnext=gui_internal_image_new(this, image_new_xs(this, "gui_select_house_number")); + wnext->func=gui_internal_search_house_number; + } else if (!strcmp(type,"House number")) { + gui_internal_widget_append(we, wb=gui_internal_image_new(this, image_new_xs(this, "gui_select_street"))); + wb->state |= STATE_SENSITIVE; + wb->func = gui_internal_back; } gui_internal_widget_append(we, wk=gui_internal_label_new(this, NULL)); if (wnext) { @@ -2715,9 +2737,25 @@ gui_internal_search(struct gui_priv *this, char *what, char *type, int flags) } static void +gui_internal_search_house_number(struct gui_priv *this, struct widget *widget, void *data) +{ + search_list_select(this->sl, attr_street_name, 0, 0); + gui_internal_search(this,_("House number"),"House number",0); +} + +static void +gui_internal_search_house_number_in_street(struct gui_priv *this, struct widget *widget, void *data) +{ + dbg(0,"id %d\n", widget->selection_id); + search_list_select(this->sl, attr_street_name, 0, 0); + search_list_select(this->sl, attr_street_name, widget->selection_id, 1); + gui_internal_search(this,_("House number"),"House number",0); +} + +static void gui_internal_search_street(struct gui_priv *this, struct widget *widget, void *data) { - search_list_select(this->sl, attr_town_name, 0, 0); + search_list_select(this->sl, attr_town_or_district_name, 0, 0); gui_internal_search(this,_("Street"),"Street",0); } @@ -2725,8 +2763,8 @@ static void gui_internal_search_street_in_town(struct gui_priv *this, struct widget *widget, void *data) { dbg(0,"id %d\n", widget->selection_id); - search_list_select(this->sl, attr_town_name, 0, 0); - search_list_select(this->sl, attr_town_name, widget->selection_id, 1); + search_list_select(this->sl, attr_town_or_district_name, 0, 0); + search_list_select(this->sl, attr_town_or_district_name, widget->selection_id, 1); gui_internal_search(this,_("Street"),"Street",0); } diff --git a/navit/navit/item.h b/navit/navit/item.h index 32b1d08..64dda9f 100644 --- a/navit/navit/item.h +++ b/navit/navit/item.h @@ -46,6 +46,7 @@ extern int default_flags[]; we want navit's town search to find them */ #define item_is_town(item) ((item).type >= type_town_label && (item).type <= type_district_label_1e7) +#define item_is_district(item) ((item).type >= type_district_label && (item).type <= type_district_label_1e7) #define item_is_equal_id(a,b) ((a).id_hi == (b).id_hi && (a).id_lo == (b).id_lo) #define item_is_equal(a,b) (item_is_equal_id(a,b) && (a).map == (b).map) diff --git a/navit/navit/map/binfile/binfile.c b/navit/navit/map/binfile/binfile.c index c79474d..1b15fd0 100644 --- a/navit/navit/map/binfile/binfile.c +++ b/navit/navit/map/binfile/binfile.c @@ -646,6 +646,7 @@ binmap_search_new(struct map_priv *map, struct item *item, struct attr *search, case attr_country_name: break; case attr_town_name: + case attr_town_or_district_name: msp = g_new(struct map_search_priv, 1); msp->search_results = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); map_rec = map_rect_new_binfile(map, NULL); @@ -724,8 +725,11 @@ binmap_search_get_item(struct map_search_priv *map_search) { struct item* it; while ((it = map_rect_get_item_binfile(map_search->mr))) { - if (map_search->search->type == attr_town_name) { - if (item_is_town(*it)) { + switch (map_search->search->type) { + case attr_town_name: + case attr_district_name: + case attr_town_or_district_name: + if ((item_is_town(*it) && map_search->search->type != attr_district_name) || (item_is_district(*it) && map_search->search->type != attr_town_name)) { struct attr at; if (binfile_attr_get(it->priv_data, attr_label, &at)) { if (!ascii_cmp(at.u.str, map_search->search->u.str, map_search->partial)) { @@ -733,7 +737,8 @@ binmap_search_get_item(struct map_search_priv *map_search) } } } - } else if (map_search->search->type == attr_street_name) { + break; + case attr_street_name: if ((it->type == type_street_3_city) || (it->type == type_street_2_city) || (it->type == type_street_1_city)) { struct attr at; if (map_selection_contains_item_rect(map_search->mr->sel, it) && binfile_attr_get(it->priv_data, attr_label, &at)) { @@ -747,6 +752,9 @@ binmap_search_get_item(struct map_search_priv *map_search) } } } + break; + default: + return NULL; } } return NULL; diff --git a/navit/navit/map/mg/map.c b/navit/navit/map/mg/map.c index 7e5f895..bac769c 100644 --- a/navit/navit/map/mg/map.c +++ b/navit/navit/map/mg/map.c @@ -26,6 +26,8 @@ #include "mg.h" +GList *maps; + static struct country_isonum { int country; int isonum; @@ -207,7 +209,7 @@ file_next(struct map_rect_priv *mr) } } -static void +void map_destroy_mg(struct map_priv *m) { int i; @@ -221,7 +223,7 @@ map_destroy_mg(struct map_priv *m) extern int block_lin_count,block_idx_count,block_active_count,block_mem,block_active_mem; -static struct map_rect_priv * +struct map_rect_priv * map_rect_new_mg(struct map_priv *map, struct map_selection *sel) { struct map_rect_priv *mr; @@ -239,7 +241,6 @@ map_rect_new_mg(struct map_priv *map, struct map_selection *sel) if (sel && sel->next) for (i=0 ; i < file_end ; i++) mr->block_hash[i]=g_hash_table_new(g_int_hash,g_int_equal); - file_next(mr); return mr; } @@ -293,10 +294,10 @@ map_rect_get_item_mg(struct map_rect_priv *mr) } } -static struct item * +struct item * map_rect_get_item_byid_mg(struct map_rect_priv *mr, int id_hi, int id_lo) { - mr->current_file = id_hi >> 16; + mr->current_file = (id_hi >> 16) & 0xff; switch (mr->current_file) { case file_town_twn: if (town_get_byid(mr, &mr->town, id_hi, id_lo, &mr->item)) @@ -315,7 +316,7 @@ map_rect_get_item_byid_mg(struct map_rect_priv *mr, int id_hi, int id_lo) } -static void +void map_rect_destroy_mg(struct map_rect_priv *mr) { int i; @@ -366,64 +367,138 @@ map_search_mg_convert_special(char *str) } } - -static struct map_search_priv * -map_search_new_mg(struct map_priv *map, struct item *item, struct attr *search, int partial) +static int +map_search_setup(struct map_rect_priv *mr) { - struct map_rect_priv *mr=g_new0(struct map_rect_priv, 1); char *prefix; - dbg(1,"id_lo=0x%x\n", item->id_lo); - dbg(1,"search=%s\n", search->u.str); - mr->m=map; - mr->search_type=search->type; - - /* - * NOTE: If you implement search for other attributes than attr_town_postal, attr_town_name and attr_street_name, - * please update this comment and the documentation for map_search_new() in map.c - */ - - switch (search->type) { + dbg(1,"%s\n", attr_to_name(mr->search_type)); + switch (mr->search_type) { case attr_town_postal: - if (item->type != type_country_label) - return NULL; - prefix=mg_country_postal_prefix(item->id_lo); + if (mr->search_item.type != type_country_label) { + dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type)); + return 0; + } + prefix=mg_country_postal_prefix(mr->search_item.id_lo); if (! prefix) - return NULL; - tree_search_init(map->dirname, "town.b1", &mr->ts, 0); + return 0; + tree_search_init(mr->m->dirname, "town.b1", &mr->ts, 0); mr->current_file=file_town_twn; - mr->search_str=g_strdup_printf("%s%s",prefix,search->u.str); + mr->search_str=g_strdup_printf("%s%s",prefix,mr->search_attr->u.str); dbg(0,"search_str='%s'\n",mr->search_str); - mr->search_country=mg_country_from_isonum(item->id_lo); + mr->search_country=mg_country_from_isonum(mr->search_item.id_lo); break; case attr_town_name: - if (item->type != type_country_label) - return NULL; - tree_search_init(map->dirname, "town.b2", &mr->ts, 0x1000); + if (mr->search_item.type != type_country_label) { + dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type)); + return 0; + } + tree_search_init(mr->m->dirname, "town.b2", &mr->ts, 0x1000); + mr->current_file=file_town_twn; + mr->search_str=map_search_mg_convert_special(mr->search_attr->u.str); + mr->search_country=mg_country_from_isonum(mr->search_item.id_lo); + break; + case attr_district_name: + if (mr->search_item.type != type_country_label) { + dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type)); + return 0; + } + tree_search_init(mr->m->dirname, "town.b3", &mr->ts, 0x1000); mr->current_file=file_town_twn; - mr->search_str=map_search_mg_convert_special(search->u.str); - mr->search_country=mg_country_from_isonum(item->id_lo); + mr->search_str=map_search_mg_convert_special(mr->search_attr->u.str); + mr->search_country=mg_country_from_isonum(mr->search_item.id_lo); break; case attr_street_name: - if (item->type != type_town_streets) - return NULL; - dbg(1,"street_assoc=0x%x\n", item->id_lo); - tree_search_init(map->dirname, "strname.b1", &mr->ts, 0); + if (mr->search_item.type != type_town_streets) { + GList *tmp=maps; + struct item *item=NULL; + struct attr attr; + struct map_rect_priv *mr2; + while (tmp) { + mr2=map_rect_new_mg(tmp->data, NULL); + item=map_rect_get_item_byid_mg(mr2, mr->search_item.id_hi, mr->search_item.id_lo); + if (item) + break; + map_rect_destroy_mg(mr2); + tmp=g_list_next(tmp); + } + if (item) { + if (item_attr_get(item, attr_town_streets_item, &attr)) { + mr->search_item=*attr.u.item; + map_rect_destroy_mg(mr2); + } else { + map_rect_destroy_mg(mr2); + return 0; + } + } else { + dbg(0,"wrong parent type %s %p 0x%x 0x%x\n", item_to_name(mr->search_item.type), item, mr->search_item.id_hi, mr->search_item.id_lo); + return 0; + } + } + dbg(1,"street_assoc=0x%x\n", mr->search_item.id_lo); + tree_search_init(mr->m->dirname, "strname.b1", &mr->ts, 0); mr->current_file=file_strname_stn; - mr->search_str=g_strdup(search->u.str); + mr->search_str=g_strdup(mr->search_attr->u.str); + break; + case attr_house_number: + if (!map_priv_is(mr->search_item.map, mr->m)) + return 0; + if (!housenumber_search_setup(mr)) { + dbg(0,"failed to search for attr_house_number\n"); + return 0; + } break; default: - dbg(0,"unknown search\n"); - g_free(mr); - return NULL; + dbg(0,"unknown search %s\n",attr_to_name(mr->search_type)); + return 0; } - mr->search_item=*item; - mr->search_partial=partial; mr->file=mr->m->file[mr->current_file]; block_init(mr); + return 1; +} +static void map_search_cleanup(struct map_rect_priv *mr); + +static struct item * map_search_get_item_mg(struct map_search_priv *ms); + +static struct map_search_priv * +map_search_new_mg(struct map_priv *map, struct item *item, struct attr *search, int partial) +{ + struct map_rect_priv *mr=g_new0(struct map_rect_priv, 1); + dbg(1,"searching for %s '%s'\n", attr_to_name(search->type), search->u.str); + dbg(1,"id_lo=0x%x\n", item->id_lo); + dbg(1,"search=%s\n", search->u.str); + mr->m=map; + mr->search_attr=attr_dup(search); + mr->search_type=search->type; + mr->search_item=*item; + mr->search_partial=partial; + if (search->type == attr_town_or_district_name) { + mr->search_type=attr_town_name; + mr->search_type_next=attr_district_name; + } + if (!map_search_setup(mr)) { + dbg(1,"map_search_new_mg failed\n"); + g_free(mr); + return NULL; + } + mr->search_mr_tmp=map_rect_new_mg(map, NULL); + return (struct map_search_priv *)mr; } static void +map_search_cleanup(struct map_rect_priv *mr) +{ + g_free(mr->search_str); + mr->search_str=NULL; + tree_search_free(&mr->ts); + mr->search_linear=0; + mr->search_p=NULL; + mr->search_blk_count=0; + mr->search_blk_off=NULL; + mr->search_block=0; +} + +static void map_search_destroy_mg(struct map_search_priv *ms) { struct map_rect_priv *mr=(struct map_rect_priv *)ms; @@ -431,8 +506,10 @@ map_search_destroy_mg(struct map_search_priv *ms) dbg(1,"mr=%p\n", mr); if (! mr) return; - g_free(mr->search_str); - tree_search_free(&mr->ts); + map_search_cleanup(mr); + if (mr->search_mr_tmp) + map_rect_destroy_mg(mr->search_mr_tmp); + attr_free(mr->search_attr); g_free(mr); } @@ -440,18 +517,34 @@ static struct item * map_search_get_item_mg(struct map_search_priv *ms) { struct map_rect_priv *mr=(struct map_rect_priv *)ms; + struct item *ret=NULL; if (! mr) return NULL; switch (mr->search_type) { case attr_town_postal: case attr_town_name: - return town_search_get_item(mr); + case attr_district_name: + ret=town_search_get_item(mr); + break; case attr_street_name: - return street_search_get_item(mr); + ret=street_search_get_item(mr); + break; + case attr_house_number: + ret=housenumber_search_get_item(mr); + break; default: - return NULL; + dbg(0,"unknown search %s\n",attr_to_name(mr->search_type)); + break; } + if (!ret && mr->search_type_next != attr_none) { + mr->search_type=mr->search_type_next; + mr->search_type_next=attr_none; + map_search_cleanup(mr); + map_search_setup(mr); + return map_search_get_item_mg(ms); + } + return ret; } static struct map_methods map_methods_mg = { @@ -467,6 +560,7 @@ static struct map_methods map_methods_mg = { map_search_get_item_mg, }; + struct map_priv * map_new_mg(struct map_methods *meth, struct attr **attrs) { @@ -480,8 +574,8 @@ map_new_mg(struct map_methods *meth, struct attr **attrs) if (! data) return NULL; - wexp=file_wordexp_new(data->u.str); - wexp_data=file_wordexp_get_array(wexp); + wexp=file_wordexp_new(data->u.str); + wexp_data=file_wordexp_get_array(wexp); *meth=map_methods_mg; data=attr_search(attrs, NULL, attr_data); @@ -503,6 +597,7 @@ map_new_mg(struct map_methods *meth, struct attr **attrs) g_free(filename); } } + maps=g_list_append(maps, m); return m; } diff --git a/navit/navit/map/mg/mg.h b/navit/navit/map/mg/mg.h index 22270f9..32e710f 100644 --- a/navit/navit/map/mg/mg.h +++ b/navit/navit/map/mg/mg.h @@ -136,14 +136,19 @@ struct street_name { unsigned char *tmp_data; }; +struct housenumber { + int number; + char *suffix; +}; + struct street_name_numbers { int len; int tag; int dist; int country; struct coord *c; - int first; - int last; + struct housenumber first; + struct housenumber last; int segment_count; struct street_name_segment *segments; int aux_len; @@ -161,8 +166,8 @@ struct street_name_number { int len; int tag; struct coord *c; - int first; - int last; + struct housenumber first; + struct housenumber last; struct street_name_segment *segment; }; @@ -186,9 +191,20 @@ struct street_priv { int bytes; int more; int flags; + int housenumber; + int cidx; + struct coord hnc[100]; + struct housenumber hn[100]; + int hn_count; struct street_name name; + struct street_name_numbers name_numbers; + struct street_name_number name_number; enum attr_type attr_next; char debug[256]; + char first_number[32]; + char last_number[32]; + char current_number[32]; + GHashTable *streetname_hash; }; enum file_index { @@ -209,7 +225,13 @@ enum file_index { file_tunnel_ply, file_water_ply, file_woodland_ply, - file_end + file_end, + file_town_twn_alt1, + file_town_twn_alt2, + file_street_str_alt1, + file_street_str_alt2, + file_street_str_alt3, + file_street_str_alt4, }; struct map_priv { @@ -286,12 +308,15 @@ struct map_rect_priv { struct tree_search ts; int search_country; struct item search_item; + struct attr *search_attr; char *search_str; int search_partial; int search_linear; unsigned char *search_p; int search_blk_count; - enum attr_type search_type; + enum attr_type search_type,search_type_next; + struct map_rect_priv *search_mr_tmp; + struct item *search_item_tmp; struct block_offset *search_blk_off; int search_block; GHashTable *block_hash[file_end]; @@ -315,6 +340,7 @@ int poly_get(struct map_rect_priv *mr, struct poly_priv *poly, struct item *item int poly_get_byid(struct map_rect_priv *mr, struct poly_priv *poly, int id_hi, int id_lo, struct item *item); int street_get(struct map_rect_priv *mr, struct street_priv *street, struct item *item); int street_get_byid(struct map_rect_priv *mr, struct street_priv *street, int id_hi, int id_lo, struct item *item); +int street_name_get_byid(struct map_rect_priv *mr, struct street_priv *street, int id_hi, int id_lo, struct item *item); struct item * street_search_get_item(struct map_rect_priv *mr); void tree_search_init(char *dirname, char *filename, struct tree_search *ts, int offset); void tree_search_free(struct tree_search *ts); diff --git a/navit/navit/map/mg/street.c b/navit/navit/map/mg/street.c index f3b0575..6faa2ea 100644 --- a/navit/navit/map/mg/street.c +++ b/navit/navit/map/mg/street.c @@ -19,14 +19,51 @@ #include #include +#include #include "debug.h" #include "mg.h" int coord_debug; +#if 0 +static void street_name_numbers_get(struct street_name_numbers *name_numbers, unsigned char **p); +static void street_name_number_get(struct street_name_number *name_number, unsigned char **p); + +static void +street_name_debug(struct street_name *sn, FILE *out) +{ + struct street_name_numbers nns; + unsigned char *p=sn->aux_data; + unsigned char *end=p+sn->aux_len; + int i; + + while (p < end) { + unsigned char *pn,*pn_end; + struct street_name_number nn; + street_name_numbers_get(&nns, &p); + fprintf(out,"0x%x 0x%x type=town_label label=\"%s(%d):0x%x:%d%s-%d%s\" debug=\"len=0x%x\"",nns.c->x,nns.c->y,sn->name2, sn->segment_count, nns.tag, nns.first.number,nns.first.suffix,nns.last.number,nns.last.suffix,nns.len); + for (i = 0 ; i < sn->segment_count ; i++) { + fprintf(out," debug=\"segment(%d)=0x%x\"",i,sn->segments[i].segid); + } + fprintf(out,"\n"); + pn=nns.aux_data; + pn_end=nns.aux_data+nns.aux_len; + while (pn < pn_end) { + street_name_number_get(&nn, &pn); + fprintf(out,"0x%x 0x%x type=town_label label=\"%s:0x%x:%d%s-%d%s\" debug=\"len=0x%x\"\n", nn.c->x, nn.c->y, sn->name2, nn.tag, nn.first.number, nn.first.suffix, nn.last.number,nn.last.suffix,nn.len); + } + } + fflush(out); +} +#endif + static void street_name_get(struct street_name *name, unsigned char **p) { +#if 0 + static FILE *out; + static GHashTable *hash; +#endif unsigned char *start=*p; name->len=get_u16_unal(p); name->country=get_u16_unal(p); @@ -41,6 +78,24 @@ street_name_get(struct street_name *name, unsigned char **p) name->tmp_len=name->aux_len; name->tmp_data=name->aux_data; *p=start+name->len; +#if 0 + if (! out) { + out=fopen("hn.txt","a"); + } + if (! hash) { + hash=g_hash_table_new(NULL,NULL); + } + if (! g_hash_table_lookup(hash, *p)) { + g_hash_table_insert(hash, *p, (void *)1); + street_name_debug(name, out); + } +#endif +} + +static int +street_name_eod(struct street_name *name) +{ + return (name->tmp_data >= name->aux_data+name->aux_len); } static void @@ -52,8 +107,10 @@ street_name_numbers_get(struct street_name_numbers *name_numbers, unsigned char name_numbers->dist=get_u32_unal(p); name_numbers->country=get_u32_unal(p); name_numbers->c=coord_get(p); - name_numbers->first=get_u24_unal(p); - name_numbers->last=get_u24_unal(p); + name_numbers->first.number=get_u16_unal(p); + name_numbers->first.suffix=get_string(p); + name_numbers->last.number=get_u16_unal(p); + name_numbers->last.suffix=get_string(p); name_numbers->segment_count=get_u32_unal(p); name_numbers->segments=(struct street_name_segment *)(*p); (*p)+=sizeof(struct street_name_segment)*name_numbers->segment_count; @@ -64,6 +121,27 @@ street_name_numbers_get(struct street_name_numbers *name_numbers, unsigned char *p=start+name_numbers->len; } +static int +street_name_numbers_eod(struct street_name_numbers *name_numbers) +{ + return (name_numbers->tmp_data >= name_numbers->aux_data+name_numbers->aux_len); +} + + +static int +street_name_numbers_get_byid(struct street_name_numbers *name_numbers, struct street_name *name, int id) +{ + unsigned char *p=name->aux_data; + unsigned char *end=p+name->aux_len; + while (id >= 0) { + if (p >= end) + return 0; + street_name_numbers_get(name_numbers, &p); + id--; + } + return 1; +} + static void street_name_number_get(struct street_name_number *name_number, unsigned char **p) { @@ -71,12 +149,28 @@ street_name_number_get(struct street_name_number *name_number, unsigned char **p name_number->len=get_u16_unal(p); name_number->tag=get_u8(p); name_number->c=coord_get(p); - name_number->first=get_u24_unal(p); - name_number->last=get_u24_unal(p); + name_number->first.number=get_u16_unal(p); + name_number->first.suffix=get_string(p); + name_number->last.number=get_u16_unal(p); + name_number->last.suffix=get_string(p); name_number->segment=(struct street_name_segment *)p; *p=start+name_number->len; } +static int +street_name_number_get_byid(struct street_name_number *name_number, struct street_name_numbers *name_numbers, int id) +{ + unsigned char *p=name_numbers->tmp_data; + unsigned char *end=p+name_numbers->tmp_len; + while (id >= 0) { + if (p >= end) + return 0; + street_name_number_get(name_number, &p); + id--; + } + return 1; +} + static void street_name_get_by_id(struct street_name *name, struct file *file, unsigned long id) { @@ -165,8 +259,10 @@ street_coord_get_begin(unsigned char **p) static void street_coord_rewind(void *priv_data) { - /* struct street_priv *street=priv_data; */ + struct street_priv *street=priv_data; + street->p=street->next=NULL; + street->status=street->status_rewind; } static int @@ -193,6 +289,9 @@ street_coord_get(void *priv_data, struct coord *c, int count) { struct street_priv *street=priv_data; int ret=0,i,scount; +#ifdef DEBUG_COORD_GET + int segid,debug=0; +#endif if (! street->p && count) { street->p=street->coord_begin; @@ -204,8 +303,23 @@ street_coord_get(void *priv_data, struct coord *c, int count) } street->status_rewind=street->status=L(street->str[1].segid) >= 0 ? 0:1; } +#ifdef DEBUG_COORD_GET + segid=street->str[0].segid; + if (segid < 0) + segid=-segid; + if (segid == 0x15) + debug=1; + if (debug) { + dbg(0,"enter 0x%x\n",segid); + } +#endif while (count > 0) { if (street_coord_get_helper(street, c)) { +#ifdef DEBUG_COORD_GET + if (debug) { + dbg(0,"0x%x,0x%x\n", c->x, c->y); + } +#endif c++; ret++; count--; @@ -217,7 +331,7 @@ street_coord_get(void *priv_data, struct coord *c, int count) return ret; } -static void + static void street_attr_rewind(void *priv_data) { /* struct street_priv *street=priv_data; */ @@ -316,6 +430,190 @@ street_get_data(struct street_priv *street, unsigned char **p) } +static void +street_housenumber_coord_rewind(void *priv_data) +{ + struct street_priv *street=priv_data; + street->cidx=0; +} + +static void +street_housenumber_attr_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static int +street_housenumber_coord_get(void *priv_data, struct coord *c, int count) +{ + struct street_priv *street=priv_data; + if (street->cidx || !count || !street->name.len) + return 0; + *c=street->hnc[street->housenumber-2]; + street->cidx=1; + return 1; +} + +static int +street_housenumber_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct street_priv *street=priv_data; + struct housenumber *hn; + attr->type=attr_type; + switch (attr_type) { + case attr_label: + hn=&street->hn[street->housenumber-2]; + sprintf(street->debug,"%d%s",hn->number,hn->suffix); + attr->u.str=street->debug; + return 1; + default: + dbg(0,"unknown item\n"); + return 0; + } +} + +static struct item_methods street_housenumber_meth = { + street_housenumber_coord_rewind, + street_housenumber_coord_get, + street_housenumber_attr_rewind, + street_housenumber_attr_get, +}; + +static void +project(struct coord *c, int count, int di, int dlr, struct coord *ch) +{ + struct coord cr; + int dx,dy; + int l; + + if (di > 0) { + dx=c[1].x-c[0].x; + dy=c[1].y-c[0].y; + cr=c[0]; + } else if (di < 0) { + dx=c[count-1].x-c[count-2].x; + dy=c[count-1].y-c[count-2].y; + cr=c[count-1]; + } else { + dx=c[1].x-c[0].x; + dy=c[1].y-c[0].y; + di=0; + if (count % 2) { + cr=c[count/2]; + } else { + cr.x=(c[count/2-1].x+c[count/2].x)/2; + cr.y=(c[count/2-1].y+c[count/2].y)/2; + } + } + l=sqrtf(dx*dx+dy*dy); + if (!l) { + *ch=cr; + return; + } + ch->x=cr.x+(di*dx+dlr*dy)/l; + ch->y=cr.y+(di*dy-dlr*dx)/l; +} + +static int +street_lookup_housenumber(struct street_priv *street) +{ + int i,count,scount,maxcount=16384; + struct coord c[maxcount]; + struct street_name_numbers nns; + unsigned char *p=street->name.aux_data; + unsigned char *end=p+street->name.aux_len; + unsigned char *pn,*pn_end; + + street->hn_count=0; + street_coord_rewind(street); + scount=street_coord_get(street, c, maxcount/2); + if (scount >= maxcount/2) { + dbg(0,"overflow"); + } + for (i = 0 ; i < scount-1 ; i++) { + c[scount+i].x=(c[i].x+c[i+1].x)/2; + c[scount+i].y=(c[i].y+c[i+1].y)/2; + } + count=scount*2-1; + while (p < end) { + struct street_name_number nn; + street_name_numbers_get(&nns, &p); + pn=nns.aux_data; + pn_end=nns.aux_data+nns.aux_len; + while (pn < pn_end) { + street_name_number_get(&nn, &pn); + for (i = 0 ; i < count ; i++) { + int dx=nn.c->x-c[i].x; + int dy=nn.c->y-c[i].y; + int dlr,dir; + if (dx < 3 && dx > -3 && dy < 3 && dy > -3) { + dir=15; + dlr=15; + switch (nn.tag & 0xf) { + case 0xa: + break; + case 0xb: + dlr=-dlr; + dir=-dir; + break; + case 0xe: + dlr=-dlr; + break; + case 0xf: + dir=-dir; + break; + default: + dbg(0,"unknown tag 0x%x\n",nn.tag); +#if 0 + continue; +#endif + } + if (street->str->type & 0x40) { + dir=-dir; + dlr=-dlr; + } + if (nn.first.number == nn.last.number && !strcmp(nn.first.suffix, nn.last.suffix)) + dir=0; + project(c, scount, dir, dlr, &street->hnc[street->hn_count]); + street->hn[street->hn_count]=nn.first; + street->hn_count++; + g_assert(street->hn_count < 100); + project(c, scount, -dir, dlr, &street->hnc[street->hn_count]); + street->hn[street->hn_count]=nn.last; + street->hn_count++; + g_assert(street->hn_count < 100); + dbg(1,"found %d%s %d%s\n",nn.first.number,nn.first.suffix,nn.last.number,nn.last.suffix); + } + } + } + } + return 1; +} + +static int +street_get_housenumber(struct map_rect_priv *mr, struct street_priv *street, struct item *item) +{ + int nameid; + nameid=L(street->str->nameid); + if (! nameid) + return 0; + if (! street->name.len) + street_name_get_by_id(&street->name,street->name_file,nameid); + if (! street->name.aux_len) + return 0; + if (!street->hn_count) + street_lookup_housenumber(street); + if (street->housenumber > street->hn_count) + return 0; + item->type=type_town_label; + item->id_hi = (item->id_hi & 0xffffff) | (street->housenumber*0x10000000+0x1000000); + item->meth=&street_housenumber_meth; + street->cidx=0; + street->housenumber++; + return 1; +} + /*0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 */ static unsigned char limit[]={0,0,1,1,1,2,2,4,6,6,12,13,14,20,20,20,20,20,20}; @@ -328,6 +626,13 @@ street_get(struct map_rect_priv *mr, struct street_priv *street, struct item *it struct coord c; street_coord_get(street, &c, 1); } +#if 0 + if (street->housenumber) { + if (street_get_housenumber(mr, street, item)) + return 1; + street->housenumber=0; + } +#endif if (mr->b.p == mr->b.p_start) { street_get_data(street, &mr->b.p); street->name_file=mr->m->file[file_strname_stn]; @@ -447,8 +752,12 @@ street_get(struct map_rect_priv *mr, struct street_priv *street, struct item *it street->name.len=0; street->attr_next=attr_label; street->more=1; + street->housenumber=1; + street->hn_count=0; if (!map_selection_contains_item(mr->cur_sel, 0, item->type)) continue; + item->meth=&street_meth; + item->priv_data=street; return 1; } } @@ -486,7 +795,6 @@ street_get_byid(struct map_rect_priv *mr, struct street_priv *street, int id_hi, return 0; } - struct street_name_index { int block; @@ -520,7 +828,7 @@ latin1_tolower_ascii(unsigned char c) return 'u'; default: if (ret >= 0x80) - dbg(0,"ret=0x%x\n",c); + dbg(1,"ret=0x%x\n",c); return ret; } } @@ -678,30 +986,9 @@ street_name_coord_get(void *priv_data, struct coord *c, int count) return 0; } -static int -street_name_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +static void +debug(struct map_rect_priv *mr) { - struct map_rect_priv *mr=priv_data; - struct item *item; - - attr->type=attr_type; - switch (attr_type) { - case attr_street_name: - attr->u.str=mr->street.name.name2; - return ((attr->u.str && attr->u.str[0]) ? 1:0); - case attr_street_name_systematic: - attr->u.str=mr->street.name.name1; - return ((attr->u.str && attr->u.str[0]) ? 1:0); - case attr_street_name_numbers_item: - item=&mr->item3.item; - attr->u.item=item; - item->type=type_street_name_numbers; - item->id_hi=0; - item->id_lo=1; - item->meth=&street_name_numbers_meth; - item->map=NULL; - item->priv_data=mr; - { int i; struct street_name_numbers nns; unsigned char *p=mr->street.name.aux_data; @@ -722,8 +1009,8 @@ street_name_attr_get(void *priv_data, enum attr_type attr_type, struct attr *att printf(" dist 0x%x\n", nns.dist); printf(" country 0x%x\n", nns.country); printf(" coord 0x%x,0x%x\n", nns.c->x, nns.c->y); - printf(" first %d\n", nns.first); - printf(" last %d\n", nns.last); + printf(" first %d\n", nns.first.number); + printf(" last %d\n", nns.last.number); printf(" segment count 0x%x\n", nns.segment_count); printf(" aux_len 0x%x\n", nns.aux_len); pn=nns.aux_data; @@ -734,15 +1021,39 @@ street_name_attr_get(void *priv_data, enum attr_type attr_type, struct attr *att printf(" len 0x%x\n", nn.len); printf(" tag 0x%x\n", nn.tag); printf(" coord 0x%x,0x%x\n", nn.c->x, nn.c->y); - printf(" first %d\n", nn.first); - printf(" last %d\n", nn.last); + printf(" first %d\n", nn.first.number); + printf(" last %d\n", nn.last.number); } } } - } - return 1; +} + +static int +street_name_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct map_rect_priv *mr=priv_data; + struct item *item; + struct attr attrd; + + attr->type=attr_type; + switch (attr_type) { + case attr_street_name: + attr->u.str=mr->street.name.name2; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_street_name_systematic: + attr->u.str=mr->street.name.name1; + return ((attr->u.str && attr->u.str[0]) ? 1:0); + case attr_town_name: + case attr_district_name: + case attr_postal: + if (!mr->search_item_tmp) + mr->search_item_tmp=map_rect_get_item_byid_mg(mr->search_mr_tmp, mr->street.name_numbers.country | (file_town_twn << 16), mr->street.name_numbers.dist); + if (!mr->search_item_tmp) + return 0; + return item_attr_get(mr->search_item_tmp, attr_type, attr); default: - dbg(0,"unknown item\n"); + dbg(0,"%p\n",mr->street.name_numbers.dist); + dbg(0,"unknown attr %s\n",attr_to_name(attr_type)); return 0; } } @@ -759,8 +1070,25 @@ static struct item_methods street_name_meth = { }; -struct item * -street_search_get_item(struct map_rect_priv *mr) +int +street_name_get_byid(struct map_rect_priv *mr, struct street_priv *street, int id_hi, int id_lo, struct item *item) +{ + mr->current_file=id_hi >> 16; + street->name_file=mr->m->file[mr->current_file]; + item->type=type_street_name; + item->id_hi=id_hi; + item->id_lo=id_lo; + item->meth=&street_name_meth; + item->map=NULL; + item->priv_data=mr; + mr->b.p=street->name_file->begin+item->id_lo; + dbg(1,"last %p map %p file %d begin %p\n", mr->b.p, mr->m, mr->current_file, mr->m->file[mr->current_file]->begin); + street_name_get(&street->name, &mr->b.p); + return 1; +} + +static struct item * +street_search_get_item_street_name(struct map_rect_priv *mr) { int dir=1,leaf; unsigned char *last; @@ -806,14 +1134,255 @@ street_search_get_item(struct map_rect_priv *mr) if (!dir) { dbg(1,"result country 0x%x assoc 0x%x name1 '%s' name2 '%s' dir=%d aux_data=%p len=0x%x\n", mr->street.name.country, mr->street.name.townassoc, mr->street.name.name1, mr->street.name.name2, dir, mr->street.name.aux_data, mr->street.name.aux_len); mr->item.type = type_street_name; - mr->item.id_hi=mr->street.name.country | (mr->current_file << 16) | 0x10000000; - mr->item.id_lo=last-mr->m->file[mr->current_file]->begin; + mr->item.id_hi=(file_strname_stn << 16); + mr->item.id_lo=last-mr->m->file[file_strname_stn]->begin; + dbg(1,"id 0x%x 0x%x last %p map %p file %d begin %p\n", mr->item.id_hi, mr->item.id_lo, last, mr->m, mr->current_file, mr->m->file[mr->current_file]->begin); mr->item.meth=&street_name_meth; mr->item.map=NULL; mr->item.priv_data=mr; + /* debug(mr); */ + dbg(1,"last %p\n",last); return &mr->item; } } } } - + +static void +district_debug(struct map_rect_priv *mr, int country, int dist) +{ + struct map_rect_priv *mrt; + struct item *item; + struct attr attrn; + + mrt=map_rect_new_mg(mr->m, NULL); + item=map_rect_get_item_byid_mg(mrt, country | (file_town_twn << 16), dist); + dbg(0,"item=%p\n",item); + if (item_attr_get(item, attr_town_postal, &attrn)) + dbg(0,"postal=%s\n",attrn.u.str); + if (item_attr_get(item, attr_town_name, &attrn)) + dbg(0,"town_name=%s\n",attrn.u.str); + if (item_attr_get(item, attr_district_name, &attrn)) + dbg(0,"district_name=%s\n",attrn.u.str); + map_rect_destroy_mg(mrt); +} + +static int +street_name_numbers_get_next(struct map_rect_priv *mr, struct street_name *name, char *start, char **p, int mode, int *id, struct street_name_numbers *ret) +{ + struct street_name_numbers tmp; + char *s,*ps,*pt; + int found; + while (*p < name->aux_data+name->aux_len) { + ps=*p; + street_name_numbers_get(ret, p); + (*id)++; + found=0; + pt=name->aux_data; + while (pt < ps) { + street_name_numbers_get(&tmp, &pt); + if (tmp.country == ret->country && tmp.dist == ret->dist) { + found=1; + break; + } + } + if (!found) { + dbg(0,"district 0x%x\n",ret->dist); + district_debug(mr, ret->country, ret->dist); + return 1; + } + } + return 0; +} + + +static struct item * +street_search_get_item_street_name_district(struct map_rect_priv *mr, int flag) +{ + struct street_name_numbers name_numbers; + int id=mr->item.id_hi & 0xff; + if (street_name_eod(&mr->street.name)) + return NULL; + if (!street_name_numbers_get_next(mr, &mr->street.name, NULL, &mr->street.name.tmp_data, 1, &mr->item.id_hi, &mr->street.name_numbers)) + return NULL; + return &mr->item; +} + +struct item * +street_search_get_item(struct map_rect_priv *mr) +{ + struct item *item; + for (;;) { + if (!mr->street.name.tmp_data || street_name_eod(&mr->street.name)) { + item=street_search_get_item_street_name(mr); + if (!item) + return NULL; + if (!mr->street.name.aux_len) + return item; + } + mr->item.id_hi++; + street_name_numbers_get(&mr->street.name_numbers, &mr->street.name.tmp_data); + mr->search_item_tmp=NULL; + return &mr->item; + } +} + +static int +street_name_numbers_next(struct map_rect_priv *mr) +{ + if (street_name_eod(&mr->street.name)) + return 0; + dbg(1,"%p vs %p\n",mr->street.name.tmp_data, mr->street.name.aux_data); + street_name_numbers_get(&mr->street.name_numbers, &mr->street.name.tmp_data); + return 1; +} + +static int +street_name_number_next(struct map_rect_priv *mr) +{ + if (street_name_numbers_eod(&mr->street.name_numbers)) + return 0; + street_name_number_get(&mr->street.name_number, &mr->street.name_numbers.tmp_data); + sprintf(mr->street.first_number,"%d%s",mr->street.name_number.first.number,mr->street.name_number.first.suffix); + sprintf(mr->street.last_number,"%d%s",mr->street.name_number.last.number,mr->street.name_number.last.suffix); + mr->street.current_number[0]='\0'; + return 1; +} + +static void +housenumber_coord_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static void +housenumber_attr_rewind(void *priv_data) +{ + /* struct street_priv *street=priv_data; */ + +} + +static int +housenumber_coord_get(void *priv_data, struct coord *c, int count) +{ + return 0; +} + +static int +housenumber_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) +{ + struct map_rect_priv *mr=priv_data,*mrt; + struct item *item; + struct attr attrn; + attr->type=attr_type; + switch (attr_type) { + case attr_house_number: + attr->u.str=mr->street.current_number; + return 1; + case attr_town_name: + case attr_district_name: + case attr_postal: + if (!mr->search_item_tmp) + mr->search_item_tmp=map_rect_get_item_byid_mg(mr->search_mr_tmp, mr->street.name_numbers.country | (file_town_twn << 16), mr->street.name_numbers.dist); + if (!mr->search_item_tmp) + return 0; + return item_attr_get(mr->search_item_tmp, attr_type, attr); + default: + dbg(0,"unknown attr %s\n",attr_to_name(attr_type)); + return 0; + } +} + + +static struct item_methods housenumber_meth = { + housenumber_coord_rewind, + housenumber_coord_get, + housenumber_attr_rewind, + housenumber_attr_get, +}; + +int +housenumber_search_setup(struct map_rect_priv *mr) +{ + dbg(1,"enter (0x%x,0x%x)\n",mr->search_item.id_hi,mr->search_item.id_lo); + int id=mr->search_item.id_hi & 0xff; + mr->current_file=file_strname_stn; + mr->street.name_file=mr->m->file[mr->current_file]; + mr->b.p=mr->street.name_file->begin+mr->search_item.id_lo; + mr->search_str=g_strdup(mr->search_attr->u.str); + dbg(1,"last %p\n",mr->b.p); + street_name_get(&mr->street.name, &mr->b.p); +#if 0 + debug(mr); +#endif + while (id > 0) { + id--; + dbg(1,"loop\n"); + if (!street_name_numbers_next(mr)) + return 0; + } + mr->item.type=type_house_number; + mr->item.priv_data=mr; + mr->item.id_hi=mr->search_item.id_hi + 0x100; + mr->item.meth=&housenumber_meth; + if (!id) + mr->item.id_hi+=1; + mr->item.id_lo=mr->search_item.id_lo; + dbg(1,"getting name_number %p vs %p + %d\n",mr->street.name_numbers.tmp_data,mr->street.name_numbers.aux_data, mr->street.name_numbers.aux_len); + if (!street_name_number_next(mr)) + return 0; + dbg(1,"enter\n"); + // debug(mr); + return 1; +} + +int +house_number_next(char *number, char *first, char *last, int interpolation, int *percentage) +{ + int firstn=atoi(first); + int lastn=atoi(last); + int current,delta,len=lastn-firstn; + if (interpolation) { + len/=2; + } + if (!number[0]) { + strcpy(number,first); + delta=0; + } else { + current=atoi(number)+(interpolation ? 2:1); + if (current > lastn) + return 0; + sprintf(number,"%d",current); + delta=current-firstn; + } + if (percentage) { + if (len) + *percentage=delta*100/len; + else + percentage=50; + } + return 1; +} + +struct item * +housenumber_search_get_item(struct map_rect_priv *mr) +{ + int d; + dbg(1,"enter %s %s\n",mr->street.first_number,mr->street.last_number); + for (;;) { + if (!house_number_next(mr->street.current_number, mr->street.first_number, mr->street.last_number, 0, NULL)) { + if (!street_name_number_next(mr)) + return NULL; + continue; + } + if (mr->search_partial) + d=strncasecmp(mr->search_str, mr->street.current_number, strlen(mr->search_str)); + else + d=strcasecmp(mr->search_str, mr->street.current_number); + if (!d) { + mr->search_item_tmp=NULL; + return &mr->item; + } + } +} diff --git a/navit/navit/map/mg/town.c b/navit/navit/map/mg/town.c index e22b8d3..cee0468 100644 --- a/navit/navit/map/mg/town.c +++ b/navit/navit/map/mg/town.c @@ -79,6 +79,7 @@ town_attr_get(void *priv_data, enum attr_type attr_type, struct attr *attr) twn->attr_next=attr_town_postal; return ((attr->u.str && attr->u.str[0]) ? 1:0); case attr_town_postal: + case attr_postal: strncpy(twn->postal, twn->postal_code1, 32); attr->u.str=twn->postal; len=mg_country_postal_len(twn->country); @@ -252,7 +253,7 @@ town_search_get_item(struct map_rect_priv *mr) if (! mr->search_linear) { while ((leaf=tree_search_next(&mr->ts, &mr->search_p, dir)) != -1) { dir=town_search_compare(&mr->search_p, mr); - if (! dir && leaf) { + if (! dir) { mr->search_linear=1; mr->search_p=NULL; break; diff --git a/navit/navit/map/mg/tree.c b/navit/navit/map/mg/tree.c index 695b401..0c2a4bb 100644 --- a/navit/navit/map/mg/tree.c +++ b/navit/navit/map/mg/tree.c @@ -259,5 +259,6 @@ tree_search_init(char *dirname, char *filename, struct tree_search *ts, int offs void tree_search_free(struct tree_search *ts) { - file_destroy(ts->f); + if (ts->f) + file_destroy(ts->f); } diff --git a/navit/navit/search.c b/navit/navit/search.c index 16d223d..7c8b7fd 100644 --- a/navit/navit/search.c +++ b/navit/navit/search.c @@ -29,7 +29,7 @@ struct search_list_level { struct mapset *ms; - struct item *parent; + struct search_list_common *parent; struct attr attr; int partial; int selected; @@ -43,6 +43,8 @@ struct search_list { int level; struct search_list_level levels[4]; struct search_list_result result; + struct search_list_result last_result; + int last_result_valid; }; static guint @@ -90,10 +92,15 @@ search_list_level(enum attr_type attr_type) case attr_town_postal: return 1; case attr_town_name: + case attr_district_name: + case attr_town_or_district_name: return 1; case attr_street_name: return 2; + case attr_house_number: + return 3; default: + dbg(0,"unknown search '%s'\n",attr_to_name(attr_type)); return -1; } } @@ -103,7 +110,7 @@ search_list_search(struct search_list *this_, struct attr *search_attr, int part { struct search_list_level *le; int level=search_list_level(search_attr->type); - dbg(0,"level=%d\n", level); + dbg(1,"level=%d\n", level); if (level != -1) { this_->result.id=0; this_->level=level; @@ -156,7 +163,7 @@ search_list_country_new(struct item *item) struct search_list_country *ret=g_new0(struct search_list_country, 1); struct attr attr; - ret->item=*item; + ret->common.item=ret->common.unique=*item; if (item_attr_get(item, attr_country_car, &attr)) ret->car=g_strdup(attr.u.str); if (item_attr_get(item, attr_country_iso2, &attr)) { @@ -189,23 +196,28 @@ search_list_town_new(struct item *item) struct coord c; ret->itemt=*item; + ret->common.item=ret->common.unique=*item; if (item_attr_get(item, attr_town_streets_item, &attr)) { dbg(1,"town_assoc 0x%x 0x%x\n", attr.u.item->id_hi, attr.u.item->id_lo); - ret->item=*attr.u.item; + ret->common.unique=*attr.u.item; } - else - ret->item=*item; if (item_attr_get(item, attr_town_name, &attr)) ret->name=map_convert_string(item->map,attr.u.str); + else + ret->name=NULL; if (item_attr_get(item, attr_town_postal, &attr)) - ret->postal=map_convert_string(item->map,attr.u.str); + ret->common.postal=map_convert_string(item->map,attr.u.str); + else + ret->common.postal=NULL; if (item_attr_get(item, attr_district_name, &attr)) ret->district=map_convert_string(item->map,attr.u.str); + else + ret->district=NULL; if (item_coord_get(item, &c, 1)) { - ret->c=g_new(struct pcoord, 1); - ret->c->x=c.x; - ret->c->y=c.y; - ret->c->pro = map_projection(item->map); + ret->common.c=g_new(struct pcoord, 1); + ret->common.c->x=c.x; + ret->common.c->y=c.y; + ret->common.c->pro = map_projection(item->map); } return ret; } @@ -214,12 +226,30 @@ static void search_list_town_destroy(struct search_list_town *this_) { map_convert_free(this_->name); - map_convert_free(this_->postal); - if (this_->c) - g_free(this_->c); + map_convert_free(this_->common.postal); + if (this_->common.c) + g_free(this_->common.c); g_free(this_); } +static void +search_list_common_new(struct item *item, struct search_list_common *common) +{ + struct attr attr; + if (item_attr_get(item, attr_town_name, &attr)) + common->town_name=map_convert_string(item->map, attr.u.str); + else + common->town_name=NULL; + if (item_attr_get(item, attr_district_name, &attr)) + common->district_name=map_convert_string(item->map, attr.u.str); + else + common->district_name=NULL; + if (item_attr_get(item, attr_postal, &attr)) + common->postal=map_convert_string(item->map, attr.u.str); + else + common->postal=NULL; +} + static struct search_list_street * search_list_street_new(struct item *item) { @@ -227,27 +257,68 @@ search_list_street_new(struct item *item) struct attr attr; struct coord c; - ret->item=*item; + ret->common.item=ret->common.unique=*item; if (item_attr_get(item, attr_street_name, &attr)) ret->name=map_convert_string(item->map, attr.u.str); + else + ret->name=NULL; + search_list_common_new(item, &ret->common); if (item_coord_get(item, &c, 1)) { - ret->c=g_new(struct pcoord, 1); - ret->c->x=c.x; - ret->c->y=c.y; - ret->c->pro = map_projection(item->map); + ret->common.c=g_new(struct pcoord, 1); + ret->common.c->x=c.x; + ret->common.c->y=c.y; + ret->common.c->pro = map_projection(item->map); } return ret; } static void +search_list_common_destroy(struct search_list_common *common) +{ + map_convert_free(common->town_name); + map_convert_free(common->district_name); + map_convert_free(common->postal); +} + +static void search_list_street_destroy(struct search_list_street *this_) { map_convert_free(this_->name); - if (this_->c) - g_free(this_->c); + search_list_common_destroy(&this_->common); + if (this_->common.c) + g_free(this_->common.c); g_free(this_); } +static struct search_list_house_number * +search_list_house_number_new(struct item *item) +{ + struct search_list_house_number *ret=g_new0(struct search_list_house_number, 1); + struct attr attr; + struct coord c; + + ret->common.item=ret->common.unique=*item; + if (item_attr_get(item, attr_house_number, &attr)) + ret->house_number=map_convert_string(item->map, attr.u.str); + search_list_common_new(item, &ret->common); + if (item_coord_get(item, &c, 1)) { + ret->common.c=g_new(struct pcoord, 1); + ret->common.c->x=c.x; + ret->common.c->y=c.y; + ret->common.c->pro = map_projection(item->map); + } + return ret; +} + +static void +search_list_house_number_destroy(struct search_list_house_number *this_) +{ + map_convert_free(this_->house_number); + search_list_common_destroy(&this_->common); + if (this_->common.c) + g_free(this_->common.c); + g_free(this_); +} static void search_list_result_destroy(int level, void *p) @@ -262,6 +333,9 @@ search_list_result_destroy(int level, void *p) case 2: search_list_street_destroy(p); break; + case 3: + search_list_house_number_destroy(p); + break; } } @@ -293,14 +367,51 @@ search_list_search_free(struct search_list *sl, int level) } +static char * +postal_merge(char *mask, char *new) +{ + dbg(1,"enter %s %s\n", mask, new); + int i; + char *ret=NULL; + if (!new) + return NULL; + if (!mask) + return g_strdup(new); + i=0; + while (mask[i] && new[i]) { + if (mask[i] != '.' && mask[i] != new[i]) + break; + i++; + + } + if (mask[i]) { + ret=g_strdup(mask); + while (mask[i]) + ret[i++]='.'; + } + dbg(1,"merged %s with %s as %s\n", mask, new, ret); + return ret; +} + static int -search_add_result(struct search_list_level *le, void *p) +search_add_result(struct search_list_level *le, struct search_list_common *slc) { - if (! g_hash_table_lookup(le->hash, p)) { - g_hash_table_insert(le->hash, p, (void *)1); - le->list=g_list_append(le->list, p); + struct search_list_common *slo; + char *merged; + slo=g_hash_table_lookup(le->hash, &slc->unique); + if (!slo) { + g_hash_table_insert(le->hash, &slc->unique, slc); + if (slc->postal && !slc->postal_mask) { + slc->postal_mask=g_strdup(slc->postal); + } + le->list=g_list_append(le->list, slc); return 1; } + merged=postal_merge(slo->postal_mask, slc->postal); + if (merged) { + g_free(slo->postal_mask); + slo->postal_mask=merged; + } return 0; } @@ -338,9 +449,9 @@ search_list_get_result(struct search_list *this_) } } if (le->parent) - dbg(1,"mapset_search_new with item(%d,%d)\n", le->parent->id_hi, le->parent->id_lo); - dbg(1,"attr=%s\n", attr_to_name(le->attr.type)); - le->search=mapset_search_new(this_->ms, le->parent, &le->attr, le->partial); + dbg(1,"mapset_search_new with item(%d,%d)\n", le->parent->item.id_hi, le->parent->item.id_lo); + dbg(1,"attr=%s\n", attr_to_name(le->attr.type)); + le->search=mapset_search_new(this_->ms, &le->parent->item, &le->attr, le->partial); le->hash=g_hash_table_new(search_item_hash_hash, search_item_hash_equal); } dbg(1,"le->search=%p\n", le->search); @@ -362,15 +473,23 @@ search_list_get_result(struct search_list *this_) p=search_list_town_new(item); this_->result.country=this_->levels[0].last->data; this_->result.town=p; - this_->result.c=this_->result.town->c; + this_->result.c=this_->result.town->common.c; break; case 2: p=search_list_street_new(item); this_->result.country=this_->levels[0].last->data; this_->result.town=this_->levels[1].last->data; this_->result.street=p; - this_->result.c=this_->result.street->c; + this_->result.c=this_->result.street->common.c; break; + case 3: + p=search_list_house_number_new(item); + this_->result.country=this_->levels[0].last->data; + this_->result.town=this_->levels[1].last->data; + this_->result.street=this_->levels[2].last->data; + this_->result.house_number=p; + this_->result.c=this_->result.street->common.c; + } if (p) { if (search_add_result(le, p)) { @@ -400,3 +519,169 @@ void search_init(void) { } + +#if 0 +static char * +search_fix_spaces(char *str) +{ + int i; + int len=strlen(str); + char c,*s,*d,*ret=g_strdup(str); + + for (i = 0 ; i < len ; i++) { + if (ret[i] == ',' || ret[i] == ',' || ret[i] == '/') + ret[i]=' '; + } + s=ret; + d=ret; + len=0; + do { + c=*s++; + if (c != ' ' || len != 0) { + *d++=c; + len++; + } + while (c == ' ' && *s == ' ') + s++; + if (c == ' ' && *s == '\0') { + d--; + len--; + } + } while (c); + return ret; +} + +static GList * +search_split_phrases(char *str) +{ + char *tmp,*s,*d; + s=str; + GList *ret=NULL; + do { + tmp=g_strdup(s); + d=tmp+strlen(s)-1; + ret=g_list_append(ret, g_strdup(s)); + while (d >= tmp) { + if (*d == ' ') { + *d = '\0'; + ret=g_list_append(ret, g_strdup(tmp)); + } + d--; + } + g_free(tmp); + do { + s++; + if (*s == ' ') { + s++; + break; + } + } while (*s != '\0'); + } while (*s != '\0'); + return ret; +} + +static void +search_address_housenumber(struct search_list *sl, GList *phrases, GList *exclude1, GList *exclude2, GList *exclude3) +{ + struct search_list_result *slr; + GList *tmp=phrases; + int count=0; + struct attr attr; + attr.type=attr_street_name; + while (slr=search_list_get_result(sl)) { + dbg(0,"%p\n",slr); + dbg(0,"%p %p\n",slr->country,slr->town); + dbg(0,"%s %s %s %s %s\n",slr->country->car,slr->town->common.postal,slr->town->name,slr->town->district,slr->street->name); + count++; + } + if (!count) + return; + dbg(0,"count %d\n",count); + while (tmp) { + if (tmp != exclude1 && tmp != exclude2 && tmp != exclude3) { + attr.type=attr_house_number; + attr.u.str=tmp->data; + search_list_search(sl, &attr, 0); + while (slr=search_list_get_result(sl)) { + dbg(0,"result %s %s(%s) %s %s\n",slr->house_number->common.postal,slr->house_number->common.town_name, slr->house_number->common.district_name,slr->street->name,slr->house_number->house_number); + } + + } + tmp=g_list_next(tmp); + } +} +static void +search_address_street(struct search_list *sl, GList *phrases, GList *exclude1, GList *exclude2) +{ + struct search_list_result *slr; + GList *tmp=phrases; + int count=0; + struct attr attr; + attr.type=attr_street_name; + while (slr=search_list_get_result(sl)) { +#if 0 + dbg(0,"%s %s %s %s",slr->country->car,slr->town->name,slr->town->district,slr->street->name); +#endif + dbg(0,"%s %s %s %s\n",slr->country->car,slr->town->common.postal,slr->town->name,slr->town->district); + count++; + } + if (!count) + return; + dbg(0,"count %d\n",count); + while (tmp) { + if (tmp != exclude1 && tmp != exclude2) { + attr.u.str=tmp->data; + search_list_search(sl, &attr, 0); + search_address_housenumber(sl, phrases, exclude1, exclude2, tmp); + } + tmp=g_list_next(tmp); + } +} + +static void +search_address_town(struct search_list *sl, GList *phrases, GList *exclude) +{ + GList *tmp=phrases; + int count=0; + struct attr attr; + attr.type=attr_town_or_district_name; + while (search_list_get_result(sl)) + count++; + if (!count) + return; + dbg(0,"count %d\n",count); + while (tmp) { + if (tmp != exclude) { + attr.u.str=tmp->data; + search_list_search(sl, &attr, 0); + search_address_street(sl, phrases, exclude, tmp); + } + tmp=g_list_next(tmp); + } +} + +void +search_by_address(struct mapset *ms, char *addr) +{ + char *str=search_fix_spaces(addr); + GList *tmp,*phrases=search_split_phrases(str); + dbg(0,"enter %s\n",addr); + struct search_list *sl; + struct search_list_result *slr; + struct attr attr; + attr.type=attr_country_all; + tmp=phrases; + sl=search_list_new(ms); + while (tmp) { + attr.u.str=tmp->data; + search_list_search(sl, &attr, 0); + search_address_town(sl, phrases, tmp); + tmp=g_list_next(tmp); + } + search_list_search(sl, country_default(), 0); + search_address_town(sl, phrases, NULL); + + g_free(str); +} +#endif + diff --git a/navit/navit/search.h b/navit/navit/search.h index c868ab6..04547bf 100644 --- a/navit/navit/search.h +++ b/navit/navit/search.h @@ -24,15 +24,17 @@ extern "C" { #endif struct search_list_common { - struct item item; + struct item unique,item; int selected; struct pcoord *c; + char *town_name; + char *district_name; + char *postal; + char *postal_mask; }; struct search_list_country { - struct item item; - int selected; - struct pcoord *c; + struct search_list_common common; char *car; char *iso2; char *iso3; @@ -41,28 +43,29 @@ struct search_list_country { }; struct search_list_town { - struct item item; - int selected; - struct pcoord *c; + struct search_list_common common; struct item itemt; - char *postal; char *name; char *district; }; struct search_list_street { - struct item item; - int selected; - struct pcoord *c; + struct search_list_common common; char *name; }; +struct search_list_house_number { + struct search_list_common common; + char *house_number; +}; + struct search_list_result { int id; struct pcoord *c; struct search_list_country *country; struct search_list_town *town; struct search_list_street *street; + struct search_list_house_number *house_number; }; /* prototypes */ -- 2.7.4