|
|
1.1 root 1: #include "map.h"
2:
3: #define NTRACK 10 /* max number of -t and -u files */
4: #define NFILE 30 /* max number of map files */
5: #define NVERT 20 /* max number of vertices in a -v polygon */
6: #define HALFWIDTH 8192 /* output scaled to fit in -HALFWIDTH,HALFWIDTH */
7: #define LONGLINES (HALFWIDTH*4) /* permissible segment lengths */
8: #define SHORTLINES (HALFWIDTH/8)
9: #define SCALERATIO 10 /* of abs to rel data (see map(5)) */
10: #define RESOL 2. /* coarsest resolution for tracing grid (degrees) */
11: #define TWO_THRD 0.66666666666666667
12:
13: int normproj(double, double, double *, double *);
14: int posproj(double, double, double *, double *);
15: int picut(struct place *, struct place *, double *);
16: double reduce(double);
17: short getshort(FILE *);
18: char *mapindex(char *);
19: proj projection;
20:
21:
22: static char *mapdir = "/usr/dict"; /* default map directory */
23: static char *file[NFILE+1] = { /* list of map files */
24: "world", /* default map */
25: 0
26: };
27:
28:
29: extern struct index index[];
30: int halfwidth = HALFWIDTH;
31:
32: static int (*cut)(struct place *, struct place *, double *);
33: static int poles;
34: static double orientation[3] = { 90., 0., 0. }; /* -o option */
35: static oriented; /* nonzero if -o option occurred */
36: static upright; /* 1 if orientation[0]==90, -1 if -90, else 0*/
37: static int delta = 1; /* -d setting */
38: static double limits[4] = { /* -l parameters */
39: -90., 90., -180., 180.
40: };
41: static double klimits[4] = { /* -k parameters */
42: -90., 90., -180., 180.
43: };
44: static int limcase;
45: static double rlimits[4]; /* limits expressed in radians */
46: static double lolat, hilat, lolon, hilon;
47: static double window[4] = { /* option -w */
48: -90., 90., -180., 180.
49: };
50: static windowed; /* nozero if option -w */
51: static struct vert { double x, y; } v[NVERT+2]; /*clipping polygon*/
52: static struct edge { double a, b, c; } e[NVERT]; /* coeffs for linear inequality */
53: static int nvert; /* number of vertices in clipping polygon */
54:
55: static double rwindow[4]; /* window, expressed in radians */
56: static double params[2]; /* projection params */
57: /* bounds on output values before scaling; found by coarse survey */
58: static double xmin = 100.;
59: static double xmax = -100.;
60: static double ymin = 100.;
61: static double ymax = -100.;
62: static double xcent, ycent;
63: static double xoff, yoff;
64: double xrange, yrange;
65: static int left = -HALFWIDTH;
66: static int right = HALFWIDTH;
67: static int bottom = -HALFWIDTH;
68: static int top = HALFWIDTH;
69: static int longlines = SHORTLINES; /* drop longer segments */
70: static int shortlines = SHORTLINES;
71: static int bflag = 1; /* 0 for option -b */
72: static int s1flag = 0; /* 1 for option -s1 */
73: static int s2flag = 0; /* 1 for option -s2 */
74: static int rflag = 0; /* 1 for option -r */
75: static int mflag = 0; /* 1 if option -m occurred */
76: static int kflag = 0; /* 1 if option -k occurred */
77: static double position[3]; /* option -p */
78: static double center[3] = {0., 0., 0.}; /* option -c */
79: static struct coord crot; /* option -c */
80: static double grid[3] = { 10., 10., RESOL }; /* option -g */
81: static double dlat, dlon; /* resolution for tracing grid in lat and lon */
82: static double scaling; /* to compute final integer output */
83: static struct track { /* options -t and -u */
84: int tracktyp; /* 't' or 'u' */
85: char *tracknam; /* name of input file */
86: } track[NTRACK];
87: static int ntrack; /* number of tracks present */
88: static char *symbolfile; /* option -y */
89:
90: void clamp(double *px, double v);
91: void clipinit(void);
92: double diddle(struct place *, double, double);
93: double diddle(struct place *, double, double);
94: void dobounds(double, double, double, double, int);
95: void dogrid(double, double, double, double);
96: int duple(struct place *, double);
97: double fmax(double, double);
98: double fmin(double, double);
99: void getdata(char *);
100: int gridpt(double, double, int);
101: int inpoly(double, double);
102: int inwindow(struct place *);
103: void pathnames(void);
104: int pnorm(double);
105: void radbds(double *w, double *rw);
106: void revlon(struct place *, double);
107: void satellite(struct track *);
108: int seeable(double, double);
109: void windlim(void);
110: void realcut(void);
111:
112: int
113: option(char *s)
114: {
115:
116: if(s[0]=='-' && (s[1]<'0'||s[1]>'9'))
117: return(s[1]!='.'&&s[1]!=0);
118: else
119: return(0);
120: }
121:
122: void
123: conv(int k, struct coord *g)
124: {
125: g->l = (0.0001/SCALERATIO)*k;
126: sincos(g);
127: }
128:
129: int
130: main(int argc, char *argv[])
131: {
132: int i,k;
133: char *s, *t;
134: double x, y;
135: double lat, lon;
136: double *wlim;
137: double dd;
138: if(sizeof(short)!=2)
139: abort(); /* getshort() won't work */
140: s = getenv("MAP");
141: if(s)
142: file[0] = s;
143: s = getenv("MAPDIR");
144: if(s)
145: mapdir = s;
146: if(argc<=1)
147: error("usage: map projection params options");
148: for(k=0;index[k].name;k++) {
149: s = index[k].name;
150: t = argv[1];
151: while(*s == *t){
152: if(*s==0) goto found;
153: s++;
154: t++;
155: }
156: }
157: fprintf(stderr,"projections:\n");
158: for(i=0;index[i].name;i++) {
159: fprintf(stderr,"%s",index[i].name);
160: for(k=0; k<index[i].npar; k++)
161: fprintf(stderr," p%d", k);
162: fprintf(stderr,"\n");
163: }
164: exit(1);
165: found:
166: argv += 2;
167: argc -= 2;
168: cut = index[k].cut;
169: poles = index[k].poles;
170: for(i=0;i<index[k].npar;i++) {
171: if(i>=argc||option(argv[i])) {
172: fprintf(stderr,"%s needs %d params\n",index[k].name,index[k].npar);
173: exit(1);
174: }
175: params[i] = atof(argv[i]);
176: }
177: argv += i;
178: argc -= i;
179: while(argc>0&&option(argv[0])) {
180: argc--;
181: argv++;
182: switch(argv[-1][1]) {
183: case 'm':
184: i = 0;
185: if(!mflag) while(file[i]!=0)
186: i++;
187: for(i=0;i<NFILE&&argc>i&&!option(argv[i]);i++)
188: file[i] = argv[i];
189: file[i] = 0;
190: mflag++;
191: argc -= i;
192: argv += i;
193: break;
194: case 'b':
195: bflag = 0;
196: for(nvert=0;nvert<NVERT&&argc>=2;nvert++) {
197: if(option(*argv))
198: break;
199: v[nvert].x = atof(*argv++);
200: argc--;
201: if(option(*argv))
202: break;
203: v[nvert].y = atof(*argv++);
204: argc--;
205: }
206: if(nvert>=NVERT)
207: error("too many clipping vertices");
208: break;
209: case 'g':
210: for(i=0;i<3&&argc>i&&!option(argv[i]);i++)
211: grid[i] = atof(argv[i]);
212: switch(i) {
213: case 0:
214: grid[0] = grid[1] = 0.;
215: break;
216: case 1:
217: grid[1] = grid[0];
218: }
219: argc -= i;
220: argv += i;
221: break;
222: case 't':
223: case 'u':
224: for(i=0;ntrack<NTRACK&&argc>i&&!option(argv[i]);i++) {
225: track[ntrack].tracktyp = argv[-1][1];
226: track[ntrack++].tracknam = argv[i];
227: }
228: argc -= i;
229: argv +=i;
230: break;
231: case 'r':
232: rflag++;
233: break;
234: case 's':
235: switch(argv[-1][2]) {
236: case '1':
237: s1flag++;
238: break;
239: case 0: /* compatibility */
240: case '2':
241: s2flag++;
242: }
243: break;
244: case 'o':
245: for(i=0;i<3&&i<argc&&!option(argv[i]);i++)
246: orientation[i] = atof(argv[i]);
247: oriented++;
248: argv += i;
249: argc -= i;
250: break;
251: case 'l':
252: for(i=0;i<argc&&i<4&&!option(argv[i]);i++)
253: limits[i] = atof(argv[i]);
254: argv += i;
255: argc -= i;
256: break;
257: case 'k':
258: kflag++;
259: for(i=0;i<argc&&i<4&&!option(argv[i]);i++)
260: klimits[i] = atof(argv[i]);
261: argv += i;
262: argc -= i;
263: break;
264: case 'd':
265: if(argc>0&&!option(argv[0])) {
266: delta = atoi(argv[0]);
267: argv++;
268: argc--;
269: }
270: break;
271: case 'w':
272: windowed++;
273: for(i=0;i<argc&&i<4&&!option(argv[i]);i++)
274: window[i] = atof(argv[i]);
275: argv += i;
276: argc -= i;
277: break;
278: case 'c':
279: for(i=0;i<3&&argc>i&&!option(argv[i]);i++)
280: center[i] = atof(argv[i]);
281: argc -= i;
282: argv += i;
283: break;
284: case 'p':
285: for(i=0;i<3&&argc>i&&!option(argv[i]);i++)
286: position[i] = atof(argv[i]);
287: argc -= i;
288: argv += i;
289: if(i!=3||position[2]<=0)
290: error("incomplete positioning");
291: break;
292: case 'y':
293: if(argc>0&&!option(argv[0]))
294: symbolfile = argv[0];
295: argc--;
296: argv++;
297: break;
298: }
299: }
300: if(argc>0)
301: error("error in arguments");
302: pathnames();
303: clamp(&limits[0],-90.);
304: clamp(&limits[1],90.);
305: clamp(&klimits[0],-90.);
306: clamp(&klimits[1],90.);
307: clamp(&window[0],-90.);
308: clamp(&window[1],90.);
309: radbds(limits,rlimits);
310: limcase = limits[2]<-180.?0:
311: limits[3]>180.?2:
312: 1;
313: if(
314: window[0]>=window[1]||
315: window[2]>=window[3]||
316: window[0]>90.||
317: window[1]<-90.||
318: window[2]>180.||
319: window[3]<-180.)
320: error("unreasonable window");
321: windlim();
322: radbds(window,rwindow);
323: upright = orientation[0]==90? 1: orientation[0]==-90? -1: 0;
324: if(index[k].spheroid && !upright)
325: error("can't tilt the spheroid");
326: if(limits[2]>limits[3])
327: limits[3] += 360;
328: if(!oriented)
329: orientation[2] = (limits[2]+limits[3])/2;
330: orient(orientation[0],orientation[1],orientation[2]);
331: projection = (*index[k].prog)(params[0],params[1]);
332: if(projection == 0)
333: error("unreasonable projection parameters");
334: clipinit();
335: grid[0] = fabs(grid[0]);
336: grid[1] = fabs(grid[1]);
337: if(!kflag)
338: for(i=0;i<4;i++)
339: klimits[i] = limits[i];
340: if(klimits[2]>klimits[3])
341: klimits[3] += 360;
342: lolat = limits[0];
343: hilat = limits[1];
344: lolon = limits[2];
345: hilon = limits[3];
346: if(lolon>=hilon||lolat>=hilat||lolat<-90.||hilat>90.)
347: error("unreasonable limits");
348: wlim = kflag? klimits: window;
349: dlat = fmin(hilat-lolat,wlim[1]-wlim[0])/16;
350: dlon = fmin(hilon-lolon,wlim[3]-wlim[2])/32;
351: dd = fmax(dlat,dlon);
352: while(grid[2]>fmin(dlat,dlon)/2)
353: grid[2] /= 2;
354: realcut();
355: if(nvert<=0) {
356: for(lat=klimits[0];lat<klimits[1]+dd-FUZZ;lat+=dd) {
357: if(lat>klimits[1])
358: lat = klimits[1];
359: for(lon=klimits[2];lon<klimits[3]+dd-FUZZ;lon+=dd) {
360: if((kflag?posproj:normproj)
361: (lat,lon+(lon<klimits[3]?FUZZ:-FUZZ),
362: &x,&y)<=0)
363: continue;
364: if(x<xmin) xmin = x;
365: if(x>xmax) xmax = x;
366: if(y<ymin) ymin = y;
367: if(y>ymax) ymax = y;
368: }
369: }
370: } else {
371: for(i=0; i<nvert; i++) {
372: x = v[i].x;
373: y = v[i].y;
374: if(x<xmin) xmin = x;
375: if(x>xmax) xmax = x;
376: if(y<ymin) ymin = y;
377: if(y>ymax) ymax = y;
378: }
379: }
380: xrange = xmax - xmin;
381: yrange = ymax - ymin;
382: if(xrange<=0||yrange<=0)
383: error("map seems to be empty");
384: scaling = 2; /*plotting area from -1 to 1*/
385: if(position[2]!=0) {
386: if(posproj(position[0]-.5,position[1],&xcent,&ycent)<=0||
387: posproj(position[0]+.5,position[1],&x,&y)<=0)
388: error("unreasonable position");
389: scaling /= (position[2]*hypot(x-xcent,y-ycent));
390: if(posproj(position[0],position[1],&xcent,&ycent)<=0)
391: error("unreasonable position");
392: } else {
393: scaling /= (xrange>yrange?xrange:yrange);
394: xcent = (xmin+xmax)/2;
395: ycent = (ymin+ymax)/2;
396: }
397: xoff = center[0]/scaling;
398: yoff = center[1]/scaling;
399: crot.l = center[2]*RAD;
400: sincos(&crot);
401: scaling *= HALFWIDTH*0.9;
402: if(symbolfile)
403: getsyms(symbolfile);
404: if(!s2flag) {
405: openpl();
406: erase();
407: }
408: range(left,bottom,right,top);
409: pen("dotted");
410: if(grid[0]>0.)
411: for(lat=ceil(lolat/grid[0])*grid[0];
412: lat<=hilat;lat+=grid[0])
413: dogrid(lat,lat,lolon,hilon);
414: if(grid[1]>0.)
415: for(lon=ceil(lolon/grid[1])*grid[1];
416: lon<=hilon;lon+=grid[1])
417: dogrid(lolat,hilat,lon,lon);
418: pen("solid");
419: if(bflag) {
420: dobounds(lolat,hilat,lolon,hilon,0);
421: dobounds(window[0],window[1],window[2],window[3],1);
422: }
423: lolat = floor(limits[0]/10)*10;
424: hilat = ceil(limits[1]/10)*10;
425: lolon = floor(limits[2]/10)*10;
426: hilon = ceil(limits[3]/10)*10;
427: if(lolon>hilon)
428: hilon += 360.;
429: /*do tracks first so as not to lose the standard input*/
430: for(i=0;i<ntrack;i++) {
431: longlines = LONGLINES;
432: satellite(&track[i]);
433: longlines = shortlines;
434: }
435: pen("solid");
436: for(i=0;file[i];i++)
437: getdata(file[i]);
438:
439: move(right,bottom);
440: if(!s1flag)
441: closepl();
442: return 0;
443: }
444:
445:
446: int
447: normproj(double lat, double lon, double *x, double *y)
448: {
449: int i;
450: struct place geog;
451: latlon(lat,lon,&geog);
452: /*
453: printp(&geog);
454: */
455: normalize(&geog);
456: if(!inwindow(&geog))
457: return(-1);
458: i = (*projection)(&geog,x,y);
459: if(rflag)
460: *x = -*x;
461: /*
462: printp(&geog);
463: fprintf(stderr,"%d %.3f %.3f\n",i,*x,*y);
464: */
465: return(i);
466: }
467:
468: int
469: posproj(double lat, double lon, double *x, double *y)
470: {
471: int i;
472: struct place geog;
473: latlon(lat,lon,&geog);
474: normalize(&geog);
475: i = (*projection)(&geog,x,y);
476: if(rflag)
477: *x = -*x;
478: return(i);
479: }
480:
481: int
482: inwindow(struct place *geog)
483: {
484: if(geog->nlat.l<rwindow[0]||
485: geog->nlat.l>rwindow[1]||
486: geog->wlon.l<rwindow[2]||
487: geog->wlon.l>rwindow[3])
488: return(0);
489: else return(1);
490: }
491:
492: int
493: inlimits(struct place *g)
494: {
495: if(rlimits[0]>g->nlat.l||
496: rlimits[1]<g->nlat.l)
497: return(0);
498: switch(limcase) {
499: case 0:
500: if(rlimits[2]+TWOPI>g->wlon.l&&
501: rlimits[3]<g->wlon.l)
502: return(0);
503: break;
504: case 1:
505: if(rlimits[2]>g->wlon.l||
506: rlimits[3]<g->wlon.l)
507: return(0);
508: break;
509: case 2:
510: if(rlimits[2]>g->wlon.l&&
511: rlimits[3]-TWOPI<g->wlon.l)
512: return(0);
513: break;
514: }
515: return(1);
516: }
517:
518:
519: long patch[18][36];
520:
521: void
522: getdata(char *mapfile)
523: {
524: char *indexfile;
525: int kx,ky,c;
526: int k;
527: long b;
528: long *p;
529: int ip, jp;
530: int n;
531: struct place g;
532: int i, j;
533: double lat, lon;
534: int conn;
535: FILE *ifile, *xfile;
536:
537: indexfile = mapindex(mapfile);
538: xfile = fopen(indexfile,"r");
539: if(xfile==NULL)
540: filerror("can't find map index", indexfile);
541: free(indexfile);
542: for(i=0,p=patch[0];i<18*36;i++,p++)
543: *p = 1;
544: while(!feof(xfile) && fscanf(xfile,"%d%d%ld",&i,&j,&b)==3)
545: patch[i+9][j+18] = b;
546: fclose(xfile);
547: ifile = fopen(mapfile,"r");
548: if(ifile==NULL)
549: filerror("can't find map data", mapfile);
550: for(lat=lolat;lat<hilat;lat+=10.)
551: for(lon=lolon;lon<hilon;lon+=10.) {
552: if(!seeable(lat,lon))
553: continue;
554: i = pnorm(lat);
555: j = pnorm(lon);
556: if((b=patch[i+9][j+18])&1)
557: continue;
558: fseek(ifile,b,0);
559: while((ip=getc(ifile))>=0&&(jp=getc(ifile))>=0){
560: if(ip!=(i&0377)||jp!=(j&0377))
561: break;
562: n = getshort(ifile);
563: conn = 0;
564: if(n > 0) { /* absolute coordinates */
565: for(k=0;k<n;k++){
566: kx = SCALERATIO*getshort(ifile);
567: ky = SCALERATIO*getshort(ifile);
568: if (((k%delta) != 0) && (k != (n-1)))
569: continue;
570: conv(kx,&g.nlat);
571: conv(ky,&g.wlon);
572: conn = plotpt(&g,conn);
573: }
574: } else { /* differential, scaled by SCALERATI0 */
575: n = -n;
576: kx = SCALERATIO*getshort(ifile);
577: ky = SCALERATIO*getshort(ifile);
578: for(k=0; k<n; k++) {
579: c = getc(ifile);
580: if(c&0200) c|= ~0177;
581: kx += c;
582: c = getc(ifile);
583: if(c&0200) c|= ~0177;
584: ky += c;
585: if(k%delta!=0&&k!=n-1)
586: continue;
587: conv(kx,&g.nlat);
588: conv(ky,&g.wlon);
589: conn = plotpt(&g,conn);
590: }
591: }
592: if(k==1) {
593: conv(kx,&g.nlat);
594: conv(ky,&g.wlon);
595: conn = plotpt(&g,conn);
596: }
597: }
598: }
599: fclose(ifile);
600: }
601:
602: int
603: seeable(double lat0, double lon0)
604: {
605: double x, y;
606: double lat, lon;
607: for(lat=lat0;lat<=lat0+10;lat+=2*grid[2])
608: for(lon=lon0;lon<=lon0+10;lon+=2*grid[2])
609: if(normproj(lat,lon,&x,&y)>0)
610: return(1);
611: return(0);
612: }
613:
614: void
615: satellite(struct track *t)
616: {
617: char sym[50];
618: char lbl[50];
619: double scale;
620: register conn;
621: double lat,lon;
622: struct place place;
623: static FILE *ifile = stdin;
624: if(t->tracknam[0]!='-'||t->tracknam[1]!=0) {
625: fclose(ifile);
626: if((ifile=fopen(t->tracknam,"r"))==NULL)
627: filerror("can't find track", t->tracknam);
628: }
629: pen(t->tracktyp=='t'?"dotdash":"solid");
630: for(;;) {
631: conn = 0;
632: while(!feof(ifile) && fscanf(ifile,"%f%f",&lat,&lon)==2){
633: latlon(lat,lon,&place);
634: if(fscanf(ifile,"%1s",lbl) == 1) {
635: if(strchr("+-.0123456789",*lbl)==0)
636: break;
637: ungetc(*lbl,ifile);
638: }
639: conn = plotpt(&place,conn);
640: }
641: if(feof(ifile))
642: return;
643: fscanf(ifile,"%[^\n]",lbl+1);
644: switch(*lbl) {
645: case '"':
646: if(plotpt(&place,conn))
647: text(lbl+1);
648: break;
649: case ':':
650: case '!':
651: if(sscanf(lbl+1,"%s %f",sym,&scale) <= 1)
652: scale = 1;
653: if(plotpt(&place,conn?conn:-1)) {
654: int r = *lbl=='!'?0:rflag?-1:1;
655: if(putsym(&place,sym,scale,r) == 0)
656: text(lbl);
657: }
658: break;
659: default:
660: if(plotpt(&place,conn))
661: text(lbl);
662: break;
663: }
664: }
665: }
666:
667: int
668: pnorm(double x)
669: {
670: int i;
671: i = x/10.;
672: i %= 36;
673: if(i>=18) return(i-36);
674: if(i<-18) return(i+36);
675: return(i);
676: }
677:
678: void
679: error(char *s)
680: {
681: fprintf(stderr,"map: \r\n%s\n",s);
682: exit(1);
683: }
684:
685: void
686: filerror(char *s, char *f)
687: {
688: fprintf(stderr,"\r\n%s %s\n",s,f);
689: exit(1);
690: }
691:
692: char *
693: mapindex(char *s)
694: {
695: char *t = malloc(strlen(s)+3);
696: strcpy(t,s);
697: strcat(t,".x");
698: return t;
699: }
700:
701: #define NOPT 32767
702: static ox = NOPT, oy = NOPT;
703:
704: int
705: cpoint(int xi, int yi, int conn)
706: {
707: int dx = abs(ox-xi);
708: int dy = abs(oy-yi);
709: if(xi<left||xi>=right || yi<bottom||yi>=top) {
710: ox = oy = NOPT;
711: return 0;
712: }
713: if(conn == -1) /* isolated plotting symbol */
714: ;
715: else if(!conn)
716: move(xi,yi);
717: else {
718: if(dx+dy>longlines) {
719: ox = oy = NOPT; /* don't leap across cuts */
720: return 0;
721: }
722: if(dx || dy)
723: vec(xi,yi);
724: }
725: ox = xi, oy = yi;
726: return dx+dy<=2? 2: 1; /* 2=very near; see dogrid */
727: }
728:
729:
730: struct place oldg;
731:
732: int
733: plotpt(struct place *g, int conn)
734: {
735: int kx,ky;
736: int ret;
737: double cutlon;
738: if(!inlimits(g)) {
739: return(0);
740: }
741: normalize(g);
742: if(!inwindow(g)) {
743: return(0);
744: }
745: switch((*cut)(g,&oldg,&cutlon)) {
746: case 2:
747: if(conn) {
748: ret = duple(g,cutlon)|duple(g,cutlon);
749: oldg = *g;
750: return(ret);
751: }
752: case 0:
753: conn = 0;
754: default: /* prevent diags about bad return value */
755: case 1:
756: oldg = *g;
757: if(doproj(g,&kx,&ky)<=0) {
758: return(0);
759: }
760: ret = cpoint(kx,ky,conn);
761: return ret;
762: }
763: }
764:
765: int
766: doproj(struct place *g, int *kx, int *ky)
767: {
768: double x,y,x1,y1;
769: /*fprintf(stderr,"dopr1 %f %f \n",g->nlat.l,g->wlon.l);*/
770: if((*projection)(g,&x,&y)<=0) {
771: return(0);
772: }
773: if(rflag)
774: x = -x;
775: /*fprintf(stderr,"dopr2 %f %f\n",x,y);*/
776: if(!inpoly(x,y)) {
777: return 0;
778: }
779: x1 = x - xcent;
780: y1 = y - ycent;
781: x = (x1*crot.c - y1*crot.s + xoff)*scaling;
782: y = (x1*crot.s + y1*crot.c + yoff)*scaling;
783: *kx = x + (x>0?.5:-.5);
784: *ky = y + (y>0?.5:-.5);
785: return(1);
786: }
787:
788: int
789: duple(struct place *g, double cutlon)
790: {
791: int kx,ky;
792: int okx,oky;
793: struct place ig;
794: revlon(g,cutlon);
795: revlon(&oldg,cutlon);
796: ig = *g;
797: invert(&ig);
798: if(!inlimits(&ig))
799: return(0);
800: if(doproj(g,&kx,&ky)<=0 || doproj(&oldg,&okx,&oky)<=0)
801: return(0);
802: cpoint(okx,oky,0);
803: cpoint(kx,ky,1);
804: return(1);
805: }
806:
807: void
808: revlon(struct place *g, double cutlon)
809: {
810: g->wlon.l = reduce(cutlon-reduce(g->wlon.l-cutlon));
811: sincos(&g->wlon);
812: }
813:
814:
815: /* recognize problems of cuts
816: * move a point across cut to side of its predecessor
817: * if its very close to the cut
818: * return(0) if cut interrupts the line
819: * return(1) if line is to be drawn normally
820: * return(2) if line is so close to cut as to
821: * be properly drawn on both sheets
822: */
823:
824: int
825: picut(struct place *g, struct place *og, double *cutlon)
826: {
827: *cutlon = PI;
828: return(ckcut(g,og,PI));
829: }
830:
831: int
832: nocut(struct place *g, struct place *og, double *cutlon)
833: {
834: #pragma ref g
835: #pragma ref og
836: #pragma ref cutlon
837: return(1);
838: }
839:
840: int
841: ckcut(struct place *g1, struct place *g2, double lon)
842: {
843: double d1, d2;
844: double f1, f2;
845: int kx,ky;
846: d1 = reduce(g1->wlon.l -lon);
847: d2 = reduce(g2->wlon.l -lon);
848: if((f1=fabs(d1))<FUZZ)
849: d1 = diddle(g1,lon,d2);
850: if((f2=fabs(d2))<FUZZ) {
851: d2 = diddle(g2,lon,d1);
852: if(doproj(g2,&kx,&ky)>0)
853: cpoint(kx,ky,0);
854: }
855: if(f1<FUZZ&&f2<FUZZ)
856: return(2);
857: if(f1>PI*TWO_THRD||f2>PI*TWO_THRD)
858: return(1);
859: return(d1*d2>=0);
860: }
861:
862: double
863: diddle(struct place *g, double lon, double d)
864: {
865: double d1;
866: d1 = FUZZ/2;
867: if(d<0)
868: d1 = -d1;
869: g->wlon.l = reduce(lon+d1);
870: sincos(&g->wlon);
871: return(d1);
872: }
873:
874: double
875: reduce(double lon)
876: {
877: if(lon>PI)
878: lon -= 2*PI;
879: else if(lon<-PI)
880: lon += 2*PI;
881: return(lon);
882: }
883:
884:
885: double tetrapt = 35.26438968; /* atan(1/sqrt(2)) */
886:
887: void
888: dogrid(double lat0, double lat1, double lon0, double lon1)
889: {
890: double slat,slon,tlat,tlon;
891: register int conn, oconn;
892: slat = tlat = slon = tlon = 0;
893: if(lat1>lat0)
894: slat = tlat = fmin(grid[2],dlat);
895: else
896: slon = tlon = fmin(grid[2],dlon);;
897: conn = oconn = 0;
898: while(lat0<=lat1&&lon0<=lon1) {
899: conn = gridpt(lat0,lon0,conn);
900: if(projection==Xguyou&&slat>0) {
901: if(lat0<-45&&lat0+slat>-45)
902: conn = gridpt(-45.,lon0,conn);
903: else if(lat0<45&&lat0+slat>45)
904: conn = gridpt(45.,lon0,conn);
905: } else if(projection==Xtetra&&slat>0) {
906: if(lat0<-tetrapt&&lat0+slat>-tetrapt) {
907: gridpt(-tetrapt-.001,lon0,conn);
908: conn = gridpt(-tetrapt+.001,lon0,0);
909: }
910: else if(lat0<tetrapt&&lat0+slat>tetrapt) {
911: gridpt(tetrapt-.001,lon0,conn);
912: conn = gridpt(tetrapt+.001,lon0,0);
913: }
914: }
915: if(conn==0 && oconn!=0) {
916: if(slat+slon>.05) {
917: lat0 -= slat; /* steps too big */
918: lon0 -= slon; /* or near bdry */
919: slat /= 2;
920: slon /= 2;
921: conn = oconn = gridpt(lat0,lon0,conn);
922: } else
923: oconn = 0;
924: } else {
925: if(conn==2) {
926: slat = tlat;
927: slon = tlon;
928: conn = 1;
929: }
930: oconn = conn;
931: }
932: lat0 += slat;
933: lon0 += slon;
934: }
935: gridpt(lat1,lon1,conn);
936: }
937:
938: static gridinv; /* nonzero when doing window bounds */
939:
940: int
941: gridpt(double lat, double lon, int conn)
942: {
943: struct place g;
944: /*fprintf(stderr,"%f %f\n",lat,lon);*/
945: latlon(lat,lon,&g);
946: if(gridinv)
947: invert(&g);
948: return(plotpt(&g,conn));
949: }
950:
951: /* win=0 ordinary grid lines, win=1 window lines */
952:
953: void
954: dobounds(double lolat, double hilat, double lolon, double hilon, int win)
955: {
956: gridinv = win;
957: if(lolat>-90 || win && (poles&1)!=0)
958: dogrid(lolat+FUZZ,lolat+FUZZ,lolon,hilon);
959: if(hilat<90 || win && (poles&2)!=0)
960: dogrid(hilat-FUZZ,hilat-FUZZ,lolon,hilon);
961: if(hilon-lolon<360 || win && cut==picut) {
962: dogrid(lolat,hilat,lolon+FUZZ,lolon+FUZZ);
963: dogrid(lolat,hilat,hilon-FUZZ,hilon-FUZZ);
964: }
965: gridinv = 0;
966: }
967:
968: void
969: radbds(double *w, double *rw)
970: {
971: int i;
972: for(i=0;i<4;i++)
973: rw[i] = w[i]*RAD;
974: rw[0] -= FUZZ;
975: rw[1] += FUZZ;
976: rw[2] -= FUZZ;
977: rw[3] += FUZZ;
978: }
979:
980: void
981: windlim(void)
982: {
983: double center = orientation[0];
984: double colat;
985: if(center>90)
986: center = 180 - center;
987: if(center<-90)
988: center = -180 - center;
989: if(fabs(center)>90)
990: error("unreasonable orientation");
991: colat = 90 - window[0];
992: if(center-colat>limits[0])
993: limits[0] = center - colat;
994: if(center+colat<limits[1])
995: limits[1] = center + colat;
996: }
997:
998:
999: short
1000: getshort(FILE *f)
1001: {
1002: int c, r;
1003: c = getc(f);
1004: r = (c | getc(f)<<8);
1005: if (r&0x8000)
1006: r |= ~0xFFFF; /* in case short > 16 bits */
1007: return r;
1008: }
1009:
1010: double
1011: fmin(double x, double y)
1012: {
1013: return(x<y?x:y);
1014: }
1015:
1016: double
1017: fmax(double x, double y)
1018: {
1019: return(x>y?x:y);
1020: }
1021:
1022: void
1023: clamp(double *px, double v)
1024: {
1025: *px = (v<0?fmax:fmin)(*px,v);
1026: }
1027:
1028: void
1029: pathnames(void)
1030: {
1031: int i;
1032: char *t, *indexfile;
1033: FILE *f, *fx;
1034: for(i=0; i<NFILE && file[i]; i++) {
1035: if(*file[i]=='/')
1036: continue;
1037: indexfile = mapindex(file[i]);
1038: /* ansi equiv of unix access() call */
1039: f = fopen(file[i], "r");
1040: fx = fopen(indexfile, "r");
1041: if(f) fclose(f);
1042: if(fx) fclose(fx);
1043: free(indexfile);
1044: if(f && fx)
1045: continue;
1046: t = malloc(strlen(file[i])+strlen(mapdir)+2);
1047: strcpy(t,mapdir);
1048: strcat(t,"/");
1049: strcat(t,file[i]);
1050: file[i] = t;
1051: }
1052: }
1053:
1054: void
1055: clipinit(void)
1056: {
1057: register i;
1058: double s,t;
1059: if(nvert<=0)
1060: return;
1061: for(i=0; i<nvert; i++) { /*convert latlon to xy*/
1062: if(normproj(v[i].x,v[i].y,&v[i].x,&v[i].y)<=0)
1063: error("invisible clipping vertex");
1064: }
1065: if(nvert==2) { /*rectangle with diag specified*/
1066: nvert = 4;
1067: v[2] = v[1];
1068: v[1].x=v[0].x, v[1].y=v[2].y, v[3].x=v[2].x, v[3].y=v[0].y;
1069: }
1070: v[nvert] = v[0];
1071: v[nvert+1] = v[1];
1072: s = 0;
1073: for(i=1; i<=nvert; i++) { /*test for convexity*/
1074: t = (v[i-1].x-v[i].x)*(v[i+1].y-v[i].y) -
1075: (v[i-1].y-v[i].y)*(v[i+1].x-v[i].x);
1076: if(t<-FUZZ && s>=0) s = 1;
1077: if(t>FUZZ && s<=0) s = -1;
1078: if(-FUZZ<=t&&t<=FUZZ || t*s>0) {
1079: s = 0;
1080: break;
1081: }
1082: }
1083: if(s==0)
1084: error("improper clipping polygon");
1085: for(i=0; i<nvert; i++) { /*edge equation ax+by=c*/
1086: e[i].a = s*(v[i+1].y - v[i].y);
1087: e[i].b = s*(v[i].x - v[i+1].x);
1088: e[i].c = s*(v[i].x*v[i+1].y - v[i].y*v[i+1].x);
1089: }
1090: }
1091:
1092: int
1093: inpoly(double x, double y)
1094: {
1095: register i;
1096: for(i=0; i<nvert; i++) {
1097: register struct edge *ei = &e[i];
1098: double val = x*ei->a + y*ei->b - ei->c;
1099: if(val>10*FUZZ)
1100: return(0);
1101: }
1102: return 1;
1103: }
1104:
1105: void
1106: realcut()
1107: {
1108: struct place g;
1109: double lat;
1110:
1111: if(cut != picut) /* punt on unusual cuts */
1112: return;
1113: for(lat=window[0]; lat<=window[1]; lat+=grid[2]) {
1114: g.wlon.l = PI;
1115: sincos(&g.wlon);
1116: g.nlat.l = lat*RAD;
1117: sincos(&g.nlat);
1118: if(!inwindow(&g)) {
1119: break;
1120: }
1121: invert(&g);
1122: if(inlimits(&g)) {
1123: return;
1124: }
1125: }
1126: longlines = shortlines = LONGLINES;
1127: cut = nocut; /* not necessary; small eff. gain */
1128: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.