|  | #include <u.h> | 
|  | #include <libc.h> | 
|  | #include <stdio.h> | 
|  | #include "map.h" | 
|  | #include "iplot.h" | 
|  |  | 
|  | #define NVERT 20	/* max number of vertices in a -v polygon */ | 
|  | #define HALFWIDTH 8192	/* output scaled to fit in -HALFWIDTH,HALFWIDTH */ | 
|  | #define LONGLINES (HALFWIDTH*4)	/* permissible segment lengths */ | 
|  | #define SHORTLINES (HALFWIDTH/8) | 
|  | #define SCALERATIO 10	/* of abs to rel data (see map(5)) */ | 
|  | #define RESOL 2.	/* coarsest resolution for tracing grid (degrees) */ | 
|  | #define TWO_THRD 0.66666666666666667 | 
|  |  | 
|  | int normproj(double, double, double *, double *); | 
|  | int posproj(double, double, double *, double *); | 
|  | int picut(struct place *, struct place *, double *); | 
|  | double reduce(double); | 
|  | short getshort(FILE *); | 
|  | char *mapindex(char *); | 
|  | proj projection; | 
|  |  | 
|  |  | 
|  | static char *mapdir = "#9/map";	/* default map directory */ | 
|  | struct file { | 
|  | char *name; | 
|  | char *color; | 
|  | char *style; | 
|  | }; | 
|  | static struct file dfltfile = { | 
|  | "world", BLACK, SOLID	/* default map */ | 
|  | }; | 
|  | static struct file *file = &dfltfile;	/* list of map files */ | 
|  | static int nfile = 1;			/* length of list */ | 
|  | static char *currcolor = BLACK;		/* current color */ | 
|  | static char *gridcolor = BLACK; | 
|  | static char *bordcolor = BLACK; | 
|  |  | 
|  | extern struct index index[]; | 
|  | int halfwidth = HALFWIDTH; | 
|  |  | 
|  | static int (*cut)(struct place *, struct place *, double *); | 
|  | static int (*limb)(double*, double*, double); | 
|  | static void dolimb(void); | 
|  | static int onlimb; | 
|  | static int poles; | 
|  | static double orientation[3] = { 90., 0., 0. };	/* -o option */ | 
|  | static int oriented;	/* nonzero if -o option occurred */ | 
|  | static int upright;		/* 1 if orientation[0]==90, -1 if -90, else 0*/ | 
|  | static int delta = 1;	/* -d setting */ | 
|  | static double limits[4] = {	/* -l parameters */ | 
|  | -90., 90., -180., 180. | 
|  | }; | 
|  | static double klimits[4] = {	/* -k parameters */ | 
|  | -90., 90., -180., 180. | 
|  | }; | 
|  | static int limcase; | 
|  | static double rlimits[4];	/* limits expressed in radians */ | 
|  | static double lolat, hilat, lolon, hilon; | 
|  | static double window[4] = {	/* option -w */ | 
|  | -90., 90., -180., 180. | 
|  | }; | 
|  | static int windowed;	/* nozero if option -w */ | 
|  | static struct vert { double x, y; } v[NVERT+2];	/*clipping polygon*/ | 
|  | static struct edge { double a, b, c; } e[NVERT]; /* coeffs for linear inequality */ | 
|  | static int nvert;	/* number of vertices in clipping polygon */ | 
|  |  | 
|  | static double rwindow[4];	/* window, expressed in radians */ | 
|  | static double params[2];		/* projection params */ | 
|  | /* bounds on output values before scaling; found by coarse survey */ | 
|  | static double xmin = 100.; | 
|  | static double xmax = -100.; | 
|  | static double ymin = 100.; | 
|  | static double ymax = -100.; | 
|  | static double xcent, ycent; | 
|  | static double xoff, yoff; | 
|  | double xrange, yrange; | 
|  | static int left = -HALFWIDTH; | 
|  | static int right = HALFWIDTH; | 
|  | static int bottom = -HALFWIDTH; | 
|  | static int top = HALFWIDTH; | 
|  | static int longlines = SHORTLINES; /* drop longer segments */ | 
|  | static int shortlines = SHORTLINES; | 
|  | static int bflag = 1;	/* 0 for option -b */ | 
|  | static int s1flag = 0;	/* 1 for option -s1 */ | 
|  | static int s2flag = 0;	/* 1 for option -s2 */ | 
|  | static int rflag = 0;	/* 1 for option -r */ | 
|  | static int kflag = 0;	/* 1 if option -k occurred */ | 
|  | static int xflag = 0;	/* 1 for option -x */ | 
|  | int vflag = 1;	/* -1 if option -v occurred */ | 
|  | static double position[3];	/* option -p */ | 
|  | static double center[3] = {0., 0., 0.};	/* option -c */ | 
|  | static struct coord crot;		/* option -c */ | 
|  | static double grid[3] = { 10., 10., RESOL };	/* option -g */ | 
|  | static double dlat, dlon;	/* resolution for tracing grid in lat and lon */ | 
|  | static double scaling;	/* to compute final integer output */ | 
|  | static struct file *track;	/* options -t and -u */ | 
|  | static int ntrack;		/* number of tracks present */ | 
|  | static char *symbolfile;	/* option -y */ | 
|  |  | 
|  | void	clamp(double *px, double v); | 
|  | void	clipinit(void); | 
|  | double	diddle(struct place *, double, double); | 
|  | double	diddle(struct place *, double, double); | 
|  | void	dobounds(double, double, double, double, int); | 
|  | void	dogrid(double, double, double, double); | 
|  | int	duple(struct place *, double); | 
|  | #define fmax map_fmax | 
|  | #define fmin map_fmin | 
|  | double	fmax(double, double); | 
|  | double	fmin(double, double); | 
|  | void	getdata(char *); | 
|  | int	gridpt(double, double, int); | 
|  | int	inpoly(double, double); | 
|  | int	inwindow(struct place *); | 
|  | void	pathnames(void); | 
|  | int	pnorm(double); | 
|  | void	radbds(double *w, double *rw); | 
|  | void	revlon(struct place *, double); | 
|  | void	satellite(struct file *); | 
|  | int	seeable(double, double); | 
|  | void	windlim(void); | 
|  | void	realcut(void); | 
|  |  | 
|  | int | 
|  | option(char *s) | 
|  | { | 
|  |  | 
|  | if(s[0]=='-' && (s[1]<'0'||s[1]>'9')) | 
|  | return(s[1]!='.'&&s[1]!=0); | 
|  | else | 
|  | return(0); | 
|  | } | 
|  |  | 
|  | void | 
|  | conv(int k, struct coord *g) | 
|  | { | 
|  | g->l = (0.0001/SCALERATIO)*k; | 
|  | sincos(g); | 
|  | } | 
|  |  | 
|  | int | 
|  | main(int argc, char *argv[]) | 
|  | { | 
|  | int i,k; | 
|  | char *s, *t, *style; | 
|  | double x, y; | 
|  | double lat, lon; | 
|  | double *wlim; | 
|  | double dd; | 
|  | if(sizeof(short)!=2) | 
|  | abort();	/* getshort() won't work */ | 
|  | mapdir = unsharp(mapdir); | 
|  | s = getenv("MAP"); | 
|  | if(s) | 
|  | file[0].name = s; | 
|  | s = getenv("MAPDIR"); | 
|  | if(s) | 
|  | mapdir = s; | 
|  | if(argc<=1) | 
|  | error("usage: map projection params options"); | 
|  | for(k=0;index[k].name;k++) { | 
|  | s = index[k].name; | 
|  | t = argv[1]; | 
|  | while(*s == *t){ | 
|  | if(*s==0) goto found; | 
|  | s++; | 
|  | t++; | 
|  | } | 
|  | } | 
|  | fprintf(stderr,"projections:\n"); | 
|  | for(i=0;index[i].name;i++)  { | 
|  | fprintf(stderr,"%s",index[i].name); | 
|  | for(k=0; k<index[i].npar; k++) | 
|  | fprintf(stderr," p%d", k); | 
|  | fprintf(stderr,"\n"); | 
|  | } | 
|  | exits("error"); | 
|  | found: | 
|  | argv += 2; | 
|  | argc -= 2; | 
|  | cut = index[k].cut; | 
|  | limb = index[k].limb; | 
|  | poles = index[k].poles; | 
|  | for(i=0;i<index[k].npar;i++) { | 
|  | if(i>=argc||option(argv[i])) { | 
|  | fprintf(stderr,"%s needs %d params\n",index[k].name,index[k].npar); | 
|  | exits("error"); | 
|  | } | 
|  | params[i] = atof(argv[i]); | 
|  | } | 
|  | argv += i; | 
|  | argc -= i; | 
|  | while(argc>0&&option(argv[0])) { | 
|  | argc--; | 
|  | argv++; | 
|  | switch(argv[-1][1]) { | 
|  | case 'm': | 
|  | if(file == &dfltfile) { | 
|  | file = 0; | 
|  | nfile = 0; | 
|  | } | 
|  | while(argc && !option(*argv)) { | 
|  | file = realloc(file,(nfile+1)*sizeof(*file)); | 
|  | file[nfile].name = *argv; | 
|  | file[nfile].color = currcolor; | 
|  | file[nfile].style = SOLID; | 
|  | nfile++; | 
|  | argv++; | 
|  | argc--; | 
|  | } | 
|  | break; | 
|  | case 'b': | 
|  | bflag = 0; | 
|  | for(nvert=0;nvert<NVERT&&argc>=2;nvert++) { | 
|  | if(option(*argv)) | 
|  | break; | 
|  | v[nvert].x = atof(*argv++); | 
|  | argc--; | 
|  | if(option(*argv)) | 
|  | break; | 
|  | v[nvert].y = atof(*argv++); | 
|  | argc--; | 
|  | } | 
|  | if(nvert>=NVERT) | 
|  | error("too many clipping vertices"); | 
|  | break; | 
|  | case 'g': | 
|  | gridcolor = currcolor; | 
|  | for(i=0;i<3&&argc>i&&!option(argv[i]);i++) | 
|  | grid[i] = atof(argv[i]); | 
|  | switch(i) { | 
|  | case 0: | 
|  | grid[0] = grid[1] = 0.; | 
|  | break; | 
|  | case 1: | 
|  | grid[1] = grid[0]; | 
|  | } | 
|  | argc -= i; | 
|  | argv += i; | 
|  | break; | 
|  | case 't': | 
|  | style = SOLID; | 
|  | goto casetu; | 
|  | case 'u': | 
|  | style = DOTDASH; | 
|  | casetu: | 
|  | while(argc && !option(*argv)) { | 
|  | track = realloc(track,(ntrack+1)*sizeof(*track)); | 
|  | track[ntrack].name = *argv; | 
|  | track[ntrack].color = currcolor; | 
|  | track[ntrack].style = style; | 
|  | ntrack++; | 
|  | argv++; | 
|  | argc--; | 
|  | } | 
|  | break; | 
|  | case 'r': | 
|  | rflag++; | 
|  | break; | 
|  | case 's': | 
|  | switch(argv[-1][2]) { | 
|  | case '1': | 
|  | s1flag++; | 
|  | break; | 
|  | case 0:		/* compatibility */ | 
|  | case '2': | 
|  | s2flag++; | 
|  | } | 
|  | break; | 
|  | case 'o': | 
|  | for(i=0;i<3&&i<argc&&!option(argv[i]);i++) | 
|  | orientation[i] = atof(argv[i]); | 
|  | oriented++; | 
|  | argv += i; | 
|  | argc -= i; | 
|  | break; | 
|  | case 'l': | 
|  | bordcolor = currcolor; | 
|  | for(i=0;i<argc&&i<4&&!option(argv[i]);i++) | 
|  | limits[i] = atof(argv[i]); | 
|  | argv += i; | 
|  | argc -= i; | 
|  | break; | 
|  | case 'k': | 
|  | kflag++; | 
|  | for(i=0;i<argc&&i<4&&!option(argv[i]);i++) | 
|  | klimits[i] = atof(argv[i]); | 
|  | argv += i; | 
|  | argc -= i; | 
|  | break; | 
|  | case 'd': | 
|  | if(argc>0&&!option(argv[0])) { | 
|  | delta = atoi(argv[0]); | 
|  | argv++; | 
|  | argc--; | 
|  | } | 
|  | break; | 
|  | case 'w': | 
|  | bordcolor = currcolor; | 
|  | windowed++; | 
|  | for(i=0;i<argc&&i<4&&!option(argv[i]);i++) | 
|  | window[i] = atof(argv[i]); | 
|  | argv += i; | 
|  | argc -= i; | 
|  | break; | 
|  | case 'c': | 
|  | for(i=0;i<3&&argc>i&&!option(argv[i]);i++) | 
|  | center[i] = atof(argv[i]); | 
|  | argc -= i; | 
|  | argv += i; | 
|  | break; | 
|  | case 'p': | 
|  | for(i=0;i<3&&argc>i&&!option(argv[i]);i++) | 
|  | position[i] = atof(argv[i]); | 
|  | argc -= i; | 
|  | argv += i; | 
|  | if(i!=3||position[2]<=0) | 
|  | error("incomplete positioning"); | 
|  | break; | 
|  | case 'y': | 
|  | if(argc>0&&!option(argv[0])) { | 
|  | symbolfile = argv[0]; | 
|  | argc--; | 
|  | argv++; | 
|  | } | 
|  | break; | 
|  | case 'v': | 
|  | if(index[k].limb == 0) | 
|  | error("-v does not apply here"); | 
|  | vflag = -1; | 
|  | break; | 
|  | case 'x': | 
|  | xflag = 1; | 
|  | break; | 
|  | case 'C': | 
|  | if(argc && !option(*argv)) { | 
|  | currcolor = colorcode(*argv); | 
|  | argc--; | 
|  | argv++; | 
|  | } | 
|  | break; | 
|  | } | 
|  | } | 
|  | if(argc>0) | 
|  | error("error in arguments"); | 
|  | pathnames(); | 
|  | clamp(&limits[0],-90.); | 
|  | clamp(&limits[1],90.); | 
|  | clamp(&klimits[0],-90.); | 
|  | clamp(&klimits[1],90.); | 
|  | clamp(&window[0],-90.); | 
|  | clamp(&window[1],90.); | 
|  | radbds(limits,rlimits); | 
|  | limcase = limits[2]<-180.?0: | 
|  | limits[3]>180.?2: | 
|  | 1; | 
|  | if( | 
|  | window[0]>=window[1]|| | 
|  | window[2]>=window[3]|| | 
|  | window[0]>90.|| | 
|  | window[1]<-90.|| | 
|  | window[2]>180.|| | 
|  | window[3]<-180.) | 
|  | error("unreasonable window"); | 
|  | windlim(); | 
|  | radbds(window,rwindow); | 
|  | upright = orientation[0]==90? 1: orientation[0]==-90? -1: 0; | 
|  | if(index[k].spheroid && !upright) | 
|  | error("can't tilt the spheroid"); | 
|  | if(limits[2]>limits[3]) | 
|  | limits[3] += 360; | 
|  | if(!oriented) | 
|  | orientation[2] = (limits[2]+limits[3])/2; | 
|  | orient(orientation[0],orientation[1],orientation[2]); | 
|  | projection = (*index[k].prog)(params[0],params[1]); | 
|  | if(projection == 0) | 
|  | error("unreasonable projection parameters"); | 
|  | clipinit(); | 
|  | grid[0] = fabs(grid[0]); | 
|  | grid[1] = fabs(grid[1]); | 
|  | if(!kflag) | 
|  | for(i=0;i<4;i++) | 
|  | klimits[i] = limits[i]; | 
|  | if(klimits[2]>klimits[3]) | 
|  | klimits[3] += 360; | 
|  | lolat = limits[0]; | 
|  | hilat = limits[1]; | 
|  | lolon = limits[2]; | 
|  | hilon = limits[3]; | 
|  | if(lolon>=hilon||lolat>=hilat||lolat<-90.||hilat>90.) | 
|  | error("unreasonable limits"); | 
|  | wlim = kflag? klimits: window; | 
|  | dlat = fmin(hilat-lolat,wlim[1]-wlim[0])/16; | 
|  | dlon = fmin(hilon-lolon,wlim[3]-wlim[2])/32; | 
|  | dd = fmax(dlat,dlon); | 
|  | while(grid[2]>fmin(dlat,dlon)/2) | 
|  | grid[2] /= 2; | 
|  | realcut(); | 
|  | if(nvert<=0) { | 
|  | for(lat=klimits[0];lat<klimits[1]+dd-FUZZ;lat+=dd) { | 
|  | if(lat>klimits[1]) | 
|  | lat = klimits[1]; | 
|  | for(lon=klimits[2];lon<klimits[3]+dd-FUZZ;lon+=dd) { | 
|  | i = (kflag?posproj:normproj) | 
|  | (lat,lon+(lon<klimits[3]?FUZZ:-FUZZ), | 
|  | &x,&y); | 
|  | if(i*vflag <= 0) | 
|  | continue; | 
|  | if(x<xmin) xmin = x; | 
|  | if(x>xmax) xmax = x; | 
|  | if(y<ymin) ymin = y; | 
|  | if(y>ymax) ymax = y; | 
|  | } | 
|  | } | 
|  | } else { | 
|  | for(i=0; i<nvert; i++) { | 
|  | x = v[i].x; | 
|  | y = v[i].y; | 
|  | if(x<xmin) xmin = x; | 
|  | if(x>xmax) xmax = x; | 
|  | if(y<ymin) ymin = y; | 
|  | if(y>ymax) ymax = y; | 
|  | } | 
|  | } | 
|  | xrange = xmax - xmin; | 
|  | yrange = ymax - ymin; | 
|  | if(xrange<=0||yrange<=0) | 
|  | error("map seems to be empty"); | 
|  | scaling = 2;	/*plotting area from -1 to 1*/ | 
|  | if(position[2]!=0) { | 
|  | if(posproj(position[0]-.5,position[1],&xcent,&ycent)==0|| | 
|  | posproj(position[0]+.5,position[1],&x,&y)==0) | 
|  | error("unreasonable position"); | 
|  | scaling /= (position[2]*hypot(x-xcent,y-ycent)); | 
|  | if(posproj(position[0],position[1],&xcent,&ycent)==0) | 
|  | error("unreasonable position"); | 
|  | } else { | 
|  | scaling /= (xrange>yrange?xrange:yrange); | 
|  | xcent = (xmin+xmax)/2; | 
|  | ycent = (ymin+ymax)/2; | 
|  | } | 
|  | xoff = center[0]/scaling; | 
|  | yoff = center[1]/scaling; | 
|  | crot.l = center[2]*RAD; | 
|  | sincos(&crot); | 
|  | scaling *= HALFWIDTH*0.9; | 
|  | if(symbolfile) | 
|  | getsyms(symbolfile); | 
|  | if(!s2flag) { | 
|  | openpl(); | 
|  | erase(); | 
|  | } | 
|  | range(left,bottom,right,top); | 
|  | comment("grid",""); | 
|  | colorx(gridcolor); | 
|  | pen(DOTTED); | 
|  | if(grid[0]>0.) | 
|  | for(lat=ceil(lolat/grid[0])*grid[0]; | 
|  | lat<=hilat;lat+=grid[0]) | 
|  | dogrid(lat,lat,lolon,hilon); | 
|  | if(grid[1]>0.) | 
|  | for(lon=ceil(lolon/grid[1])*grid[1]; | 
|  | lon<=hilon;lon+=grid[1]) | 
|  | dogrid(lolat,hilat,lon,lon); | 
|  | comment("border",""); | 
|  | colorx(bordcolor); | 
|  | pen(SOLID); | 
|  | if(bflag) { | 
|  | dolimb(); | 
|  | dobounds(lolat,hilat,lolon,hilon,0); | 
|  | dobounds(window[0],window[1],window[2],window[3],1); | 
|  | } | 
|  | lolat = floor(limits[0]/10)*10; | 
|  | hilat = ceil(limits[1]/10)*10; | 
|  | lolon = floor(limits[2]/10)*10; | 
|  | hilon = ceil(limits[3]/10)*10; | 
|  | if(lolon>hilon) | 
|  | hilon += 360.; | 
|  | /*do tracks first so as not to lose the standard input*/ | 
|  | for(i=0;i<ntrack;i++) { | 
|  | longlines = LONGLINES; | 
|  | satellite(&track[i]); | 
|  | longlines = shortlines; | 
|  | } | 
|  | for(i=0;i<nfile;i++) { | 
|  | comment("mapfile",file[i].name); | 
|  | colorx(file[i].color); | 
|  | pen(file[i].style); | 
|  | getdata(file[i].name); | 
|  | } | 
|  | move(right,bottom); | 
|  | if(!s1flag) | 
|  | closepl(); | 
|  | return 0; | 
|  | } | 
|  |  | 
|  | /* Out of perverseness (really to recover from a dubious, | 
|  | but documented, convention) the returns from projection | 
|  | functions (-1 unplottable, 0 wrong sheet, 1 good) are | 
|  | recoded into -1 wrong sheet, 0 unplottable, 1 good. */ | 
|  |  | 
|  | int | 
|  | fixproj(struct place *g, double *x, double *y) | 
|  | { | 
|  | int i = (*projection)(g,x,y); | 
|  | return i<0? 0: i==0? -1: 1; | 
|  | } | 
|  |  | 
|  | int | 
|  | normproj(double lat, double lon, double *x, double *y) | 
|  | { | 
|  | int i; | 
|  | struct place geog; | 
|  | latlon(lat,lon,&geog); | 
|  | /* | 
|  | printp(&geog); | 
|  | */ | 
|  | normalize(&geog); | 
|  | if(!inwindow(&geog)) | 
|  | return(-1); | 
|  | i = fixproj(&geog,x,y); | 
|  | if(rflag) | 
|  | *x = -*x; | 
|  | /* | 
|  | printp(&geog); | 
|  | fprintf(stderr,"%d %.3f %.3f\n",i,*x,*y); | 
|  | */ | 
|  | return(i); | 
|  | } | 
|  |  | 
|  | int | 
|  | posproj(double lat, double lon, double *x, double *y) | 
|  | { | 
|  | int i; | 
|  | struct place geog; | 
|  | latlon(lat,lon,&geog); | 
|  | normalize(&geog); | 
|  | i = fixproj(&geog,x,y); | 
|  | if(rflag) | 
|  | *x = -*x; | 
|  | return(i); | 
|  | } | 
|  |  | 
|  | int | 
|  | inwindow(struct place *geog) | 
|  | { | 
|  | if(geog->nlat.l<rwindow[0]-FUZZ|| | 
|  | geog->nlat.l>rwindow[1]+FUZZ|| | 
|  | geog->wlon.l<rwindow[2]-FUZZ|| | 
|  | geog->wlon.l>rwindow[3]+FUZZ) | 
|  | return(0); | 
|  | else return(1); | 
|  | } | 
|  |  | 
|  | int | 
|  | inlimits(struct place *g) | 
|  | { | 
|  | if(rlimits[0]-FUZZ>g->nlat.l|| | 
|  | rlimits[1]+FUZZ<g->nlat.l) | 
|  | return(0); | 
|  | switch(limcase) { | 
|  | case 0: | 
|  | if(rlimits[2]+TWOPI-FUZZ>g->wlon.l&& | 
|  | rlimits[3]+FUZZ<g->wlon.l) | 
|  | return(0); | 
|  | break; | 
|  | case 1: | 
|  | if(rlimits[2]-FUZZ>g->wlon.l|| | 
|  | rlimits[3]+FUZZ<g->wlon.l) | 
|  | return(0); | 
|  | break; | 
|  | case 2: | 
|  | if(rlimits[2]>g->wlon.l&& | 
|  | rlimits[3]-TWOPI+FUZZ<g->wlon.l) | 
|  | return(0); | 
|  | break; | 
|  | } | 
|  | return(1); | 
|  | } | 
|  |  | 
|  |  | 
|  | long patch[18][36]; | 
|  |  | 
|  | void | 
|  | getdata(char *mapfile) | 
|  | { | 
|  | char *indexfile; | 
|  | int kx,ky,c; | 
|  | int k; | 
|  | long b; | 
|  | long *p; | 
|  | int ip, jp; | 
|  | int n; | 
|  | struct place g; | 
|  | int i, j; | 
|  | double lat, lon; | 
|  | int conn; | 
|  | FILE *ifile, *xfile; | 
|  |  | 
|  | indexfile = mapindex(mapfile); | 
|  | xfile = fopen(indexfile,"r"); | 
|  | if(xfile==NULL) | 
|  | filerror("can't find map index", indexfile); | 
|  | free(indexfile); | 
|  | for(i=0,p=patch[0];i<18*36;i++,p++) | 
|  | *p = 1; | 
|  | while(!feof(xfile) && fscanf(xfile,"%d%d%ld",&i,&j,&b)==3) | 
|  | patch[i+9][j+18] = b; | 
|  | fclose(xfile); | 
|  | ifile = fopen(mapfile,"r"); | 
|  | if(ifile==NULL) | 
|  | filerror("can't find map data", mapfile); | 
|  | for(lat=lolat;lat<hilat;lat+=10.) | 
|  | for(lon=lolon;lon<hilon;lon+=10.) { | 
|  | if(!seeable(lat,lon)) | 
|  | continue; | 
|  | i = pnorm(lat); | 
|  | j = pnorm(lon); | 
|  | if((b=patch[i+9][j+18])&1) | 
|  | continue; | 
|  | fseek(ifile,b,0); | 
|  | while((ip=getc(ifile))>=0&&(jp=getc(ifile))>=0){ | 
|  | if(ip!=(i&0377)||jp!=(j&0377)) | 
|  | break; | 
|  | n = getshort(ifile); | 
|  | conn = 0; | 
|  | if(n > 0) {	/* absolute coordinates */ | 
|  | kx = ky = 0;	/* set */ | 
|  | for(k=0;k<n;k++){ | 
|  | kx = SCALERATIO*getshort(ifile); | 
|  | ky = SCALERATIO*getshort(ifile); | 
|  | if (((k%delta) != 0) && (k != (n-1))) | 
|  | continue; | 
|  | conv(kx,&g.nlat); | 
|  | conv(ky,&g.wlon); | 
|  | conn = plotpt(&g,conn); | 
|  | } | 
|  | } else {	/* differential, scaled by SCALERATI0 */ | 
|  | n = -n; | 
|  | kx = SCALERATIO*getshort(ifile); | 
|  | ky = SCALERATIO*getshort(ifile); | 
|  | for(k=0; k<n; k++) { | 
|  | c = getc(ifile); | 
|  | if(c&0200) c|= ~0177; | 
|  | kx += c; | 
|  | c = getc(ifile); | 
|  | if(c&0200) c|= ~0177; | 
|  | ky += c; | 
|  | if(k%delta!=0&&k!=n-1) | 
|  | continue; | 
|  | conv(kx,&g.nlat); | 
|  | conv(ky,&g.wlon); | 
|  | conn = plotpt(&g,conn); | 
|  | } | 
|  | } | 
|  | if(k==1) { | 
|  | conv(kx,&g.nlat); | 
|  | conv(ky,&g.wlon); | 
|  | plotpt(&g,conn); | 
|  | } | 
|  | } | 
|  | } | 
|  | fclose(ifile); | 
|  | } | 
|  |  | 
|  | int | 
|  | seeable(double lat0, double lon0) | 
|  | { | 
|  | double x, y; | 
|  | double lat, lon; | 
|  | for(lat=lat0;lat<=lat0+10;lat+=2*grid[2]) | 
|  | for(lon=lon0;lon<=lon0+10;lon+=2*grid[2]) | 
|  | if(normproj(lat,lon,&x,&y)*vflag>0) | 
|  | return(1); | 
|  | return(0); | 
|  | } | 
|  |  | 
|  | void | 
|  | satellite(struct file *t) | 
|  | { | 
|  | char sym[50]; | 
|  | char lbl[50]; | 
|  | double scale; | 
|  | int conn; | 
|  | double lat,lon; | 
|  | struct place place; | 
|  | static FILE *ifile; | 
|  |  | 
|  | if(ifile == nil) | 
|  | ifile = stdin; | 
|  | if(t->name[0]!='-'||t->name[1]!=0) { | 
|  | fclose(ifile); | 
|  | if((ifile=fopen(t->name,"r"))==NULL) | 
|  | filerror("can't find track", t->name); | 
|  | } | 
|  | comment("track",t->name); | 
|  | colorx(t->color); | 
|  | pen(t->style); | 
|  | for(;;) { | 
|  | conn = 0; | 
|  | while(!feof(ifile) && fscanf(ifile,"%lf%lf",&lat,&lon)==2){ | 
|  | latlon(lat,lon,&place); | 
|  | if(fscanf(ifile,"%1s",lbl) == 1) { | 
|  | if(strchr("+-.0123456789",*lbl)==0) | 
|  | break; | 
|  | ungetc(*lbl,ifile); | 
|  | } | 
|  | conn = plotpt(&place,conn); | 
|  | } | 
|  | if(feof(ifile)) | 
|  | return; | 
|  | fscanf(ifile,"%[^\n]",lbl+1); | 
|  | switch(*lbl) { | 
|  | case '"': | 
|  | if(plotpt(&place,conn)) | 
|  | text(lbl+1); | 
|  | break; | 
|  | case ':': | 
|  | case '!': | 
|  | if(sscanf(lbl+1,"%s %lf",sym,&scale) <= 1) | 
|  | scale = 1; | 
|  | if(plotpt(&place,conn?conn:-1)) { | 
|  | int r = *lbl=='!'?0:rflag?-1:1; | 
|  | pen(SOLID); | 
|  | if(putsym(&place,sym,scale,r) == 0) | 
|  | text(lbl); | 
|  | pen(t->style); | 
|  | } | 
|  | break; | 
|  | default: | 
|  | if(plotpt(&place,conn)) | 
|  | text(lbl); | 
|  | break; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | pnorm(double x) | 
|  | { | 
|  | int i; | 
|  | i = x/10.; | 
|  | i %= 36; | 
|  | if(i>=18) return(i-36); | 
|  | if(i<-18) return(i+36); | 
|  | return(i); | 
|  | } | 
|  |  | 
|  | void | 
|  | error(char *s) | 
|  | { | 
|  | fprintf(stderr,"map: \r\n%s\n",s); | 
|  | exits("error"); | 
|  | } | 
|  |  | 
|  | void | 
|  | filerror(char *s, char *f) | 
|  | { | 
|  | fprintf(stderr,"\r\n%s %s\n",s,f); | 
|  | exits("error"); | 
|  | } | 
|  |  | 
|  | char * | 
|  | mapindex(char *s) | 
|  | { | 
|  | char *t = malloc(strlen(s)+3); | 
|  | strcpy(t,s); | 
|  | strcat(t,".x"); | 
|  | return t; | 
|  | } | 
|  |  | 
|  | #define NOPT 32767 | 
|  | static int ox = NOPT; | 
|  | static int oy = NOPT; | 
|  |  | 
|  | int | 
|  | cpoint(int xi, int yi, int conn) | 
|  | { | 
|  | int dx = abs(ox-xi); | 
|  | int dy = abs(oy-yi); | 
|  | if(!xflag && (xi<left||xi>=right || yi<bottom||yi>=top)) { | 
|  | ox = oy = NOPT; | 
|  | return 0; | 
|  | } | 
|  | if(conn == -1)		/* isolated plotting symbol */ | 
|  | {} | 
|  | else if(!conn) | 
|  | point(xi,yi); | 
|  | else { | 
|  | if(dx+dy>longlines) { | 
|  | ox = oy = NOPT;	/* don't leap across cuts */ | 
|  | return 0; | 
|  | } | 
|  | if(dx || dy) | 
|  | vec(xi,yi); | 
|  | } | 
|  | ox = xi, oy = yi; | 
|  | return dx+dy<=2? 2: 1;	/* 2=very near; see dogrid */ | 
|  | } | 
|  |  | 
|  |  | 
|  | struct place oldg; | 
|  |  | 
|  | int | 
|  | plotpt(struct place *g, int conn) | 
|  | { | 
|  | int kx,ky; | 
|  | int ret; | 
|  | double cutlon; | 
|  | if(!inlimits(g)) { | 
|  | return(0); | 
|  | } | 
|  | normalize(g); | 
|  | if(!inwindow(g)) { | 
|  | return(0); | 
|  | } | 
|  | switch((*cut)(g,&oldg,&cutlon)) { | 
|  | case 2: | 
|  | if(conn) { | 
|  | ret = duple(g,cutlon)|duple(g,cutlon); | 
|  | oldg = *g; | 
|  | return(ret); | 
|  | } | 
|  | case 0: | 
|  | conn = 0; | 
|  | default:	/* prevent diags about bad return value */ | 
|  | case 1: | 
|  | oldg = *g; | 
|  | ret = doproj(g,&kx,&ky); | 
|  | if(ret==0 || !onlimb && ret*vflag<=0) | 
|  | return(0); | 
|  | ret = cpoint(kx,ky,conn); | 
|  | return ret; | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | doproj(struct place *g, int *kx, int *ky) | 
|  | { | 
|  | int i; | 
|  | double x,y,x1,y1; | 
|  | /*fprintf(stderr,"dopr1 %f %f \n",g->nlat.l,g->wlon.l);*/ | 
|  | i = fixproj(g,&x,&y); | 
|  | if(i == 0) | 
|  | return(0); | 
|  | if(rflag) | 
|  | x = -x; | 
|  | /*fprintf(stderr,"dopr2 %f %f\n",x,y);*/ | 
|  | if(!inpoly(x,y)) { | 
|  | return 0; | 
|  | } | 
|  | x1 = x - xcent; | 
|  | y1 = y - ycent; | 
|  | x = (x1*crot.c - y1*crot.s + xoff)*scaling; | 
|  | y = (x1*crot.s + y1*crot.c + yoff)*scaling; | 
|  | *kx = x + (x>0?.5:-.5); | 
|  | *ky = y + (y>0?.5:-.5); | 
|  | return(i); | 
|  | } | 
|  |  | 
|  | int | 
|  | duple(struct place *g, double cutlon) | 
|  | { | 
|  | int kx,ky; | 
|  | int okx,oky; | 
|  | struct place ig; | 
|  | revlon(g,cutlon); | 
|  | revlon(&oldg,cutlon); | 
|  | ig = *g; | 
|  | invert(&ig); | 
|  | if(!inlimits(&ig)) | 
|  | return(0); | 
|  | if(doproj(g,&kx,&ky)*vflag<=0 || | 
|  | doproj(&oldg,&okx,&oky)*vflag<=0) | 
|  | return(0); | 
|  | cpoint(okx,oky,0); | 
|  | cpoint(kx,ky,1); | 
|  | return(1); | 
|  | } | 
|  |  | 
|  | void | 
|  | revlon(struct place *g, double cutlon) | 
|  | { | 
|  | g->wlon.l = reduce(cutlon-reduce(g->wlon.l-cutlon)); | 
|  | sincos(&g->wlon); | 
|  | } | 
|  |  | 
|  |  | 
|  | /*	recognize problems of cuts | 
|  | *	move a point across cut to side of its predecessor | 
|  | *	if its very close to the cut | 
|  | *	return(0) if cut interrupts the line | 
|  | *	return(1) if line is to be drawn normally | 
|  | *	return(2) if line is so close to cut as to | 
|  | *	be properly drawn on both sheets | 
|  | */ | 
|  |  | 
|  | int | 
|  | picut(struct place *g, struct place *og, double *cutlon) | 
|  | { | 
|  | *cutlon = PI; | 
|  | return(ckcut(g,og,PI)); | 
|  | } | 
|  |  | 
|  | int | 
|  | nocut(struct place *g, struct place *og, double *cutlon) | 
|  | { | 
|  | USED(g); | 
|  | USED(og); | 
|  | USED(cutlon); | 
|  | /* | 
|  | #pragma	ref g | 
|  | #pragma	ref og | 
|  | #pragma	ref cutlon | 
|  | */ | 
|  | return(1); | 
|  | } | 
|  |  | 
|  | int | 
|  | ckcut(struct place *g1, struct place *g2, double lon) | 
|  | { | 
|  | double d1, d2; | 
|  | double f1, f2; | 
|  | int kx,ky; | 
|  | d1 = reduce(g1->wlon.l -lon); | 
|  | d2 = reduce(g2->wlon.l -lon); | 
|  | if((f1=fabs(d1))<FUZZ) | 
|  | d1 = diddle(g1,lon,d2); | 
|  | if((f2=fabs(d2))<FUZZ) { | 
|  | d2 = diddle(g2,lon,d1); | 
|  | if(doproj(g2,&kx,&ky)*vflag>0) | 
|  | cpoint(kx,ky,0); | 
|  | } | 
|  | if(f1<FUZZ&&f2<FUZZ) | 
|  | return(2); | 
|  | if(f1>PI*TWO_THRD||f2>PI*TWO_THRD) | 
|  | return(1); | 
|  | return(d1*d2>=0); | 
|  | } | 
|  |  | 
|  | double | 
|  | diddle(struct place *g, double lon, double d) | 
|  | { | 
|  | double d1; | 
|  | d1 = FUZZ/2; | 
|  | if(d<0) | 
|  | d1 = -d1; | 
|  | g->wlon.l = reduce(lon+d1); | 
|  | sincos(&g->wlon); | 
|  | return(d1); | 
|  | } | 
|  |  | 
|  | double | 
|  | reduce(double lon) | 
|  | { | 
|  | if(lon>PI) | 
|  | lon -= 2*PI; | 
|  | else if(lon<-PI) | 
|  | lon += 2*PI; | 
|  | return(lon); | 
|  | } | 
|  |  | 
|  |  | 
|  | double tetrapt = 35.26438968;	/* atan(1/sqrt(2)) */ | 
|  |  | 
|  | void | 
|  | dogrid(double lat0, double lat1, double lon0, double lon1) | 
|  | { | 
|  | double slat,slon,tlat,tlon; | 
|  | register int conn, oconn; | 
|  | slat = tlat = slon = tlon = 0; | 
|  | if(lat1>lat0) | 
|  | slat = tlat = fmin(grid[2],dlat); | 
|  | else | 
|  | slon = tlon = fmin(grid[2],dlon);; | 
|  | conn = oconn = 0; | 
|  | while(lat0<=lat1&&lon0<=lon1) { | 
|  | conn = gridpt(lat0,lon0,conn); | 
|  | if(projection==Xguyou&&slat>0) { | 
|  | if(lat0<-45&&lat0+slat>-45) | 
|  | conn = gridpt(-45.,lon0,conn); | 
|  | else if(lat0<45&&lat0+slat>45) | 
|  | conn = gridpt(45.,lon0,conn); | 
|  | } else if(projection==Xtetra&&slat>0) { | 
|  | if(lat0<-tetrapt&&lat0+slat>-tetrapt) { | 
|  | gridpt(-tetrapt-.001,lon0,conn); | 
|  | conn = gridpt(-tetrapt+.001,lon0,0); | 
|  | } | 
|  | else if(lat0<tetrapt&&lat0+slat>tetrapt) { | 
|  | gridpt(tetrapt-.001,lon0,conn); | 
|  | conn = gridpt(tetrapt+.001,lon0,0); | 
|  | } | 
|  | } | 
|  | if(conn==0 && oconn!=0) { | 
|  | if(slat+slon>.05) { | 
|  | lat0 -= slat;	/* steps too big */ | 
|  | lon0 -= slon;	/* or near bdry */ | 
|  | slat /= 2; | 
|  | slon /= 2; | 
|  | conn = oconn = gridpt(lat0,lon0,conn); | 
|  | } else | 
|  | oconn = 0; | 
|  | } else { | 
|  | if(conn==2) { | 
|  | slat = tlat; | 
|  | slon = tlon; | 
|  | conn = 1; | 
|  | } | 
|  | oconn = conn; | 
|  | } | 
|  | lat0 += slat; | 
|  | lon0 += slon; | 
|  | } | 
|  | gridpt(lat1,lon1,conn); | 
|  | } | 
|  |  | 
|  | static int gridinv;		/* nonzero when doing window bounds */ | 
|  |  | 
|  | int | 
|  | gridpt(double lat, double lon, int conn) | 
|  | { | 
|  | struct place g; | 
|  | /*fprintf(stderr,"%f %f\n",lat,lon);*/ | 
|  | latlon(lat,lon,&g); | 
|  | if(gridinv) | 
|  | invert(&g); | 
|  | return(plotpt(&g,conn)); | 
|  | } | 
|  |  | 
|  | /* win=0 ordinary grid lines, win=1 window lines */ | 
|  |  | 
|  | void | 
|  | dobounds(double lolat, double hilat, double lolon, double hilon, int win) | 
|  | { | 
|  | gridinv = win; | 
|  | if(lolat>-90 || win && (poles&1)!=0) | 
|  | dogrid(lolat+FUZZ,lolat+FUZZ,lolon,hilon); | 
|  | if(hilat<90 || win && (poles&2)!=0) | 
|  | dogrid(hilat-FUZZ,hilat-FUZZ,lolon,hilon); | 
|  | if(hilon-lolon<360 || win && cut==picut) { | 
|  | dogrid(lolat,hilat,lolon+FUZZ,lolon+FUZZ); | 
|  | dogrid(lolat,hilat,hilon-FUZZ,hilon-FUZZ); | 
|  | } | 
|  | gridinv = 0; | 
|  | } | 
|  |  | 
|  | static void | 
|  | dolimb(void) | 
|  | { | 
|  | double lat, lon; | 
|  | double res = fmin(dlat, dlon)/4; | 
|  | int conn = 0; | 
|  | int newconn; | 
|  | if(limb == 0) | 
|  | return; | 
|  | onlimb = gridinv = 1; | 
|  | for(;;) { | 
|  | newconn = (*limb)(&lat, &lon, res); | 
|  | if(newconn == -1) | 
|  | break; | 
|  | conn = gridpt(lat, lon, conn*newconn); | 
|  | } | 
|  | onlimb = gridinv = 0; | 
|  | } | 
|  |  | 
|  |  | 
|  | void | 
|  | radbds(double *w, double *rw) | 
|  | { | 
|  | int i; | 
|  | for(i=0;i<4;i++) | 
|  | rw[i] = w[i]*RAD; | 
|  | rw[0] -= FUZZ; | 
|  | rw[1] += FUZZ; | 
|  | rw[2] -= FUZZ; | 
|  | rw[3] += FUZZ; | 
|  | } | 
|  |  | 
|  | void | 
|  | windlim(void) | 
|  | { | 
|  | double center = orientation[0]; | 
|  | double colat; | 
|  | if(center>90) | 
|  | center = 180 - center; | 
|  | if(center<-90) | 
|  | center = -180 - center; | 
|  | if(fabs(center)>90) | 
|  | error("unreasonable orientation"); | 
|  | colat = 90 - window[0]; | 
|  | if(center-colat>limits[0]) | 
|  | limits[0] = center - colat; | 
|  | if(center+colat<limits[1]) | 
|  | limits[1] = center + colat; | 
|  | } | 
|  |  | 
|  |  | 
|  | short | 
|  | getshort(FILE *f) | 
|  | { | 
|  | int c, r; | 
|  | c = getc(f); | 
|  | r = (c | getc(f)<<8); | 
|  | if (r&0x8000) | 
|  | r |= ~0xFFFF;	/* in case short > 16 bits */ | 
|  | return r; | 
|  | } | 
|  |  | 
|  | double | 
|  | fmin(double x, double y) | 
|  | { | 
|  | return(x<y?x:y); | 
|  | } | 
|  |  | 
|  | double | 
|  | fmax(double x, double y) | 
|  | { | 
|  | return(x>y?x:y); | 
|  | } | 
|  |  | 
|  | void | 
|  | clamp(double *px, double v) | 
|  | { | 
|  | *px = (v<0?fmax:fmin)(*px,v); | 
|  | } | 
|  |  | 
|  | void | 
|  | pathnames(void) | 
|  | { | 
|  | int i; | 
|  | char *t, *indexfile, *name; | 
|  | FILE *f, *fx; | 
|  | for(i=0; i<nfile; i++) { | 
|  | name = file[i].name; | 
|  | if(*name=='/') | 
|  | continue; | 
|  | indexfile = mapindex(name); | 
|  | /* ansi equiv of unix access() call */ | 
|  | f = fopen(name, "r"); | 
|  | fx = fopen(indexfile, "r"); | 
|  | if(f) fclose(f); | 
|  | if(fx) fclose(fx); | 
|  | free(indexfile); | 
|  | if(f && fx) | 
|  | continue; | 
|  | t = malloc(strlen(name)+strlen(mapdir)+2); | 
|  | strcpy(t,mapdir); | 
|  | strcat(t,"/"); | 
|  | strcat(t,name); | 
|  | file[i].name = t; | 
|  | } | 
|  | } | 
|  |  | 
|  | void | 
|  | clipinit(void) | 
|  | { | 
|  | int i; | 
|  | double s,t; | 
|  | if(nvert<=0) | 
|  | return; | 
|  | for(i=0; i<nvert; i++) {	/*convert latlon to xy*/ | 
|  | if(normproj(v[i].x,v[i].y,&v[i].x,&v[i].y)==0) | 
|  | error("invisible clipping vertex"); | 
|  | } | 
|  | if(nvert==2) {			/*rectangle with diag specified*/ | 
|  | nvert = 4; | 
|  | v[2] = v[1]; | 
|  | v[1].x=v[0].x, v[1].y=v[2].y, v[3].x=v[2].x, v[3].y=v[0].y; | 
|  | } | 
|  | v[nvert] = v[0]; | 
|  | v[nvert+1] = v[1]; | 
|  | s = 0; | 
|  | for(i=1; i<=nvert; i++) {	/*test for convexity*/ | 
|  | t = (v[i-1].x-v[i].x)*(v[i+1].y-v[i].y) - | 
|  | (v[i-1].y-v[i].y)*(v[i+1].x-v[i].x); | 
|  | if(t<-FUZZ && s>=0) s = 1; | 
|  | if(t>FUZZ && s<=0) s = -1; | 
|  | if(-FUZZ<=t&&t<=FUZZ || t*s>0) { | 
|  | s = 0; | 
|  | break; | 
|  | } | 
|  | } | 
|  | if(s==0) | 
|  | error("improper clipping polygon"); | 
|  | for(i=0; i<nvert; i++) {	/*edge equation ax+by=c*/ | 
|  | e[i].a = s*(v[i+1].y - v[i].y); | 
|  | e[i].b = s*(v[i].x - v[i+1].x); | 
|  | e[i].c = s*(v[i].x*v[i+1].y - v[i].y*v[i+1].x); | 
|  | } | 
|  | } | 
|  |  | 
|  | int | 
|  | inpoly(double x, double y) | 
|  | { | 
|  | int i; | 
|  | for(i=0; i<nvert; i++) { | 
|  | register struct edge *ei = &e[i]; | 
|  | double val = x*ei->a + y*ei->b - ei->c; | 
|  | if(val>10*FUZZ) | 
|  | return(0); | 
|  | } | 
|  | return 1; | 
|  | } | 
|  |  | 
|  | void | 
|  | realcut(void) | 
|  | { | 
|  | struct place g; | 
|  | double lat; | 
|  |  | 
|  | if(cut != picut)	/* punt on unusual cuts */ | 
|  | return; | 
|  | for(lat=window[0]; lat<=window[1]; lat+=grid[2]) { | 
|  | g.wlon.l = PI; | 
|  | sincos(&g.wlon); | 
|  | g.nlat.l = lat*RAD; | 
|  | sincos(&g.nlat); | 
|  | if(!inwindow(&g)) { | 
|  | break; | 
|  | } | 
|  | invert(&g); | 
|  | if(inlimits(&g)) { | 
|  | return; | 
|  | } | 
|  | } | 
|  | longlines = shortlines = LONGLINES; | 
|  | cut = nocut;		/* not necessary; small eff. gain */ | 
|  | } |