Fix:Android:Corrected and added keycodes
[navit-package] / navit / maptool / coastline.c
1 #include "maptool.h"
2 #include "debug.h"
3
4 static int distance_from_ll(struct coord *c, struct rect *bbox)
5 {
6         int dist=0;
7         if (c->x == bbox->l.x) 
8                 return dist+c->y-bbox->l.y;
9         dist+=bbox->h.y-bbox->l.y;
10         if (c->y == bbox->h.y)
11                 return dist+c->x-bbox->l.x;
12         dist+=bbox->h.x-bbox->l.x;
13         if (c->x == bbox->h.x)
14                 return dist+bbox->h.y-c->y;
15         dist+=bbox->h.y-bbox->l.y;
16         if (c->y == bbox->l.y)
17                 return dist+bbox->h.x-c->x;
18         return -1;
19 }
20
21 static struct geom_poly_segment *
22 find_next(struct rect *bbox, GList *segments, struct coord *c, int exclude, struct coord *ci)
23 {
24         int min=INT_MAX,search=distance_from_ll(c, bbox)+(exclude?1:0);
25         GList *curr;
26         int i;
27         struct geom_poly_segment *ret=NULL;
28         int dbgl=1;
29
30         for (i = 0 ; i < 2 ; i++) {
31                 curr=segments;
32                 dbg(dbgl,"search distance %d\n",search);
33                 while (curr) {
34                         struct geom_poly_segment *seg=curr->data;
35                         int dist=distance_from_ll(seg->first, bbox);
36                         dbg(dbgl,"0x%x 0x%x dist %d\n",seg->first->x,seg->first->y,dist);
37                         if (dist != -1 && seg->first != seg->last && dist < min && (dist >= search)) {
38                                 min=dist;
39                                 ci[0]=*seg->first;
40                                 ci[1]=*seg->last;
41                                 ret=seg;
42                         }
43                         curr=g_list_next(curr);
44                 }
45                 if (ret || !search)
46                         break;
47                 search=0;
48         }
49         return ret;
50 }
51
52 static void
53 close_polygon(struct item_bin *ib, struct coord *from, struct coord *to, int dir, struct rect *bbox, int *edges)
54 {
55         int i,e,dist,fromdist,todist;
56         int full=(bbox->h.x-bbox->l.x+bbox->h.y-bbox->l.y)*2;
57         int corners=0,first_corner=0;
58         struct coord c;
59         if (dir > 0) {
60                 fromdist=distance_from_ll(from, bbox);
61                 todist=distance_from_ll(to, bbox);
62         } else {
63                 fromdist=distance_from_ll(to, bbox);
64                 todist=distance_from_ll(from, bbox);
65         }
66 #if 0
67         fprintf(stderr,"close_polygon fromdist %d todist %d full %d dir %d\n", fromdist, todist, full, dir);
68 #endif
69         if (fromdist > todist)
70                 todist+=full;
71 #if 0
72         fprintf(stderr,"close_polygon corrected fromdist %d todist %d full %d dir %d\n", fromdist, todist, full, dir);
73 #endif
74         for (i = 0 ; i < 8 ; i++) {
75                 if (dir > 0)
76                         e=i;
77                 else
78                         e=7-i;
79                 switch (e%4) {
80                 case 0:
81                         c=bbox->l;
82                         break;
83                 case 1:
84                         c.x=bbox->l.x;
85                         c.y=bbox->h.y;
86                         break;
87                 case 2:
88                         c=bbox->h;
89                         break;
90                 case 3:
91                         c.x=bbox->h.x;
92                         c.y=bbox->l.y;
93                         break;
94                 }
95                 dist=distance_from_ll(&c, bbox);
96                 if (e & 4)
97                         dist+=full;
98 #if 0
99                 fprintf(stderr,"dist %d %d\n",e,dist);
100 #endif
101                 if (dist > fromdist && dist < todist) {
102                         item_bin_add_coord(ib, &c, 1);
103 #if 0
104                         fprintf(stderr,"add\n");
105 #endif
106                 }
107                 if (dist >= fromdist && dist <= todist) {
108                         if (!corners)
109                                 first_corner=e;
110                         corners++;
111                 }
112         }
113         while (corners >= 2) {
114                 *edges |= 1<<(first_corner%4);
115                 first_corner++;
116                 corners--;
117         }
118 }
119
120 struct coastline_tile_data {
121         struct item_bin_sink_func *sink;
122         GHashTable *tile_edges;
123         int level;
124 };
125
126 static GList *
127 tile_data_to_segments(int *tile_data)
128 {
129         int *end=tile_data+tile_data[0];
130         int *curr=tile_data+1;
131         GList *segments=NULL;
132         int count=0;
133
134         while (curr < end) {
135                 struct item_bin *ib=(struct item_bin *)curr;
136                 segments=g_list_prepend(segments,item_bin_to_poly_segment(ib, geom_poly_segment_type_way_right_side));
137                 curr+=ib->len+1;
138                 count++;
139         }
140 #if 0
141         fprintf(stderr,"%d segments\n",count);
142 #endif
143         return segments;
144 }
145
146 static void
147 tile_collector_process_tile(char *tile, int *tile_data, struct coastline_tile_data *data)
148 {
149         int poly_start_valid,tile_start_valid,exclude,search=0,workload=0;
150         struct rect bbox;
151         struct coord c,cn[2],end,poly_start,tile_start;
152         struct geom_poly_segment *first;
153         struct item_bin *ib=(struct item_bin *)buffer;
154         struct item_bin_sink *out=data->sink->priv_data[1];
155         int dbgl=1;
156         int edges=0,flags;
157         GList *sorted_segments,*curr;
158 #if 0
159         if (strncmp(tile,"bcdbdcabddddba",7))
160                 return;
161 #endif
162 #if 0
163         if (strncmp(tile,"bcdbdcaaaaddba",14))
164                 return;
165 #endif
166 #if 0
167         fprintf(stderr,"tile %s of size %d\n", tile, *tile_data);
168 #endif
169         tile_bbox(tile, &bbox, 0);
170         sorted_segments=geom_poly_segments_sort(tile_data_to_segments(tile_data), geom_poly_segment_type_way_right_side);
171 #if 0
172 {
173         GList *sort_segments=sorted_segments;
174         int count=0;
175         while (sort_segments) {
176                 struct geom_poly_segment *seg=sort_segments->data;
177                 struct item_bin *ib=(struct item_bin *)buffer;
178                 char *text=g_strdup_printf("segment %d type %d %p %s area %Ld",count++,seg->type,sort_segments,coord_is_equal(*seg->first, *seg->last) ? "closed":"open",geom_poly_area(seg->first,seg->last-seg->first+1));
179                 item_bin_init(ib, type_rg_segment);
180                 item_bin_add_coord(ib, seg->first, seg->last-seg->first+1);
181                 item_bin_add_attr_string(ib, attr_debug, text);
182                 // fprintf(stderr,"%s\n",text);
183                 g_free(text);
184                 // item_bin_dump(ib, stderr);
185                 item_bin_write_to_sink(ib, out, NULL);
186                 sort_segments=g_list_next(sort_segments);
187         }
188 }
189 #endif
190         flags=0;
191         curr=sorted_segments;
192         while (curr) {
193                 struct geom_poly_segment *seg=curr->data;
194                 switch (seg->type) {
195                 case geom_poly_segment_type_way_inner:
196                         flags|=1;
197                         break;
198                 case geom_poly_segment_type_way_outer:
199                         flags|=2;
200                         break;
201                 default:
202                         flags|=4;
203                         break;
204                 }
205                 curr=g_list_next(curr);
206         }
207         if (flags == 1) {
208                 item_bin_init(ib, type_poly_water_tiled);
209                 item_bin_bbox(ib, &bbox);
210                 item_bin_write_to_sink(ib, out, NULL);
211                 g_hash_table_insert(data->tile_edges, g_strdup(tile), (void *)15);
212                 return;
213         }
214 #if 1
215         end=bbox.l;
216         tile_start_valid=0;
217         poly_start_valid=0;
218         exclude=0;
219         poly_start.x=0;
220         poly_start.y=0;
221         tile_start.x=0;
222         tile_start.y=0;
223         for (;;) {
224                 search++;
225                 // item_bin_write_debug_point_to_sink(out, &end, "Search %d",search);
226                 dbg(dbgl,"searching next polygon from 0x%x 0x%x\n",end.x,end.y);
227                 first=find_next(&bbox, sorted_segments, &end, exclude, cn);
228                 exclude=1;
229                 if (!first)
230                         break;
231                 if (!tile_start_valid) {
232                         tile_start=cn[0];
233                         tile_start_valid=1;
234                 } else {
235                         if (cn[0].x == tile_start.x && cn[0].y == tile_start.y) {
236                                 dbg(dbgl,"end of tile reached\n");
237                                 break;
238                         }
239                 }
240                 if (first->type == geom_poly_segment_type_none) {
241                         end=cn[0];
242                         continue;
243                 }
244                 poly_start_valid=0;
245                 dbg(dbgl,"start of polygon 0x%x 0x%x\n",cn[0].x,cn[0].y);
246                 for (;;) {
247                         if (!poly_start_valid) {
248                                 poly_start=cn[0];
249                                 poly_start_valid=1;
250                                 item_bin_init(ib,type_poly_water_tiled);
251                         } else {
252                                 close_polygon(ib, &end, &cn[0], 1, &bbox, &edges);
253                                 if (cn[0].x == poly_start.x && cn[0].y == poly_start.y) {
254                                         dbg(dbgl,"poly end reached\n");
255                                         item_bin_write_to_sink(ib, out, NULL);
256                                         end=cn[0];
257                                         break;
258                                 }
259                         }
260                         if (first->type == geom_poly_segment_type_none)
261                                 break;
262                         item_bin_add_coord(ib, first->first, first->last-first->first+1);
263                         first->type=geom_poly_segment_type_none;
264                         end=cn[1];
265                         if (distance_from_ll(&end, &bbox) == -1) {
266                                 dbg(dbgl,"incomplete\n");
267                                 break;
268                         }
269                         first=find_next(&bbox, sorted_segments, &end, 1, cn);
270                         dbg(dbgl,"next segment of polygon 0x%x 0x%x\n",cn[0].x,cn[0].y);
271                 }
272                 if (search > 55)
273                         break;
274         }
275 #endif
276
277 #if 0
278         {
279                 int *end=tile_data+tile_data[0];
280                 int *curr=tile_data+1;
281                 while (curr < end) {
282                         struct item_bin *ib=(struct item_bin *)curr;
283                         // item_bin_dump(ib);
284                         ib->type=type_rg_segment;
285                         item_bin_write_to_sink(ib, out, NULL);
286                         curr+=ib->len+1;
287 #if 0
288                         {
289                                 struct coord *c[2];
290                                 int i;
291                                 char *s;
292                                 c[0]=(struct coord *)(ib+1);
293                                 c[1]=c[0]+ib->clen/2-1;
294                                 for (i = 0 ; i < 2 ; i++) {
295                                         s=coord_to_str(c[i]);
296                                         item_bin_write_debug_point_to_sink(out, c[i], "%s",s);
297                                         g_free(s);
298                                 }
299                                 
300                         }
301 #endif
302                 }
303         }
304 #endif
305         g_hash_table_insert(data->tile_edges, g_strdup(tile), (void *)edges);
306 #if 0
307         item_bin_init(ib, type_border_country);
308         item_bin_bbox(ib, &bbox);
309         item_bin_add_attr_string(ib, attr_debug, tile);
310         item_bin_write_to_sink(ib, out, NULL);
311 #endif
312 #if 0
313         c.x=(bbox.l.x+bbox.h.x)/2;
314         c.y=(bbox.l.y+bbox.h.y)/2;
315         item_bin_write_debug_point_to_sink(out, &c, "%s %d",tile,edges);
316 #endif
317 }
318
319 static void
320 ocean_tile(GHashTable *hash, char *tile, char c, struct item_bin_sink *out)
321 {
322         int len=strlen(tile);
323         char tile2[len+1];
324         struct rect bbox;
325         struct item_bin *ib=(struct item_bin *)buffer;
326         struct coord co;
327
328         strcpy(tile2, tile);
329         tile2[len-1]=c;
330         //fprintf(stderr,"Testing %s\n",tile2);
331         if (g_hash_table_lookup_extended(hash, tile2, NULL, NULL))
332                 return;
333         //fprintf(stderr,"%s ok\n",tile2);
334         tile_bbox(tile2, &bbox, 0);
335         item_bin_init(ib,type_poly_water_tiled);
336         item_bin_bbox(ib, &bbox);
337         item_bin_write_to_sink(ib, out, NULL);
338         g_hash_table_insert(hash, g_strdup(tile2), (void *)15);
339 #if 0
340         item_bin_init(ib, type_border_country);
341         item_bin_bbox(ib, &bbox);
342         item_bin_add_attr_string(ib, attr_debug, tile2);
343         item_bin_write_to_sink(ib, out, NULL);
344 #endif
345         co.x=(bbox.l.x+bbox.h.x)/2;
346         co.y=(bbox.l.y+bbox.h.y)/2;
347         //item_bin_write_debug_point_to_sink(out, &co, "%s 15",tile2);
348         
349 }
350
351 /* ba */
352 /* dc */
353
354 static void
355 tile_collector_add_siblings(char *tile, void *edgesp, struct coastline_tile_data *data)
356 {
357         int len=strlen(tile);
358         char t=tile[len-1];
359         struct item_bin_sink *out=data->sink->priv_data[1];
360         int edges=(int)edgesp;
361         int debug=0;
362
363         if (len != data->level)
364                 return;
365 #if 0
366         if (!strncmp(tile,"bcacccaadbdcd",10))
367                 debug=1;
368 #endif
369         if (debug)
370                 fprintf(stderr,"%s (%c) has %d edges active\n",tile,t,edges);
371         if (t == 'a' && (edges & 1)) 
372                 ocean_tile(data->tile_edges, tile, 'b', out);
373         if (t == 'a' && (edges & 8)) 
374                 ocean_tile(data->tile_edges, tile, 'c', out);
375         if (t == 'b' && (edges & 4)) 
376                 ocean_tile(data->tile_edges, tile, 'a', out);
377         if (t == 'b' && (edges & 8)) 
378                 ocean_tile(data->tile_edges, tile, 'd', out);
379         if (t == 'c' && (edges & 1)) 
380                 ocean_tile(data->tile_edges, tile, 'd', out);
381         if (t == 'c' && (edges & 2)) 
382                 ocean_tile(data->tile_edges, tile, 'a', out);
383         if (t == 'd' && (edges & 4)) 
384                 ocean_tile(data->tile_edges, tile, 'c', out);
385         if (t == 'd' && (edges & 2)) 
386                 ocean_tile(data->tile_edges, tile, 'b', out);
387 }
388
389 static int
390 tile_sibling_edges(GHashTable *hash, char *tile, char c)
391 {
392         int len=strlen(tile);
393         int ret;
394         char tile2[len+1];
395         void *data;
396         strcpy(tile2, tile);
397         tile2[len-1]=c;
398         if (!g_hash_table_lookup_extended(hash, tile2, NULL, &data))
399                 ret=15;
400         else
401                 ret=(int)data;
402         //fprintf(stderr,"checking '%s' with %d edges active\n",tile2,ret);
403
404         return ret;
405 }
406
407 static void
408 ocean_tile2(struct rect *r, int dx, int dy, int wf, int hf, struct item_bin_sink *out)
409 {
410         struct item_bin *ib=(struct item_bin *)buffer;
411         int w=r->h.x-r->l.x;
412         int h=r->h.y-r->l.y;
413         char tile2[32];
414         struct rect bbox;
415         struct coord co;
416         bbox.l.x=r->l.x+dx*w;
417         bbox.l.y=r->l.y+dy*h;
418         bbox.h.x=bbox.l.x+w*wf;
419         bbox.h.y=bbox.l.y+h*hf;
420         //fprintf(stderr,"0x%x,0x%x-0x%x,0x%x -> 0x%x,0x%x-0x%x,0x%x\n",r->l.x,r->l.y,r->h.x,r->h.y,bbox.l.x,bbox.l.y,bbox.h.x,bbox.h.y);
421         item_bin_init(ib,type_poly_water_tiled);
422         item_bin_bbox(ib, &bbox);
423         item_bin_write_to_sink(ib, out, NULL);
424 #if 0
425         item_bin_init(ib, type_border_country);
426         item_bin_bbox(ib, &bbox);
427         item_bin_add_attr_string(ib, attr_debug, tile2);
428         item_bin_write_to_sink(ib, out, NULL);
429 #endif
430         tile(&bbox, NULL, tile2, 32, 0, NULL);
431         co.x=(bbox.l.x+bbox.h.x)/2;
432         co.y=(bbox.l.y+bbox.h.y)/2;
433         //item_bin_write_debug_point_to_sink(out, &co, "%s 15",tile2);
434 }
435
436 static void
437 tile_collector_add_siblings2(char *tile, void *edgesp, struct coastline_tile_data *data)
438 {
439         int len=strlen(tile);
440         char tile2[len+1];
441         char t=tile[len-1];
442         strcpy(tile2, tile);
443         tile2[len-1]='\0';
444         struct item_bin_sink *out=data->sink->priv_data[1];
445         struct rect bbox;
446         int edges=(int)edgesp;
447         int pedges=0;
448         int debug=0;
449 #if 0
450         if (!strncmp(tile,"bcacccaadbdcd",10))
451                 debug=1;
452 #endif
453         if (debug) 
454                 fprintf(stderr,"len of %s %d vs %d\n",tile,len,data->level);
455         if (len != data->level)
456                 return;
457
458
459         if (debug)
460                 fprintf(stderr,"checking siblings of '%s' with %d edges active\n",tile,edges);
461         if (t == 'b' && (edges & 1) && (tile_sibling_edges(data->tile_edges, tile, 'd') & 1))
462                 pedges|=1;
463         if (t == 'd' && (edges & 2) && (tile_sibling_edges(data->tile_edges, tile, 'b') & 1))
464                 pedges|=1;
465         if (t == 'a' && (edges & 2) && (tile_sibling_edges(data->tile_edges, tile, 'b') & 2))
466                 pedges|=2;
467         if (t == 'b' && (edges & 2) && (tile_sibling_edges(data->tile_edges, tile, 'a') & 2))
468                 pedges|=2;
469         if (t == 'a' && (edges & 4) && (tile_sibling_edges(data->tile_edges, tile, 'c') & 4))
470                 pedges|=4;
471         if (t == 'c' && (edges & 4) && (tile_sibling_edges(data->tile_edges, tile, 'a') & 4))
472                 pedges|=4;
473         if (t == 'd' && (edges & 8) && (tile_sibling_edges(data->tile_edges, tile, 'c') & 8))
474                 pedges|=8;
475         if (t == 'c' && (edges & 8) && (tile_sibling_edges(data->tile_edges, tile, 'd') & 8))
476                 pedges|=8;
477         if (debug)
478                 fprintf(stderr,"result '%s' %d old %d\n",tile2,pedges,(int)g_hash_table_lookup(data->tile_edges, tile2));
479         g_hash_table_insert(data->tile_edges, g_strdup(tile2), (void *)((int)g_hash_table_lookup(data->tile_edges, tile2)|pedges));
480 }
481
482 static int
483 tile_collector_finish(struct item_bin_sink_func *tile_collector)
484 {
485         struct coastline_tile_data data;
486         int i;
487         data.sink=tile_collector;
488         data.tile_edges=g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL);
489         GHashTable *hash=tile_collector->priv_data[0];
490         fprintf(stderr,"tile_collector_finish\n");
491         g_hash_table_foreach(hash, tile_collector_process_tile, &data);
492         fprintf(stderr,"tile_collector_finish foreach done\n");
493         g_hash_table_destroy(hash);
494         fprintf(stderr,"tile_collector_finish destroy done\n");
495         for (i = 14 ; i > 0 ; i--) {
496                 fprintf(stderr,"Level=%d\n",i);
497                 data.level=i;
498                 g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings, &data);
499                 fprintf(stderr,"*");
500                 g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings, &data);
501                 fprintf(stderr,"*");
502                 g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings, &data);
503                 fprintf(stderr,"*");
504                 g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings, &data);
505                 fprintf(stderr,"*");
506                 g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings2, &data);
507                 fprintf(stderr,"*\n");
508                 g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings2, &data);
509                 fprintf(stderr,"*\n");
510                 g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings2, &data);
511                 fprintf(stderr,"*\n");
512                 g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings2, &data);
513                 fprintf(stderr,"*\n");
514         }
515 #if 0
516         data.level=13;
517         g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings, &data);
518         g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings, &data);
519         g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings2, &data);
520         data.level=12;
521         g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings, &data);
522         g_hash_table_foreach(data.tile_edges, tile_collector_add_siblings, &data);
523 #endif
524         item_bin_sink_func_destroy(tile_collector);
525         fprintf(stderr,"tile_collector_finish done\n");
526         return 0;
527 }
528
529
530 static int
531 coastline_processor_process(struct item_bin_sink_func *func, struct item_bin *ib, struct tile_data *tile_data)
532 {
533         int i;
534         struct coord *c=(struct coord *)(ib+1);
535 #if 0
536         for (i = 0 ; i < 19 ; i++) {
537                 c[i]=c[i+420];
538         }
539         ib->clen=(i-1)*2;
540 #endif
541         item_bin_write_clipped(ib, func->priv_data[0], func->priv_data[1]);
542         return 0;
543 }
544
545 static struct item_bin_sink_func *
546 coastline_processor_new(struct item_bin_sink *out)
547 {
548         struct item_bin_sink_func *coastline_processor=item_bin_sink_func_new(coastline_processor_process);
549         struct item_bin_sink *tiles=item_bin_sink_new();
550         struct item_bin_sink_func *tile_collector=tile_collector_new(out);
551         struct tile_parameter *param=g_new0(struct tile_parameter, 1);
552
553         fprintf(stderr,"new:out=%p\n",out);
554         param->min=14;
555         param->max=14;
556         param->overlap=0;
557
558         item_bin_sink_add_func(tiles, tile_collector);
559         coastline_processor->priv_data[0]=param;
560         coastline_processor->priv_data[1]=tiles;
561         coastline_processor->priv_data[2]=tile_collector;
562         return coastline_processor;
563 }
564
565 static void
566 coastline_processor_finish(struct item_bin_sink_func *coastline_processor)
567 {
568         struct tile_parameter *param=coastline_processor->priv_data[0];
569         struct item_bin_sink *tiles=coastline_processor->priv_data[1];
570         struct item_bin_sink_func *tile_collector=coastline_processor->priv_data[2];
571         g_free(param);
572         tile_collector_finish(tile_collector);
573         item_bin_sink_destroy(tiles);
574         item_bin_sink_func_destroy(coastline_processor);
575 }
576
577 void
578 process_coastlines(FILE *in, FILE *out)
579 {
580         struct item_bin_sink *reader=file_reader_new(in,1000000,0);
581         struct item_bin_sink_func *file_writer=file_writer_new(out);
582         struct item_bin_sink *result=item_bin_sink_new();
583         struct item_bin_sink_func *coastline_processor=coastline_processor_new(result);
584         item_bin_sink_add_func(reader, coastline_processor);
585         item_bin_sink_add_func(result, file_writer);
586         file_reader_finish(reader);
587         coastline_processor_finish(coastline_processor);
588         file_writer_finish(file_writer);
589         item_bin_sink_destroy(result);
590 }