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