|
|
researchv8 Dan Cross
#include "map.h"
#include <stdio.h>
#include <iplot.h>
#define NTRACK 10
#define NFILE 30
#define HALFWIDTH 8192
#define SCALERATIO 10
#define RESOL 2.
#define TWO_THRD 0.66666666666666667
static int (*projection)();
double atof(), floor(), ceil(), fmin(), fmax();
extern char *getenv(), *malloc();
float reduce();
short getshort();
#define map(x) int (*x())()
static char *mapdir = "/usr/dict";
static char *file[NFILE+1] = {
"world",
0
};
map(azequidistant);
map(mercator);
map(sp_mercator);
map(cylindrical);
map(rectangular);
map(orthographic);
map(sinusoidal);
map(mollweide);
map(aitoff);
map(azequalarea);
map(stereographic);
map(laue);
map(gilbert);
map(gnomonic);
map(perspective);
map(cylequalarea);
map(conic);
map(polyconic);
map(bonne);
map(lambert);
map(albers);
map(sp_albers);
map(mecca);
map(homing);
map(guyou);
map(square);
map(tetra);
map(hex);
map(elliptic);
map(bicentric);
int Xguyou();
int Xsquare();
int Xtetra();
int nocut();
int picut();
int guycut();
int tetracut();
int hexcut();
static struct {
char *name;
int (*(*prog)())();
int npar;
int (*cut)();
int poles;/*1 S pole is a line, 2 N pole is, 3 both*/
int spheroid; /* poles must be at 90 deg */
} index[] = {
{"azequidistant", azequidistant, 0, nocut, 1, 0},
{"mercator", mercator, 0, picut, 0, 0},
{"sp_mercator", sp_mercator, 0, picut, 0, 1},
{"cylindrical", cylindrical, 0, picut, 0, 0},
{"rectangular", rectangular, 0, picut, 3, 0},
{"orthographic", orthographic, 0, nocut, 0, 0},
{"sinusoidal", sinusoidal, 0, picut, 0, 0},
{"mollweide", mollweide, 0, picut, 0, 0},
{"aitoff", aitoff, 0, picut, 0, 0},
{"azequalarea", azequalarea, 0, nocut, 1, 0},
{"stereographic", stereographic, 0, nocut, 0, 0},
{"laue", laue, 0, nocut, 0, 0},
{"gilbert",gilbert,0,picut,0, 0},
{"gnomonic", gnomonic, 0, nocut, 0, 0},
{"perspective", perspective, 1, nocut, 0, 0},
{"cylequalarea", cylequalarea, 1, picut, 3, 0},
{"conic", conic, 1, picut, 0, 0},
{"polyconic", polyconic, 0, picut, 0, 0},
{"bonne", bonne, 1, picut, 0, 0},
{"lambert", lambert, 2, picut, 0, 0},
{"albers", albers, 2, picut, 3, 0},
{"sp_albers", sp_albers, 2, picut, 3, 1},
{"mecca", mecca, 1, picut, 0, 0},
{"homing", homing, 1, picut, 0, 0},
{"guyou", guyou, 0, guycut, 0, 0},
{"square", square, 0, picut, 0, 0},
{"tetra", tetra, 0, tetracut, 0, 0},
{"hex", hex, 0, hexcut, 0, 0},
{"elliptic", elliptic, 1, nocut, 0, 0},
{"bicentric", bicentric, 1, nocut, 0, 0},
0
};
static int (*cut)();
static int poles;
static float orientation[3] = { 90., 0., 0. };
static oriented;
static int delta = 1;
static float limits[4] = {
-90., 90., -180., 180.
};
static int limcase;
static float rlimits[4];
static float lolat, hilat, lolon, hilon;
static float window[4] = {
-90., 90., -180., 180.
};
static float rwindow[4];
static float params[2];
static float xmin = 100.;
static float xmax = -100.;
static float ymin = 100.;
static float ymax = -100.;
static float xcent, ycent;
float xrange, yrange;
static int left = -HALFWIDTH;
static int right = HALFWIDTH;
static int bottom = -HALFWIDTH;
static int top = HALFWIDTH;
static int bflag = 1;
static int sflag = 0;
static int rflag = 0;
static int mflag = 0;
static float position[3];
static float center[2] = {0., 0.};
static float grid[3] = { 10., 10., RESOL };
static float dlat, dlon;
static float scaling;
static struct track {
int tracktyp;
char *tracknam;
} track[NTRACK];
static int ntrack;
main(argc,argv)
char **argv;
{
int i,k;
char *s, *t;
float x, y, lat, lon;
float dd;
if(sizeof(short)!=2)
abort(); /* getshort() won't work */
s = getenv("MAP");
if(s)
file[0] = 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\n",index[i].name);
exit(1);
found:
argv += 2;
argc -= 2;
cut = index[k].cut;
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);
exit(1);
}
params[i] = atof(argv[i]);
}
argv += i;
argc -= i;
while(argc>0&&option(argv[0])) {
argc--;
argv++;
switch(argv[-1][1]) {
case 'm':
i = 0;
if(!mflag) while(file[i]!=0)
i++;
for(i=0;i<NFILE&&argc>i&&!option(argv[i]);i++)
file[i] = argv[i];
file[i] = 0;
mflag++;
argc -= i;
argv += i;
break;
case 'b':
bflag = 0;
break;
case 'g':
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':
case 'u':
for(i=0;ntrack<NTRACK&&argc>i&&!option(argv[i]);i++) {
track[ntrack].tracktyp = argv[-1][1];
track[ntrack++].tracknam = argv[i];
}
argc -= i;
argv +=i;
break;
case 'r':
rflag++;
break;
case 's':
sflag++;
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':
for(i=0;i<argc&&i<4&&!option(argv[i]);i++)
limits[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':
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<2&&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;
}
}
if(argc>0)
error("error in arguments");
pathnames();
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");
radbds(window,rwindow);
if(index[k].spheroid && fabs(orientation[0])!=90)
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");
grid[0] = fabs(grid[0]);
grid[1] = fabs(grid[1]);
lolat = limits[0];
hilat = limits[1];
lolon = limits[2];
hilon = limits[3];
if(lolon>=hilon||lolat>=hilat||lolat<-90.||hilat>90.)
error("unreasonable limits");
dlat = fmin(hilat-lolat,window[1]-window[0])/16;
dlon = fmin(hilon-lolon,window[3]-window[2])/32;
dd = fmax(dlat,dlon);
while(grid[2]>fmin(dlat,dlon)/2)
grid[2] /= 2;
for(lat=lolat;lat<hilat+dd-FUZZ;lat+=dd) {
if(lat>hilat)
lat = hilat;
for(lon=lolon;lon<hilon+dd-FUZZ;lon+=dd) {
if(lon>hilon)
lon = hilon;
if(normproj(lat,lon,&x,&y)<=0)
continue;
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*HALFWIDTH)*0.9;
if(position[2]!=0) {
if(normproj(position[0]-.5,position[1],&xcent,&ycent)<=0||
normproj(position[0]+.5,position[1],&x,&y)<=0)
error("unreasonable position");
scaling /= (position[2]*hypot(x-xcent,y-ycent));
if(normproj(position[0],position[1],&xcent,&ycent)<=0)
error("unreasonable position");
} else {
scaling /= (xrange>yrange?xrange:yrange);
xcent = (xmin+xmax)/2;
ycent = (ymin+ymax)/2;
}
xcent -= center[0]/2;
ycent -= center[1]/2;
openpl();
range(left,bottom,right,top);
if(!sflag)
erase();
pen("dotted");
if(grid[0]>0.)
for(lat=ceil(lolat/grid[0])*grid[0];
lat<=hilat;lat+=grid[0])
dogrid(lat,lat,lolon,hilon,0);
if(grid[1]>0.)
for(lon=ceil(lolon/grid[1])*grid[1];
lon<=hilon;lon+=grid[1])
dogrid(lolat,hilat,lon,lon,0);
pen("solid");
if(bflag) {
if(lolat>-90)
dogrid(lolat+FUZZ,lolat+FUZZ,lolon,hilon,0);
if(hilat<90)
dogrid(hilat-FUZZ,hilat-FUZZ,lolon,hilon,0);
if(hilon-lolon<360) {
dogrid(lolat,hilat,lolon+FUZZ,lolon+FUZZ,0);
dogrid(lolat,hilat,hilon-FUZZ,hilon-FUZZ,0);
}
if(poles&1)
dogrid(window[0]+FUZZ,window[0]+FUZZ,window[2],window[3],1);
if(poles&2)
dogrid(window[1]-FUZZ,window[1]-FUZZ,window[2],window[3],1);
if(window[3]-window[2]<360) {
dogrid(window[0],window[1],window[2]+FUZZ,window[2]+FUZZ,1);
dogrid(window[0],window[1],window[3]-FUZZ,window[3]-FUZZ,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++)
satellite(&track[i]);
pen("solid");
for(i=0;file[i];i++)
getdata(file[i]);
move(right,bottom);
closepl();
return(0);
}
normproj(lat,lon,x,y)
float lat,lon;
float *x, *y;
{
int i;
struct place geog;
latlon(lat,lon,&geog);
/*
printp(&geog);
*/
normalize(&geog);
if(!inwindow(&geog))
return(-1);
i = (*projection)(&geog,x,y);
if(rflag)
*x = -*x;
/*
printp(&geog);
fprintf(stderr,"%d %.3f %.3f\n",i,*x,*y);
*/
return(i);
}
inwindow(geog)
struct place *geog;
{
if(geog->nlat.l<rwindow[0]||
geog->nlat.l>rwindow[1]||
geog->wlon.l<rwindow[2]||
geog->wlon.l>rwindow[3])
return(0);
else return(1);
}
inlimits(g)
struct place *g;
{
if(rlimits[0]>g->nlat.l||
rlimits[1]<g->nlat.l)
return(0);
switch(limcase) {
case 0:
if(rlimits[2]+TWOPI>g->wlon.l&&
rlimits[3]<g->wlon.l)
return(0);
break;
case 1:
if(rlimits[2]>g->wlon.l||
rlimits[3]<g->wlon.l)
return(0);
break;
case 2:
if(rlimits[2]>g->wlon.l&&
rlimits[3]-TWOPI<g->wlon.l)
return(0);
break;
}
return(1);
}
option(s)
char *s;
{
if(s[0]=='-' && (s[1]<'0'||s[1]>'9'))
return(s[1]!='.'&&s[1]!=0);
else
return(0);
}
long patch[18][36];
getdata(mapfile)
char *mapfile;
{
char indexfile[32];
int cx,cy;
int kx,ky;
int k;
long b;
long *p;
int ip, jp;
int n;
struct place g;
int i, j;
float lat, lon;
int conn;
FILE *ifile, *xfile;
for(i=0;indexfile[i]=mapfile[i];i++);
indexfile[i++] = '.';
indexfile[i++] = 'x';
indexfile[i] = 0;
xfile = fopen(indexfile,"r");
if(xfile==NULL)
filerror("can't find map index", 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 */
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++) {
kx += (char)getc(ifile);
ky += (char)getc(ifile);
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);
conn = plotpt(&g,conn);
}
}
}
fclose(ifile);
}
seeable(lat0,lon0)
float lat0,lon0;
{
float x, y;
float lat, lon;
for(lat=lat0;lat<=lat0+10;lat+=grid[2])
for(lon=lon0;lon<=lon0+10;lon+=grid[2])
if(normproj(lat,lon,&x,&y)>0)
return(1);
return(0);
}
char lbl[50];
satellite(t)
struct track *t;
{
int visible, skip;
register conn;
float lat,lon;
struct place place;
static FILE *ifile = stdin;
register char *s;
if(t->tracknam[0]!='-'||t->tracknam[1]!=0) {
fclose(ifile);
if(fopen(t->tracknam,"r")==NULL)
filerror("can't find track", t->tracknam);
}
pen(t->tracktyp=='t'?"dotdash":"solid");
visible = 0;
for(;;) {
conn = 0;
while(!feof(ifile) && fscanf(ifile,"%f%f",&lat,&lon)==2){
latlon(lat,lon,&place);
conn = plotpt(&place,conn);
visible = conn;
}
skip = 1;
s = lbl;
for(;;) {
if(feof(ifile) || fscanf(ifile,"%c",s) == EOF)
return;
if(*s=='\n')
break;
if(skip) switch(*s) {
case '"':
skip = 0;
continue;
case ' ':
case '\t':
continue;
default:
skip = 0;
}
s++;
}
*s = 0;
if(visible)
text(lbl);
}
}
pnorm(x)
float x;
{
int i;
i = x/10.;
i %= 36;
if(i>=18) return(i-36);
if(i<-18) return(i+36);
return(i);
}
conv(k,g)
struct coord *g;
{
g->l = (0.0001/SCALERATIO)*k;
sincos(g);
}
error(s)
char *s;
{
closepl();
fprintf(stderr,"map: \r\n%s\n",s);
exit(1);
}
filerror(s,f)
char *s, *f;
{
closepl();
fprintf(stderr,"\r\n%s %s\n",s,f);
exit(1);
}
cpoint(xi,yi,conn)
{
if(xi<left||xi>=right)
return(0);
if(yi<bottom||yi>=top)
return(0);
if(!conn)
move(xi,yi);
else
vec(xi,yi);
return(1);
}
struct place oldg;
plotpt(g,conn)
struct place *g;
{
if(!inlimits(g))
return(0);
normalize(g);
return(plotwin(g,conn));
}
plotwin(g,conn)
struct place *g;
{
int kx,ky;
int ret;
float cutlon;
if(!inwindow(g))
return(0);
switch((*cut)(g,&oldg,&cutlon)) {
case 2:
if(conn) {
ret = duple(g,cutlon)|duple(g,cutlon);
copyplace(g,&oldg);
return(ret);
}
case 0:
conn = 0;
case 1:
copyplace(g,&oldg);
if(doproj(g,&kx,&ky)<=0)
return(0);
return(cpoint(kx,ky,conn));
}
/*NOTREACHED*/
}
doproj(g,kx,ky)
struct place *g;
int *kx,*ky;
{
float x,y;
/*fprintf(stderr,"dopr1 %f %f \n",g->nlat.l,g->wlon.l);*/
if((*projection)(g,&x,&y)<=0)
return(0);
if(rflag)
x = -x;
/*fprintf(stderr,"dopr2 %f %f\n",x,y);*/
*kx = (x-xcent)*scaling;
*ky = (y-ycent)*scaling;
return(1);
}
duple(g,cutlon)
struct place *g;
float cutlon;
{
int kx,ky;
int okx,oky;
struct place ig;
revlon(g,cutlon);
revlon(&oldg,cutlon);
copyplace(g,&ig);
invert(&ig);
if(!inlimits(&ig))
return(0);
if(doproj(g,&kx,&ky)<=0 || doproj(&oldg,&okx,&oky)<=0)
return(0);
line(okx,oky,kx,ky);
return(1);
}
revlon(g,cutlon)
struct place *g;
float 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
*/
picut(g,og,cutlon)
struct place *g,*og;
float *cutlon;
{
*cutlon = PI;
return(ckcut(g,og,PI));
}
nocut(g,og,cutlon)
struct place *g,*og;
float *cutlon;
{
return(1);
}
ckcut(g1,g2,lon)
struct place *g1, *g2;
float lon;
{
float d1, d2;
float f1, f2;
int kx,ky;
extern float diddle();
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)>0)
move(kx,ky);
}
if(f1<FUZZ&&f2<FUZZ)
return(2);
if(f1>PI*TWO_THRD||f2>PI*TWO_THRD)
return(1);
return(d1*d2>=0);
}
float diddle(g,lon,d)
struct place *g;
float d,lon;
{
float d1;
d1 = FUZZ/2;
if(d<0)
d1 = -d1;
g->wlon.l = reduce(lon+d1);
sincos(&g->wlon);
return(d1);
}
float reduce(lon)
float lon;
{
if(lon>PI)
lon -= 2*PI;
else if(lon<-PI)
lon += 2*PI;
return(lon);
}
float tetrapt = 35.26438968; /* atan(1/sqrt(2)) */
dogrid(lat0,lat1,lon0,lon1,inv)
float lat0,lat1,lon0,lon1;
{
float slat,slon,dd;
register int conn;
slat = slon = 0;
if(lat1>lat0)
slat = fmin(grid[2],dlat);
else
slon = fmin(grid[2],dlon);;
conn = 0;
while(lat0<=lat1&&lon0<=lon1) {
conn = gridpt(lat0,lon0,conn,inv);
if(projection==Xguyou&&slat>0) {
if(lat0<-45&&lat0+slat>-45)
conn = gridpt(-45.,lon0,conn,inv);
else if(lat0<45&&lat0+slat>45)
conn = gridpt(45.,lon0,conn,inv);
} else if(projection==Xtetra&&slat>0) {
if(lat0<-tetrapt&&lat0+slat>-tetrapt) {
gridpt(-tetrapt-.001,lon0,conn,inv);
conn = gridpt(-tetrapt+.001,lon0,0,inv);
}
else if(lat0<tetrapt&&lat0+slat>tetrapt) {
gridpt(tetrapt-.001,lon0,conn,inv);
conn = gridpt(tetrapt+.001,lon0,0,inv);
}
}
lat0 += slat;
lon0 += slon;
}
gridpt(lat1,lon1,conn,inv);
}
gridpt(lat,lon,conn,inv)
float lat,lon;
{
struct place g;
struct place p;
/*fprintf(stderr,"%f %f\n",lat,lon);*/
latlon(lat,lon,&g);
if(inv) {
copyplace(&g,&p);
invert(&p);
if(!inlimits(&p))
return(0);
return(plotpt(&p,conn));
}
return(plotpt(&g,conn));
}
radbds(w,rw)
float *w,*rw;
{
register i;
for(i=0;i<4;i++)
rw[i] = w[i]*RAD;
rw[0] -= FUZZ;
rw[1] += FUZZ;
rw[2] -= FUZZ;
rw[3] += FUZZ;
}
short
getshort(f)
FILE *f;
{
register c;
c = getc(f);
return(c | getc(f)<<8);
}
double
fmin(x,y)
double x,y;
{
return(x<y?x:y);
}
double
fmax(x,y)
double x,y;
{
return(x>y?x:y);
}
pathnames()
{
int i;
char *t;
for(i=0; i<NFILE && file[i]; i++) {
if(*file[i]=='/' || access(file[i],04)==0)
continue;
t = malloc(strlen(file[i])+strlen(mapdir)+2);
strcpy(t,mapdir);
strcat(t,"/");
strcat(t,file[i]);
file[i] = t;
}
}
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.