]> www.wagner.pp.ru Git - oss/fgis.git/blob - epu/border.c
First checked in version
[oss/fgis.git] / epu / border.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include "eppl_ut.h"
5 #include "epp.h"
6 #include "dgt.h"
7 #include <getopt.h>
8 #ifndef __LINUX__
9 #include <errno.h>
10 #endif
11 #define TRUE 1
12 #define FALSE 0
13 #define SEG_LEFT 1
14 #define SEG_VERT 2
15 #define SEG_RIGHT 4
16 #define SEG_UP 8
17 #define DELTA 16
18 typedef struct U_POINT {
19         unsigned short x,y;} U_POINT;
20 typedef U_POINT *LINEBUF;
21 typedef struct INODE {
22                             unsigned short int count;
23                             short int both_ends;
24                             unsigned short int limit;
25                             int x_tail,x_head;
26                             LINEBUF points;
27                           } *LINE_INODE;
28 typedef struct LINE_END { LINE_INODE buf;
29                           int tail;
30                          } LINE_END;
31 /* ðÁÒÁÍÅÔÒÙ ËÏÎÆÉÇÕÒÁÃÉÉ */
32 int offsite_option=1;
33 int tolerance=3;
34 /* ïÓÎÏ×ÎÙÅ ÒÁÂÏÞÉÅ ÓÔÒÕËÔÕÒÙ ÄÁÎÎÙÈ */
35 LINE_END *lines;
36 unsigned short *rp1,*rp2;
37 EPP* source;
38 DGT* dest;
39 /* ïÓÎÏ×ÎÙÅ ÐÒÏÃÅÄÕÒÙ */
40 int epp2dgtX(int col);
41 int epp2dgtY(int row);
42 void getrow(int row);
43 void add_segment(LINE_END line,int col,int row);
44 /* ÄÏÂÁ×ÌÑÅÔ ÓÅÇÍÅÎÔ × ÎÁÞÁÌÏ ÉÌÉ × ËÏÎÅÃ, × ÚÁ×ÉÓÉÍÏÓÔÉ ÏÔ 
45   ÐÏÌÑ line->tail, ËÏÎÞÁÀÝÉÊÓÑ × ÔÏÞËÅ col,row */ 
46 void put_line(LINE_INODE buf);
47 /* çÅÎÅÒÁÌÉÚÕÅÔ ÌÉÎÉÀ É ÚÁÐÉÓÙ×ÁÅÔ ÅÅ. ðÒÉ ÎÅÏÂÈÏÄÉÍÏÓÔÉ ÒÅÖÅÔ
48    ðÏ ÚÁ×ÅÒÛÅÎÉÉ ÏÐÅÒÁÃÉÉ ÏÓ×ÏÂÏÖÄÁÅÔ ×ÓÀ ÐÁÍÑÔØ, ÚÁÎÑÔÕÀ ÌÉÎÉÅÊ
49 */
50 int create_header(EPP *epp,char *dgtname);
51 /* óÏÚÄÁÅÔ ×ÙÈÏÄÎÏÊ ÆÁÊÌ */
52 void write_labels(EPP *epp,DGT *dgt);
53 /* óÏÚÄÁÅÔ ÔÏÞËÉ */
54 void end_line(LINE_END line);
55 /* úÁ×ÅÒÛÁÅÔ ÐÏÐÏÌÎÅÎÉÅ ÌÉÎÉÉ Ó ÕËÁÚÁÎÎÏÇÏ ËÏÎÃÁ. åÓÌÉ Ó ÄÒÕÇÏÇÏ ËÏÎÃÁ
56   ÏÎÁ ÕÖÅ ÎÅ ÍÏÖÅÔ ÐÏÐÏÌÎÑÔØÓÑ, ÄÅÌÁÅÔ ÅÊ put_line */  
57 LINEBUF enlarge(LINE_INODE buf);
58 /* õ×ÅÌÉÞÉ×ÁÅÔ ÄÌÉÎÕ ÌÉÎÉÉ ÎÁ 1. ðÒÉ ÎÅÏÂÈÏÄÉÍÏÓÔÉ ÄÏ×ÙÄÅÌÑÅÔ ÐÁÍÑÔØ */
59 int smooth(LINE_INODE line,LINEBUF *buf);
60 /*óÇÌÁÖÉ×ÁÅÔ ÌÉÎÉÀ 
61   ×ÏÚ×ÒÁÝÁÅÔ ËÏÌÉÞÅÓÔ×Ï ÕÚÌÏ×, ÏÓÔÁ×ÛÉÈÓÑ ÐÏÓÌÅ ÇÅÎÅÒÁÌÉÚÁÃÉÉ*/
62 LINE_INODE new_line(int both,int col1,int row1,int col2,int row2);
63 /* óÏÚÄÁÅÔ ÎÏ×ÕÀ ÌÉÎÉÀ, ÐÏÍÅÝÁÑ × ÎÅÅ ÅÄÉÎÓÔ×ÅÎÎÙÊ ÓÅÇÍÅÎÔ Ó ÚÁÄÁÎÎÙÍÉ
64 ËÏÏÒÄÉÎÁÔÁÍÉ.*/
65 void join_lines(LINE_END line1,LINE_END  line2); 
66 /* ïÂßÅÄÉÎÑÅÔ Ä×Å ÌÉÎÉÉ × ÏÄÎÕ. */
67 int border_dgt(EPP *epp,char *dgtname,int offs_opt,int tol,int do_labels)
68 {int nrows=epp->lr-epp->fr+1;
69  int ncols=epp->lc-epp->fc+2;
70  unsigned short *left,*right,*up;
71  int this_node,next_node;
72  LINE_END hor_line,*vert_line;
73  int i,j;
74  offsite_option=offs_opt;
75  tolerance=tol;
76  if ((i=create_header(epp,dgtname))) return i;
77  rp1=calloc(ncols,sizeof(short int));
78  rp2=calloc(ncols,sizeof(short int));
79  lines=calloc(ncols,sizeof(struct LINE_END));
80  for(i=0;i<nrows;i++)
81  { getrow(i);
82    
83    if (EndLineProc) if ((*EndLineProc)(i,i,nrows)) return 1;
84    left=rp1;
85    right=rp1+1;
86    up=rp2+1;
87    vert_line=lines;
88    this_node=0;
89    hor_line.buf=NULL;
90    for(j=0;j<ncols-1;j++,left++,right++,up++,vert_line++)
91    { /* çÏÒÉÚÏÎÔÁÌØÎÙÊ ÓÅÇÍÅÎÔ*/
92      if (*up!=*right)
93        {next_node=SEG_LEFT;
94         this_node|=SEG_RIGHT;
95        } else next_node=0;
96      if (*left!=*right)
97        this_node|=SEG_VERT;
98      if (vert_line->buf)  
99        this_node|=SEG_UP;
100 #ifdef DEBUG
101   if ((this_node&SEG_LEFT)&&(!hor_line.buf))
102    fprintf(stderr,"Hor_line exists, where shouldn't x=%d y=%d\n",j,i);
103   if (!(this_node&SEG_LEFT)&&(hor_line.buf))
104    fprintf(stderr,"Hor_line doesn't exist x=%d y=%d\n",j,i);
105   if (this_node&SEG_UP)
106   if ((vert_line->tail?vert_line->buf->x_tail:vert_line->buf->x_head)!=j)
107    fprintf(stderr,"Invalid vertical segment at x=%d y=%d\n",j,i);
108 #endif      
109    switch(this_node)
110    {/* ìÉÎÉÉ ÐÒÏÄÏÌÖÁÀÔÓÑ ÐÒÑÍÏ*/ 
111      case 0:/* äÅÌÁÔØ ÚÄÅÓØ ÎÅÞÅÇÏ */ break;
112      case SEG_UP|SEG_VERT:add_segment(*vert_line,j,i+1);
113                           break;
114      case SEG_LEFT|SEG_RIGHT:add_segment(hor_line,j+1,i);
115                           break;
116     /* ìÉÎÉÉ ÐÒÏÄÏÌÖÁÀÔÓÑ Ó ÉÚÇÉÂÏÍ */
117      case SEG_LEFT|SEG_VERT:*vert_line=hor_line;hor_line.buf=NULL;
118                              add_segment(*vert_line,j,i+1);
119                             break;
120      case SEG_UP|SEG_RIGHT:hor_line=*vert_line;vert_line->buf=NULL;
121                              add_segment(hor_line,j+1,i);
122                              break;
123      /* ìÉÎÉÉ ÓÌÉ×ÁÀÔÓÑ */
124      case SEG_UP|SEG_LEFT:join_lines(hor_line,*vert_line);
125                           vert_line->buf=NULL;
126                           hor_line.buf=NULL;
127                           break;
128      /* ìÉÎÉÑ ÓÁÍÏÚÁÒÏÖÄÁÅÔÓÑ ÎÁ ÐÕÓÔÏÍ ÍÅÓÔÅ */
129      case SEG_VERT|SEG_RIGHT:hor_line.buf=new_line(TRUE,j,i,j+1,i);
130                              hor_line.tail=TRUE;
131                              vert_line->buf=hor_line.buf;
132                              vert_line->tail=FALSE;
133                              add_segment(*vert_line,j,i+1);
134                           /* ÓÏÚÄÁÔØ ÔÏÞËÕ */
135                              break;
136      /* ìÉÎÉÉ ÒÁÓÓÅËÁÀÔÓÑ - 5 ÓÌÕÞÁÅ× ËÏÇÄÁ × ÔÏÞËÅ 3 É ÂÏÌÅÅ ÌÉÎÉÊ */
137      case SEG_VERT|SEG_LEFT|SEG_RIGHT:
138        /* T ×ÎÉÚ */
139        end_line(hor_line);
140        hor_line.buf=new_line(FALSE,j,i,j+1,i);
141        hor_line.tail=TRUE;
142        vert_line->buf=new_line(FALSE,j,i,j,i+1);
143        vert_line->tail=TRUE;
144        /* cÏÚÄÁÔØ ÔÏÞËÕ */
145        break;
146      case SEG_UP|SEG_LEFT|SEG_RIGHT:
147        /* ô ××ÅÒÈ ÎÏÇÁÍÉ */
148        /*×ÙÂÒÏÓÉÔØ ÔÏÞËÕ*/
149        end_line(hor_line);
150        end_line(*vert_line);
151        hor_line.buf=new_line(FALSE,j,i,j+1,i);
152        hor_line.tail=TRUE;
153        vert_line->buf=NULL;
154        break;                   
155      case SEG_UP|SEG_LEFT|SEG_VERT:
156        /* ô È×ÏÓÔÏÍ ×ÌÅ×Ï */
157        /* ×ÙÂÒÏÓÉÔØ ÔÏÞËÕ */
158        end_line(hor_line);
159        end_line(*vert_line);
160        vert_line->buf=new_line(FALSE,j,i,j,i+1);
161        vert_line->tail=TRUE;
162        hor_line.buf=NULL;
163        break;   
164       case SEG_UP|SEG_RIGHT|SEG_VERT:                
165        /* ô È×ÏÓÔÏÍ ×ÐÒÁ×Ï */
166        /* ×ÙÂÒÏÓÉÔØ ÔÏÞËÕ */
167        end_line(*vert_line);
168        hor_line.buf=new_line(FALSE,j,i,j+1,i);
169        hor_line.tail=TRUE;
170        vert_line->buf=new_line(FALSE,j,i,j,i+1);
171        vert_line->tail=TRUE;
172        /* ÓÏÚÄÁÔØ ÔÏÞËÕ */
173        break;
174       case SEG_UP|SEG_RIGHT|SEG_LEFT|SEG_VERT:
175        /* ËÒÅÓÔ */ 
176        end_line(*vert_line);
177        end_line(hor_line);
178        hor_line.buf=new_line(FALSE,j,i,j+1,i);
179        hor_line.tail=TRUE;
180        vert_line->buf=new_line(FALSE,j,i,j,i+1);
181        vert_line->tail=TRUE;
182        /* ÓÏÚÄÁÔØ ÔÏÞËÕ */
183        break;
184       default:
185         /* ÷ÉÓÑÞÉÅ ÕÚÌÙ, ËÏÔÏÒÙÈ îå âù÷áåô */
186        fprintf(stderr,"Dangling node at x=%d,y=%d\n",j,i);
187       }
188       this_node=next_node; 
189     }
190   }  
191 if (do_labels) write_labels(source,dest); 
192 close_dgt(dest);
193
194 return 0;
195 }
196
197 void add_segment(LINE_END line,int col,int row)
198 {
199  LINE_INODE l=line.buf;
200
201  LINEBUF points;
202  if (line.tail)
203  {points=l->points+l->count-2;
204   if (points->x==col&&points[1].x==col) {points[1].y=row;return;}
205   if (points->y==row&&points[1].y==row) {points[1].x=col;l->x_tail=col;return;}
206   points=enlarge(l);
207   points+=l->count-1;
208   points->x=col;
209   points->y=row;
210   l->x_tail=col;
211  }
212  else
213  {LINEBUF tmp;int i=l->count; 
214   points=l->points;
215   if (points->x==col&&points[1].x==col) {points->y=row;return;}
216   if (points->y==row&&points[1].y==row) {points->x=col;l->x_head=col;return;}
217   points=enlarge(l);
218   points+=l->count-1;
219   tmp=points-1;
220   for(;i>0;i--,*(points--)=*(tmp--));
221   points->x=col;
222   points->y=row;
223   l->x_head=col; 
224  } 
225
226
227 LINEBUF enlarge(LINE_INODE buf)
228 { if (buf->count++==buf->limit)
229     buf->points=realloc(buf->points,(buf->limit+=DELTA)*sizeof(U_POINT));
230    return buf->points; 
231
232 void end_line(LINE_END line)
233 { if (line.buf->both_ends)
234      line.buf->both_ends=FALSE;
235   else
236     put_line(line.buf);
237 }
238 #ifdef DEBUG
239 #define DEBUG_CHECK(x1,x2) if (line1.buf->x1!=line2.buf->x2) fprintf(stderr,"Joining lines with separate ends %d %d\n",line1.buf->x1,line2.buf->x2)
240 #else
241 #define DEBUG_CHECK(x1,x2)
242 #endif
243 #define COPY_DIRECT(l) for(i=l.buf->count,source=l.buf->points;i>0;i--,*(dest++)=*(source++))
244 #define COPY_REVERSE(l) for(i=l.buf->count,source=l.buf->points+l.buf->count-1;i>0; i--,*(dest++)=*(source--)) 
245 void join_lines(LINE_END line1,LINE_END line2)
246 {int i;
247  LINEBUF source,dest;
248  LINE_INODE new;
249  if (line1.buf==line2.buf)
250   { put_line(line1.buf);
251     return;
252   } 
253  new=malloc(sizeof(struct INODE)); 
254  new->count=line1.buf->count+line2.buf->count-1;
255  new->limit=(new->count+DELTA-1)/DELTA*DELTA;
256  new->points=malloc(new->limit*sizeof(U_POINT));
257  dest=new->points;
258
259  if (line1.tail)
260  {
261     new->x_head=line1.buf->x_head;
262     COPY_DIRECT(line1);
263     dest--;
264
265  if (line2.tail)
266   { 
267     DEBUG_CHECK(x_tail,x_tail);
268     new->x_tail=line2.buf->x_head;
269     COPY_REVERSE(line2);    
270   }
271  else
272   { DEBUG_CHECK(x_tail,x_head);
273     new->x_tail=line2.buf->x_tail;
274     COPY_DIRECT(line2);
275   }
276  }
277  else
278  { 
279    new->x_head=line1.buf->x_tail;
280    COPY_REVERSE(line1);
281    dest--;
282    if (line2.tail)
283    { DEBUG_CHECK(x_head,x_tail);
284      new->x_tail=line2.buf->x_head;
285      COPY_REVERSE(line2);
286    }
287    else
288    { DEBUG_CHECK(x_head,x_head);
289      new->x_tail=line2.buf->x_tail;
290      COPY_DIRECT(line2);
291    }
292  }
293  new->both_ends=-1;
294  if (line1.buf->both_ends)
295   { new->both_ends++;
296     lines[new->x_head].buf=new;
297     lines[new->x_head].tail=FALSE;
298   }
299  if (line2.buf->both_ends)
300   { new->both_ends++;
301     lines[new->x_tail].buf=new;
302     lines[new->x_tail].tail=TRUE;
303   }
304  if (new->both_ends<0) 
305      put_line(new);
306  free(line1.buf->points);
307  free(line2.buf->points);
308  free(line1.buf);
309  free(line2.buf);
310 }
311 LINE_INODE new_line(int both,int col1,int row1,int col2,int row2)
312 {LINE_INODE tmp=malloc(sizeof(struct INODE));
313  tmp->both_ends=both;
314  tmp->count=2;
315  tmp->limit=DELTA;
316  tmp->points=malloc(DELTA*sizeof(U_POINT));
317  tmp->points[0].x=col1;
318  tmp->points[0].y=row1;
319  tmp->points[1].x=col2;
320  tmp->points[1].y=row2;
321  tmp->x_head=col1;
322  tmp->x_tail=col2;
323  return tmp;
324 }
325 void getrow(int row)
326 { unsigned short int *tmp,*tmp2;
327   int i;
328   tmp=rp2;
329   rp2=rp1;
330   rp1=tmp;
331   if(row+source->fr<source->lr) 
332    {
333     epp_get(source,source->fc,source->fr+row);
334     memcpy(rp1+1,source->row,(source->lc-source->fc)*sizeof(short));
335     if (offsite_option) 
336     { rp1[0]=source->offsite;
337       rp1[source->lc-source->fc+1]=source->offsite;
338     }
339     else
340     { rp1[0]=rp1[1];
341       tmp=rp1+source->lc-source->fc;
342       *(tmp+1)=*tmp;
343     }
344    }
345   else
346    if (offsite_option)
347      for(i=source->lc-source->fc,tmp=rp1;i>=0;*(tmp++)=source->offsite,i--);
348    else
349      for(i=source->lc-source->fc,tmp=rp1,tmp2=rp2;i>=0;*(tmp++)=*(tmp2++),i--);
350   if (!row) 
351    if (offsite_option)
352      for(i=source->lc-source->fc+1,tmp=rp2;i>=0;*(tmp++)=source->offsite,i--);
353    else
354      for(i=source->lc-source->fc,tmp=rp2,tmp2=rp1;i>=0;*(tmp++)=*(tmp2++),i--);
355 }
356 void put_line(LINE_INODE line)
357 {static int lineno=1;
358  int c,n;LINEBUF p;LINEBUF buf;POINT *s;
359  if (tolerance) c=smooth(line,&buf);
360   else {c=line->count;buf=line->points;}
361  p=line->points;
362  while (c>0)
363  { if (c>500) {n=500;c-=499;} else {n=c;c=0;} 
364    s=dest->buffer->s;
365    dest->buffer->npoints=n;
366    dest->buffer->ID=1;
367    for(;n>0;p++,n--,s++)
368     {s->x=epp2dgtX(p->x);
369      s->y=epp2dgtY(p->y);
370     }
371    dgt_touch(dest);
372    dgt_next(dest); 
373    p--;
374   }
375  lineno++;
376  free(buf);
377  free(line);
378 }
379 int rowfact,colfact;
380 int create_header(EPP *epp,char *dgtname)
381 {EPPHEADER h;
382  get_epp_header(epp,&h);
383  dest=creat_dgt(dgtname,epp->XLeft,epp->YBottom,epp->XRight,epp->YTop,h.coord_sys);
384 if (dest==NULL) return errno;
385 source=epp;
386 rowfact=epp->lr-epp->fr;
387 colfact=epp->lc-epp->fc;
388 if (tolerance) {rowfact*=2;colfact*=2;}
389 return 0;
390 }
391 int epp2dgtX(int col)
392 { return (col*(unsigned long)65535/colfact-32768);
393 }
394 int epp2dgtY(int row)
395 { return (32767-row*(unsigned long)65535/rowfact);
396
397 }
398 #ifdef __GNUC__
399 #define seg_len(a) abs(a->x-a[1].x?:a->y-a[1].y)
400 #else
401 #define seg_len(a) abs(a->x-a[1].x?a->x-a[1].x:a->y-a[1].y)
402 #endif
403 U_POINT make_middle_point(LINEBUF src1,LINEBUF src2)
404 {U_POINT tmp;
405  tmp.x=src1->x+src2->x;
406  tmp.y=src1->y+src2->y;
407  return tmp;
408 }
409 int smooth(LINE_INODE line,LINEBUF *buf)
410 {LINEBUF tmp; 
411  LINEBUF dest,src1,src2;
412  int i,prev_kept=TRUE;
413  if (line->count==2)
414  { *buf=line->points;
415    line->points->x=2*line->points->x;
416    line->points->y=2*line->points->y;
417    line->points[1].x=2*line->points[1].x;
418    line->points[1].y=2*line->points[1].y;
419    return 2;
420  } 
421  src1=line->points;
422  tmp=malloc(((4*line->count)/3+1)*sizeof(U_POINT));
423  tmp->x=src1->x*2;
424  tmp->y=src1->y*2;
425  dest=tmp+1;
426  *buf=tmp;
427  for(i=line->count-2,src2=src1+1;i>=0;i--,src1++,src2++)
428  { 
429    if (prev_kept)
430    { if (seg_len(src1)<tolerance)
431        {*(dest++)=make_middle_point(src1,src2);prev_kept=FALSE;}
432      else
433      {
434       if (i&&seg_len(src2)<tolerance)
435         {*(dest++)= make_middle_point(src1,src2);prev_kept=FALSE;}
436       else
437         {dest->x=src2->x*2;
438          dest->y=src2->y*2;dest++;
439         }
440       }
441     }
442     else
443     { U_POINT tmp=make_middle_point(src1,src2);
444       dest--;
445       if (((dest-1)->x-dest->x)*(dest->y-tmp.y)==
446          ((dest-1)->y-dest->y)*(dest->x-tmp.x)) *dest=tmp; else *(++dest)=tmp;
447       dest++;
448       if(seg_len(src1)>tolerance)
449        { 
450          if(i&&seg_len(src2)>tolerance)
451           { dest->x=src2->x*2;
452             dest->y=src2->y*2;
453             dest++;
454             prev_kept=TRUE; }  
455        }
456     }
457   }
458  dest->x=src1->x*2;
459  dest->y=src1->y*2; 
460  dest--;
461  if(line->count>4)
462  {
463  if(seg_len(dest)<tolerance) *dest=dest[1]; else dest++;
464  if(seg_len(tmp)<tolerance) *(++tmp)=**buf;
465  } else dest++;
466  free(line->points);
467  line->count=dest-tmp+1;
468  line->points=tmp;
469  return line->count;
470 }
471 void write_labels(EPP *epp,DGT *dgt)
472 {
473 }
474
475 int main(int argc,char **argv)
476 { struct option longoptions[]={
477   {"tolerance",1,0,'t'},
478   {"margin",0,0,'m'},
479   {"output-file",1,0,'o'},
480   {"labels",0,0,'l'},
481   {"verbose",0,0,'%'},
482   {"margins",0,0,'m'},
483   {"help",0,0,1},
484   {"version",0,0,2},
485   {NULL,0,0,0}};
486   int c,index;
487   int verbose=0;
488   int tolerance=0,draw_frame=1,do_labels=0;
489   char *endptr,outname[1024]="";
490   EPP *epp;
491   while ((c=getopt_long(argc,argv,"t:mo:l%",longoptions,&index))!=-1)
492    switch(c)
493    {
494     case 't':tolerance=strtol(optarg,&endptr,0);
495              if (*endptr||tolerance<0||tolerance>100) 
496                { fprintf(stderr,"Invalalid tolerance value %s\n",optarg);
497                  exit(1);
498                }
499              break;
500     case 'f':draw_frame=0;break;
501     case 'l':do_labels=1;break;
502     case 'm':draw_frame=0;break;
503
504     case '%':verbose=1;break;
505     case 'o':strcpy(outname,default_ext(optarg,".dgt"));
506              break; 
507     case 2:show_version("border","$Revision: 1.1 $");  
508     case 1:
509     default:
510             printf ("Usage:border [-%%][-f][-l][-t value][-o file] file.epp\n");
511             return (c!=1); 
512     }
513    if (optind==argc) { fprintf(stderr,"No input file given\n"); 
514                        exit(1);
515                      }
516    if (!*outname) strcpy(outname,force_ext(argv[optind],".dgt"));
517    epp=open_epp(default_ext(argv[optind],".epp"));
518    if (!epp) {fprintf(stderr,"Cannot open input file %s\n",argv[optind]);
519               exit(1);
520              }
521    install_progress_indicator(verbose?show_percent:check_int);
522    if ((c=clear_progress(
523         border_dgt(epp,outname,draw_frame,tolerance,do_labels))))
524    unlink(outname);
525    return c;
526 }