61099f34213e7234e2f53cf93ae313b7841fd794
[navit-package] / navit / map / mg / map.c
1 /**
2  * Navit, a modular navigation system.
3  * Copyright (C) 2005-2008 Navit Team
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License
7  * version 2 as published by the Free Software Foundation.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the
16  * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
17  * Boston, MA  02110-1301, USA.
18  */
19
20 #include <stdio.h>
21 #include <string.h>
22 #include "config.h"
23 #include "debug.h"
24 #include "plugin.h"
25 #include "maptype.h"
26 #include "mg.h"
27
28
29 GList *maps;
30
31 static struct country_isonum {
32         int country;
33         int isonum;
34         int postal_len;
35         char *postal_prefix;
36 } country_isonums[]={
37   {  1,203},
38   {  2,703},
39   {  7,674},
40   { 11,233},
41   { 12,268},
42   { 13,428},
43   { 14,440},
44   { 15,498},
45   { 16,643},
46   { 17,804},
47   { 18,112},
48   { 20,818},
49   { 30,300},
50   { 31,528},
51   { 32, 56},
52   { 33,250},
53   { 34,724},
54   { 36,348},
55   { 39,380},
56   { 40,642},
57   { 41,756},
58   { 43, 40},
59   { 44,826},
60   { 45,208},
61   { 46,752},
62   { 47,578},
63   { 48,616},
64   { 49,276,5,"D@@"},
65   { 50,292},
66   { 51,620},
67   { 52,442},
68   { 53,372},
69   { 54,352},
70   { 55,  8},
71   { 56,470},
72   { 57,196},
73   { 58,246},
74   { 59,100},
75   { 61,422},
76   { 62, 20},
77   { 63,760},
78   { 66,682},
79   { 71,434},
80   { 72,376},
81   { 73,275},
82   { 75,438},
83   { 76,504},
84   { 77, 12},
85   { 78,788},
86   { 81,688},
87   { 83,400},
88   { 85,191},
89   { 86,705},
90   { 87, 70},
91   { 89,807},
92   { 90,792},
93   { 93,492},
94   { 94, 31},
95   { 95, 51},
96   { 98,234},
97   { 99,732},
98   {336,774},
99 };
100
101 struct map_priv * map_new_mg(struct map_methods *meth, struct attr **attrs);
102
103 static int map_id;
104
105 static char *file[]={
106         [file_border_ply]="border.ply",
107         [file_bridge_ply]="bridge.ply",
108         [file_build_ply]="build.ply",
109         [file_golf_ply]="golf.ply",
110         [file_height_ply]="height.ply",
111         [file_natpark_ply]="natpark.ply",
112         [file_nature_ply]="nature.ply",
113         [file_other_ply]="other.ply",
114         [file_rail_ply]="rail.ply",
115         [file_sea_ply]="sea.ply",
116         [file_street_bti]="street.bti",
117         [file_street_str]="street.str",
118         [file_strname_stn]="strname.stn",
119         [file_town_twn]="town.twn",
120         [file_tunnel_ply]="tunnel.ply",
121         [file_water_ply]="water.ply",
122         [file_woodland_ply]="woodland.ply",
123 };
124
125 int mg_country_from_isonum(int isonum)
126 {
127         int i;
128         for (i = 0 ; i < sizeof(country_isonums)/sizeof(struct country_isonum) ; i++)
129                 if (country_isonums[i].isonum == isonum)
130                         return country_isonums[i].country;
131         return 0;
132 }
133
134 int mg_country_to_isonum(int country)
135 {
136         int i;
137         for (i = 0 ; i < sizeof(country_isonums)/sizeof(struct country_isonum) ; i++)
138                 if (country_isonums[i].country == country)
139                         return country_isonums[i].isonum;
140         return 0;
141 }
142
143 int mg_country_postal_len(int country)
144 {
145         int i;
146         for (i = 0 ; i < sizeof(country_isonums)/sizeof(struct country_isonum) ; i++)
147                 if (country_isonums[i].country == country)
148                         return country_isonums[i].postal_len;
149         return 0;
150 }
151
152 static char *mg_country_postal_prefix(int isonum)
153 {
154         int i;
155         for (i = 0 ; i < sizeof(country_isonums)/sizeof(struct country_isonum) ; i++)
156                 if (country_isonums[i].isonum == isonum)
157                         return country_isonums[i].postal_prefix;
158         return NULL;
159 }
160
161 struct item_range town_ranges[]={
162         {type_town_label,type_port_label},
163 };
164
165 struct item_range street_ranges[]={
166         {type_street_nopass,type_street_unkn},
167 };
168
169 struct item_range poly_ranges[]={
170         {type_border_country,type_water_line},
171         {type_street_unkn,type_street_unkn},
172         {type_area,type_last},
173 };
174
175
176 static int
177 file_next(struct map_rect_priv *mr)
178 {
179         int debug=0;
180
181         for (;;) {
182                 mr->current_file++;
183                 if (mr->current_file >= file_end)
184                         return 0;
185                 mr->file=mr->m->file[mr->current_file];
186                 if (! mr->file)
187                         continue;
188                 switch (mr->current_file) {
189                 case file_strname_stn:
190                         continue;
191                 case file_town_twn:
192                         if (mr->cur_sel && !map_selection_contains_item_range(mr->cur_sel, 0, town_ranges, sizeof(town_ranges)/sizeof(struct item_range)))
193                                 continue;
194                         break;
195                 case file_street_str:
196                         if (mr->cur_sel && !map_selection_contains_item_range(mr->cur_sel, 0, street_ranges, sizeof(street_ranges)/sizeof(struct item_range)))
197                                 continue;
198                         break;
199                 default:
200                         if (mr->cur_sel && !map_selection_contains_item_range(mr->cur_sel, 0, poly_ranges, sizeof(poly_ranges)/sizeof(struct item_range)))
201                                 continue;
202                         break;
203                 }
204                 if (debug)
205                         printf("current file: '%s'\n", file[mr->current_file]);
206                 mr->cur_sel=mr->xsel;
207                 if (block_init(mr))
208                         return 1;
209         }
210 }
211
212 static void
213 map_destroy_mg(struct map_priv *m)
214 {
215         int i;
216
217         printf("mg_map_destroy\n");
218         for (i = 0 ; i < file_end ; i++) {
219                 if (m->file[i])
220                         file_destroy(m->file[i]);
221         }
222 }
223
224 extern int block_lin_count,block_idx_count,block_active_count,block_mem,block_active_mem;
225
226 struct map_rect_priv *
227 map_rect_new_mg(struct map_priv *map, struct map_selection *sel)
228 {
229         struct map_rect_priv *mr;
230         int i;
231
232         block_lin_count=0;
233         block_idx_count=0;
234         block_active_count=0;
235         block_mem=0;
236         block_active_mem=0;
237         mr=g_new0(struct map_rect_priv, 1);
238         mr->m=map;
239         mr->xsel=sel;
240         mr->current_file=-1;
241         if (sel && sel->next)
242                 for (i=0 ; i < file_end ; i++) 
243                         mr->block_hash[i]=g_hash_table_new(g_int_hash,g_int_equal);
244         file_next(mr);
245         return mr;
246 }
247
248
249 static struct item *
250 map_rect_get_item_mg(struct map_rect_priv *mr)
251 {
252         for (;;) {
253                 switch (mr->current_file) {
254                 case file_town_twn:
255                         if (town_get(mr, &mr->town, &mr->item))
256                                 return &mr->item;
257                         break;
258                 case file_border_ply:
259                 case file_bridge_ply:
260                 case file_build_ply: 
261                 case file_golf_ply: 
262                 /* case file_height_ply: */
263                 case file_natpark_ply: 
264                 case file_nature_ply: 
265                 case file_other_ply:
266                 case file_rail_ply:
267                 case file_sea_ply:
268                 /* case file_tunnel_ply: */
269                 case file_water_ply:
270                 case file_woodland_ply:
271                         if (poly_get(mr, &mr->poly, &mr->item))
272                                 return &mr->item;
273                         break;
274                 case file_street_str:
275                         if (street_get(mr, &mr->street, &mr->item))
276                                 return &mr->item;
277                         break;
278                 case file_end:
279                         return NULL;
280                 default:
281                         break;
282                 }
283                 if (block_next(mr))
284                         continue;
285                 if (mr->cur_sel->next) {
286                         mr->cur_sel=mr->cur_sel->next;
287                         if (block_init(mr))
288                                 continue;
289                 }
290                 if (file_next(mr))
291                         continue;
292                 dbg(1,"lin_count %d idx_count %d active_count %d %d kB (%d kB)\n", block_lin_count, block_idx_count, block_active_count, (block_mem+block_active_mem)/1024, block_active_mem/1024);
293                 return NULL;
294         }
295 }
296
297 struct item *
298 map_rect_get_item_byid_mg(struct map_rect_priv *mr, int id_hi, int id_lo)
299 {
300         mr->current_file = (id_hi >> 16) & 0xff;
301         switch (mr->current_file) {
302         case file_town_twn:
303                 if (town_get_byid(mr, &mr->town, id_hi, id_lo, &mr->item))
304                         return &mr->item;
305                 break;
306         case file_street_str:
307                 if (street_get_byid(mr, &mr->street, id_hi, id_lo, &mr->item))
308                         return &mr->item;
309                 break;
310         default:        
311                 if (poly_get_byid(mr, &mr->poly, id_hi, id_lo, &mr->item))
312                         return &mr->item;
313                 break;
314         }
315         return NULL;
316 }
317
318
319 void
320 map_rect_destroy_mg(struct map_rect_priv *mr)
321 {
322         int i;
323         for (i=0 ; i < file_end ; i++) 
324                 if (mr->block_hash[i])
325                         g_hash_table_destroy(mr->block_hash[i]);        
326         g_free(mr);
327 }
328
329 static char *
330 map_search_mg_convert_special(char *str)
331 {
332         char *ret,*c=g_malloc(strlen(str)*2+1);
333
334         ret=c;
335         for (;;) {
336                 switch ((unsigned char)(*str)) {
337                 case 0xc4:
338                         *c++='A';
339                         break;
340                 case 0xd6:
341                         *c++='O';
342                         break;
343                 case 0xdc:
344                         *c++='U';
345                         break;
346                 case 0xdf:
347                         *c++='s';
348                         *c++='s';
349                         break;
350                 case 0xe4:
351                         *c++='a';
352                         break;
353                 case 0xf6:
354                         *c++='o';
355                         break;
356                 case 0xfc:
357                         *c++='u';
358                         break;
359                 default:
360                         dbg(1,"0x%x\n", *str);
361                         *c++=*str;
362                         break;
363                 }
364                 if (! *str)
365                         return ret;
366                 str++;
367         }
368 }
369
370 static int
371 map_search_setup(struct map_rect_priv *mr)
372 {
373         char *prefix;
374         dbg(1,"%s\n", attr_to_name(mr->search_type));
375         switch (mr->search_type) {
376         case attr_town_postal:
377                 if (mr->search_item.type != type_country_label) {
378                         dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type));
379                         return 0;
380                 }
381                 prefix=mg_country_postal_prefix(mr->search_item.id_lo);
382                 if (! prefix)
383                         return 0;
384                 tree_search_init(mr->m->dirname, "town.b1", &mr->ts, 0);
385                 mr->current_file=file_town_twn;
386                 mr->search_str=g_strdup_printf("%s%s",prefix,mr->search_attr->u.str);
387                 dbg(0,"search_str='%s'\n",mr->search_str);
388                 mr->search_country=mg_country_from_isonum(mr->search_item.id_lo);
389                 break;
390         case attr_town_name:
391                 if (mr->search_item.type != type_country_label) {
392                         dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type));
393                         return 0;
394                 }
395                 tree_search_init(mr->m->dirname, "town.b2", &mr->ts, 0x1000);
396                 mr->current_file=file_town_twn;
397                 mr->search_str=map_search_mg_convert_special(mr->search_attr->u.str);
398                 mr->search_country=mg_country_from_isonum(mr->search_item.id_lo);
399                 break;
400         case attr_district_name:
401                 if (mr->search_item.type != type_country_label) {
402                         dbg(0,"wrong parent type %s\n", item_to_name(mr->search_item.type));
403                         return 0;
404                 }
405                 tree_search_init(mr->m->dirname, "town.b3", &mr->ts, 0x1000);
406                 mr->current_file=file_town_twn;
407                 mr->search_str=map_search_mg_convert_special(mr->search_attr->u.str);
408                 mr->search_country=mg_country_from_isonum(mr->search_item.id_lo);
409                 break;
410         case attr_street_name:
411                 if (mr->search_item.type != type_town_streets) {
412                         GList *tmp=maps;
413                         struct item *item=NULL;
414                         struct attr attr;
415                         struct map_rect_priv *mr2;
416                         while (tmp) {   
417                                 mr2=map_rect_new_mg(tmp->data, NULL);
418                                 item=map_rect_get_item_byid_mg(mr2, mr->search_item.id_hi, mr->search_item.id_lo);
419                                 if (item)
420                                         break;
421                                 map_rect_destroy_mg(mr2);
422                                 tmp=g_list_next(tmp);
423                         }
424                         if (item) {
425                                 if (item_attr_get(item, attr_town_streets_item, &attr)) {
426                                         mr->search_item=*attr.u.item;
427                                         map_rect_destroy_mg(mr2);
428                                 } else {
429                                         map_rect_destroy_mg(mr2);
430                                         return 0;
431                                 }
432                         } else {
433                                 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);
434                                 return 0;
435                         }
436                 }
437                 dbg(1,"street_assoc=0x%x\n", mr->search_item.id_lo);
438                 tree_search_init(mr->m->dirname, "strname.b1", &mr->ts, 0);
439                 mr->current_file=file_strname_stn;
440                 mr->search_str=g_strdup(mr->search_attr->u.str);
441                 break;
442         case attr_house_number:
443                 if (!map_priv_is(mr->search_item.map, mr->m))
444                         return 0;
445                 if (!housenumber_search_setup(mr)) {
446                         dbg(0,"failed to search for attr_house_number\n");
447                         return 0;
448                 }
449                 break;
450         default:
451                 dbg(0,"unknown search %s\n",attr_to_name(mr->search_type));
452                 return 0;
453         }
454         mr->file=mr->m->file[mr->current_file];
455         block_init(mr);
456         return 1;
457 }
458 static void map_search_cleanup(struct map_rect_priv *mr);
459
460 static struct item * map_search_get_item_mg(struct map_search_priv *ms);
461
462 static struct map_search_priv *
463 map_search_new_mg(struct map_priv *map, struct item *item, struct attr *search, int partial)
464 {
465         struct map_rect_priv *mr=g_new0(struct map_rect_priv, 1);
466         dbg(1,"searching for %s '%s'\n", attr_to_name(search->type), search->u.str);
467         dbg(1,"id_lo=0x%x\n", item->id_lo);
468         dbg(1,"search=%s\n", search->u.str);
469         mr->m=map;
470         mr->search_attr=attr_dup(search);
471         mr->search_type=search->type;
472         mr->search_item=*item;
473         mr->search_partial=partial;
474         if (search->type == attr_town_or_district_name) {
475                 mr->search_type=attr_town_name;
476                 mr->search_type_next=attr_district_name;        
477         }
478         if (!map_search_setup(mr)) {
479                 dbg(1,"map_search_new_mg failed\n");
480                 g_free(mr);
481                 return NULL;
482         }
483         mr->search_mr_tmp=map_rect_new_mg(map, NULL);
484
485         return (struct map_search_priv *)mr;
486 }
487
488 static void
489 map_search_cleanup(struct map_rect_priv *mr)
490 {
491         g_free(mr->search_str);
492         mr->search_str=NULL;
493         tree_search_free(&mr->ts);
494         mr->search_linear=0;
495         mr->search_p=NULL;
496         mr->search_blk_count=0;
497         mr->search_blk_off=NULL;
498         mr->search_block=0;
499 }
500
501 static void
502 map_search_destroy_mg(struct map_search_priv *ms)
503 {
504         struct map_rect_priv *mr=(struct map_rect_priv *)ms;
505
506         dbg(1,"mr=%p\n", mr);
507         if (! mr)
508                 return;
509         map_search_cleanup(mr);
510         if (mr->search_mr_tmp)
511                 map_rect_destroy_mg(mr->search_mr_tmp);
512         attr_free(mr->search_attr);
513         g_free(mr);
514 }
515
516 static struct item *
517 map_search_get_item_mg(struct map_search_priv *ms)
518 {
519         struct map_rect_priv *mr=(struct map_rect_priv *)ms;
520         struct item *ret=NULL;
521
522         if (! mr)
523                 return NULL;
524         switch (mr->search_type) {
525         case attr_town_postal:
526         case attr_town_name:
527         case attr_district_name:
528                 ret=town_search_get_item(mr);
529                 break;
530         case attr_street_name:
531                 ret=street_search_get_item(mr);
532                 break;
533         case attr_house_number:
534                 ret=housenumber_search_get_item(mr);
535                 break;
536         default:
537                 dbg(0,"unknown search %s\n",attr_to_name(mr->search_type));
538                 break;
539         }
540         if (!ret && mr->search_type_next != attr_none) {
541                 mr->search_type=mr->search_type_next;
542                 mr->search_type_next=attr_none;
543                 map_search_cleanup(mr);
544                 map_search_setup(mr);
545                 return map_search_get_item_mg(ms);
546         }
547         return ret;
548 }
549
550 static struct map_methods map_methods_mg = {
551         projection_mg,
552         "iso8859-1",
553         map_destroy_mg,
554         map_rect_new_mg,
555         map_rect_destroy_mg,
556         map_rect_get_item_mg,
557         map_rect_get_item_byid_mg,
558         map_search_new_mg,
559         map_search_destroy_mg,
560         map_search_get_item_mg,
561 };
562
563
564 struct map_priv *
565 map_new_mg(struct map_methods *meth, struct attr **attrs)
566 {
567         struct map_priv *m;
568         int i,maybe_missing;
569         struct attr *data=attr_search(attrs, NULL, attr_data);
570         char *filename;
571         struct file_wordexp *wexp;
572         char **wexp_data;
573
574         if (! data)
575                 return NULL;
576         
577          wexp=file_wordexp_new(data->u.str);
578          wexp_data=file_wordexp_get_array(wexp);
579
580         *meth=map_methods_mg;
581         data=attr_search(attrs, NULL, attr_data);
582
583         m=g_new(struct map_priv, 1);
584         m->id=++map_id;
585         m->dirname=g_strdup(wexp_data[0]);
586         file_wordexp_destroy(wexp);
587         for (i = 0 ; i < file_end ; i++) {
588                 if (file[i]) {
589                         filename=g_strdup_printf("%s/%s", m->dirname, file[i]);
590                         m->file[i]=file_create_caseinsensitive(filename, 0);
591                         if (! m->file[i]) {
592                                 maybe_missing=(i == file_border_ply || i == file_height_ply || i == file_sea_ply);
593                                 if (! maybe_missing)
594                                         dbg(0,"Failed to load %s\n", filename);
595                         } else
596                                 file_mmap(m->file[i]);
597                         g_free(filename);
598                 }
599         }
600         maps=g_list_append(maps, m);
601
602         return m;
603 }
604
605 void
606 plugin_init(void)
607 {
608         plugin_register_map_type("mg", map_new_mg);
609 }