home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Usenet 1994 October
/
usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso
/
misc
/
volume32
/
wmap2ps
/
part01
/
wmap2ps.c
< prev
Wrap
C/C++ Source or Header
|
1992-09-11
|
20KB
|
741 lines
/*
wmap2ps
Description: converts files from the WORLDMAP package
(MP1 format) by John B. Allison to PostScript
The program expects input from stdin in WORLDMAP format
as described below and writes a corresponding PostScript
file to stdout.
Written by Patsch in September 1992 (I needed the map of Tassie...)
This program is in the Public Domain, as
long as the README file is kept intact.
=====================================================================
Usage :
wmap2ps [ -u unit ] %% one from { cm, in, pt }
[ -o x y ] %% lower left corner of image
[ -w width ] %% desired target width/height
[ -h height ] %% using the current unit
[ -nomercat ] %% don't use mercator projection
[ -unconnect ] %% if multiple maps are concatenated
%% this may be detected by the presence of
%% a comment. if you activate this option,
%% every block of comments that appears implies
%% that the first pair of data points in the block
%% should be treaten as the beginning of a new line.
[ -showbox ] %% draw the bounding box
[ -drawsegs ] %% do a 'stroke' after every line segment
[ -debug ] %% print additional information
NOTES: - If you specify both width and height this will result
in a change of the image ratio, i.e. a distortion.
- default unit is cm"
- default origin is 0 0"
- default width is original width\n"
=====================================================================
Compiled successfully on a SPARCstation running SunOS 4.1.1 with:
gcc -O -o wmap2ps wmap2ps.c
If you have problems compiling the program, you might need to change
the lines where strings are concatenated over more than one line.
I know that many compilers are not able to do that.
=====================================================================
.MP1 File Format: variable length ASCII records
Data Records
field
1 latitude floating point number
2 blank field separator
3 longitude floating point number
[4] optional begining with a blank
comment
5 line feed end of record (LF - 10)
Separator Records
field
[1] optional blanks[s]
2 line feed end of record (LF - 10)
All you have to do is
- to draw a line from (x0,y0) to (x1,y1); the from (x1,y1) to (x2,y2) etc.
- if a separator line (blank line) is read, break the connection,
You may have noticed distortion in the maps displayed in the
previous programs, epecially at extreme latitudes. This
distortion is caused by an attempt to map the curved surface
of a three dimensional globe onto a two dimensional plane. As
you travel toward the poles, the 360 degrees of longitude are
squeezed into less and less space on the globe, but not on the
plane.
There are many ways to compensate for the distortion problem.
Probably the solution most widely recognized is the Mercator
projection, named for a famous early map maker. Mercator's
projection has the characteristics that both lines of latitude
and longitude are straight and at right angles to each other
(orthogonal). In addition, if a small area is viewed, there
is no distortion of form: areas have the right shape although
the vertical scale and total area is distorted as you move from
the equator.
The formula for the Mercator projection is
y = ln{tan[45 deg + latitude/2)/deg_per_radian]}
Check out the Encyclopedia Britannica under Map for all this
good stuff and more.
========================================================================
The data you may use with this tool can be found for example on host
nz20.rz.uni-karlsruhe.de
in the directory
/pub/msdos/worldmap
Just use archie and look for 'worldmap' in EXACT mode.
=======================================================================
As wmap2ps acts as a pipe, you may do the following
cat AU0.MP1 AU1.MP1 AU2.MP1 | wmap2ps -unconnect -o 1 1 -w 6 > au.ps
This would create a PostScript file that draws
the map of Australia, its seas and its islands.
If you glue together different maps in such a way, this may result in
a map where the parts are connected by visible lines - to fix this
problem you may want to add an extra separator line (blank line)
at the end of the map files.
=====================================================================
cookies to RCS
=====================================================================
$Author: dockhorn $
$Revision: 1.0 $
$Log: wmap2ps.c,v $
* Revision 1.0 92/09/05 18:06:07 dockhorn
* Initial revision
*
*/
#include <stdio.h>
#include <math.h>
static char rcsid[] = "$Header: /disk/DBS0S3-2H/home/dockhorn/TOOLS/SRC/WMAP2PS/RCS/wmap2ps.c,v 1.0 92/09/05 18:06:07 dockhorn Exp Locker: dockhorn $";
#define TEMPFILE "wmap2ps.tmp"
#define Key(x) if (!(strcmp(argv[i],x)))
/* primitive prototyping */
void hints();
int main();
short rvalues();
int check_arguments();
/* print out the command line format */
void hints(void)
{
fprintf(stderr,
"\n\nwmap2ps [ -u unit ] /* one from { cm, in, pt } */"
"\n [ -o x y ] /* lower left corner of image */"
"\n [ -w width ] /* desired target width/height */"
"\n [ -h height ] /* using the current unit */"
"\n [ -nomercat ] /* don't use mercator projection */"
"\n [ -unconnect ] /* don't draw illegal connections*/"
"\n [ -showbbox ] /* draw the bounding box */"
"\n [ -debug ] /* print additional information */\n"
"\nNOTES: - If you specify both width and height this will result"
"\n in a change of the image ratio, i.e. a distortion."
"\n - default unit is cm"
"\n - default origin is 0 0"
"\n - default width is original width\n"
"\nSee the manpage for more information.\n");
}
/* ok, ok, too many global variables,
but here speed is more important than style
and I lose enough speed by letting the
program act as a pipe */
#define BUFSIZE 80
static int linecnt = 0; /* number of lines read */
static short debug = 0; /* several flags */
static float minlong = 1e10,minlat = 1e10, /* to compute bounding box */
maxlong = -1e10, maxlat = -1e10,
miny = 1e10, maxy = -1e10;
static float llx = 0.0,lly = 0.0; /* user desired object origin */
static char *unitnames[] = { "cm" , "in" , "pt" };
static float unitfacts[] = { 28.34646, 72.0, 1.0 };
/*
read in two values from stdin.
I use a procedure rather than fscanf to be able to cope with
additional comments after the values, i.e. lines like
-40.723 144.912 The World Digitized
-40.781 144.891 Islands of Australia
-40.801 144.896 Copyright 1986 John B. Allison
the returned value tells me whether I should break the line
connection or not.
*/
short rvalues(ftmp,x,y,mercat)
FILE *ftmp;
float *x; /* longitude */
float *y; /* latitude */
short mercat; /* do conversion?*/
{
static unsigned char buf[BUFSIZE]; /* buffer for line read from file*/
unsigned char c = (unsigned char) 0; /* current char read */
unsigned char *tmp;
float latitude,longitude;
short idx = 0;
c = fgetc(stdin);
while ((!(feof(stdin))) && (c != '\n') && (idx < BUFSIZE))
{
buf[idx++] = c;
c = (unsigned char) fgetc(stdin);
}
/* separator line ? */
while ((idx > 0) &&
((buf[idx-1] == ' ') ||
(buf[idx-1] == '\011') ||
(buf[idx-1] == '\015')))
buf[--idx] = (unsigned char) 0;
if (!(feof(stdin)))
{
linecnt++;
if (!(idx < BUFSIZE))
fprintf(stderr,"\nSorry, line %d is too long.",linecnt);
else
{
if (idx == 0) return(0); /* break line connection */
buf[idx] = (unsigned char) 0;
tmp = &buf[0];
/* discard any control characters at the beginning of the buffer */
while ((*tmp) && (*tmp < ' ')) tmp++;
sscanf(tmp,"%g %g",&latitude,&longitude);
if (latitude < miny) miny = latitude;
if (latitude > maxy) maxy = latitude;
if (mercat)
{
/* too close to pole -> don't project */
if (!((fabs(latitude-90.0) < 1) ||
(fabs(latitude-270.0) < 1)))
latitude = (float) log(tan((45.0 +
0.5*(double)latitude)*M_PI/180.0));
}
/* bounding box changed ? */
if (longitude < minlong) minlong = longitude;
if (longitude > maxlong) maxlong = longitude;
if (latitude < minlat) minlat = latitude;
if (latitude > maxlat) maxlat = latitude;
/* control output */
if ((debug) && ((linecnt % 200) == 0))
{
fputc('.',stderr);
fflush(stderr);
}
/* if there is a comment, print it to the output file */
tmp = &buf[0];
while ((*tmp) && (!(((*tmp >= 'a') && (*tmp <= 'z')) ||
((*tmp >= 'A') && (*tmp <= 'Z'))))) tmp++;
*y = latitude;
*x = longitude;
if (*tmp)
{
fprintf(ftmp,"\n%% %s",tmp);
return(2); /* comment encountered */
}
}
}
return(1);
}
/*
parse command line arguments
*/
int check_arguments(argc,argv,
p_unitstr,p_unitfactor,
p_width,p_height,
p_mercat,p_unconnect,
p_showbox,p_drawsegs)
int argc;
char *argv[];
char **p_unitstr;
float *p_unitfactor;
float *p_width;
float *p_height;
short *p_mercat;
short *p_unconnect;
short *p_showbox;
short *p_drawsegs;
{
int i,j;
short hit;
/* check for command line params */
for (i = 1 ; i < argc ; i++)
{
if (*argv[i] != '-')
{
fprintf(stderr,
"\nUnknown command line argument '%s' - abort.",
argv[i]);
hints();
return(-1);
}
else
switch(*(argv[i]+1))
{
case 'u':
if (!(strcmp(argv[i]+1,"unconnect"))) *p_unconnect = 1;
else
{
if (*(argv[i]+2) != (char) 0)
{
fprintf(stderr,
"\nUnknown option '%s' - maybe '-u' was intended.",
argv[i]);
hints();
return(-1);
}
i++;
for (j = 0 , hit = 0; j < 3 ; j++)
{
Key(unitnames[j])
{
hit = 1;
*p_unitstr = &unitnames[j][0];
*p_unitfactor = unitfacts[j];
}
}
if (!(hit))
{
fprintf(stderr,"\nUnknown unit '%s' requested.",argv[i]);
hints();
return(-1);
}
}
break;
case 'w' :
case 'W':
if (*(argv[i]+2) != (char) 0)
{
fprintf(stderr,
"\nUnknown option '%s' - maybe '-w' was intended.",
argv[i]);
hints();
return(-1);
}
if ((i+1) < argc)
sscanf(argv[++i],"%g",p_width);
else
{
fprintf(stderr,"\nMissing value after -w option - abort.");
hints();
return(-1);
}
break;
case 'h' :
case 'H':
if (*(argv[i]+2) != (char) 0)
{
fprintf(stderr,
"\nUnknown option '%s' - maybe '-w' was intended.",
argv[i]);
hints();
return(-1);
};
if ((i+1) < argc)
sscanf(argv[++i],"%g",p_height);
else
{
fprintf(stderr,"\nMissing value after -h option - abort.");
hints();
return(-1);
}
break;
case 'n':
if (!(strcmp(argv[i]+1,"nomercat"))) *p_mercat = 0;
else
{
fprintf(stderr,
"\nUnknown option '%s' - maybe '-nomercat' was intended.",
argv[i]);
hints();
return(-1);
};
break;
case 's':
if (!(strcmp(argv[i]+1,"showbox"))) *p_showbox = 1;
else
{
fprintf(stderr,
"\nUnknown option '%s' - maybe '-showbox' was intended.",
argv[i]);
hints();
return(-1);
};
break;
case 'd':
if (!(strcmp(argv[i]+1,"debug"))) debug = 1;
else
{
if (!(strcmp(argv[i]+1,"drawsegs")))
*p_drawsegs = 1;
else
{
fprintf(stderr,
"\nUnknown option '%s'"
"\n - maybe '-debug' or '-drawsegs' have been intended.",
argv[i]);
hints();
return(-1);
}
}
break;
case 'o':
if (*(argv[i]+2) != (char) 0)
{
fprintf(stderr,
"\nUnknown option '%s' - maybe '-o' was intended.",
argv[i]);
hints();
return(-1);
}
else
{
if ((i+2) < argc) /* arguments given ? */
{
sscanf(argv[++i],"%g",&llx);
sscanf(argv[++i],"%g",&lly);
}
else
{
fprintf(stderr,
"\nMissing values after '-o' - abort.");
hints();
return(-1);
}
}
break;
default :
fprintf(stderr,
"\nUnknown command line argument '%s' - abort.",
argv[i]);
hints();
return(-1);
} /* end switch */
} /* end loop over command line options */
return(0);
/* ------------------ end of command line parsing------------------- */
} /* end check_arguments() */
/***********************************************************************/
/***********************************************************************/
/* M A I N */
/***********************************************************************/
/***********************************************************************/
int main(argc, argv)
int argc;
char *argv[];
{
/* ============================= VARIABLES ========================== */
float y,x,lx,ly; /* temporary location variables */
float bwidth,bheight,blat; /* natural object size */
float width = -1.0, height = -1.0; /* user desired object size */
char *unitstr = unitnames[0];
float unitfactor = unitfacts[0];
short mercat = 1, showbox = 0, status,
oldstatus = 0, drawsegs = 0, unconnect = 0;
short isdrawn;
FILE *ftmp = fopen(TEMPFILE,"w"); /* handle for temporary file */
char c;
/* possible units and their conversion values */
/* =============================== CODE ============================= */
if (check_arguments(argc,argv,
&unitstr,&unitfactor,
&width,&height,
&mercat,&unconnect,
&showbox,&drawsegs)) return(-1);
llx*=unitfactor; /* convert origin to current unit */
lly*=unitfactor;
/* read stdin and write the data to a temporary
file while looking for the bounding box */
if (ftmp == (FILE *) NULL)
{
fprintf(stderr,
"\nCouldn't open temporary file %s for writing - abort.\n",
TEMPFILE);
return(-1);
}
if (debug)
{
fprintf(stderr,
mercat ? "\nUsing mercator projection." : "\nNo projection.");
fprintf(stderr,"\nscanning");
}
/* -------------------------- conversion --------------------------- */
rvalues(ftmp,&lx,&ly,mercat);
fprintf(ftmp,"\n%g %g M",lx,ly);
while (!(feof(stdin)))
{
status = rvalues(ftmp,&x,&y,mercat);
isdrawn = 0;
if ((status == 2) && (oldstatus == 1))
{
fprintf(stderr,
"\nWarning ! I found a comment in line %d of the input file"
"\n but no separator line before it. This might"
"\n result in a line that interconnects different maps.\n",
linecnt);
if (unconnect)
{
fprintf(stderr,
"As you gave the '-unconnect' option, I'll break the line here.\n");
fprintf(ftmp,"\n%g %g M",x,y);
isdrawn = 1;
status = 0;
}
else
fprintf(stderr,
"You should check the file or specify the '-unconnect' option.\n");
}
/* a blank line means break line connection */
if (status)
fprintf(ftmp,"\n%g %g L",lx,ly,x,y);
else
{
if (!(isdrawn))
{
while (!(status))
{
status = rvalues(ftmp,&x,&y,mercat); /* scan next starting point */
if ((debug) && (!(status)))
fprintf(stderr,"\nMultiple separators in line %d.\n",linecnt);
}
fprintf(ftmp,"\n%g %g M",x,y);
}
}
lx = x; ly = y;
oldstatus = status;
}
fclose(ftmp);
/* -------------------------- computation --------------------------- */
bwidth = maxlong - minlong; /* extents before scaling */
bheight = maxy - miny;
blat = maxlat - minlat;
/* if neither -w nor -h was given, use original size */
if ((height < 0.0) && (width < 0.0))
{
height = bheight;
width = bwidth;
unitfactor = 1.0;
}
else
{
if (height > 0.0)
{
/* compute width from desired height and object size */
height*=unitfactor;
if (width < 0.0) /* preserve ratio */
width = bwidth*height/bheight;
else
width*=unitfactor; /* ok, that's what you wanted */
}
else
{
/* compute height from desired width and object size */
width*=unitfactor;
height = bheight*width/bwidth;
}
}
if (debug)
fprintf(stderr,
"\n\nNumber of data points = %d"
"\nSelected unit = %s"
"\nBounding Box of given object = %6.1f %6.1f %6.1f %6.1f"
"\nNatural size of object = %6.1f x %6.1f points"
"\nScaling factors = %6.1f %6.1f"
"\nSize of object after scaling = %6.1f x %6.1f points"
"\n = %6.1f x %6.1f inches"
"\n = %6.1f x %6.1f cm"
"\nDesired origin = %6.1f , %6.1f points"
"\n = %6.1f , %6.1f inches"
"\n = %6.1f , %6.1f cm\n\n",
linecnt,
unitstr,
minlong,minlat,maxlong,maxlat,
bwidth,blat,
width/bwidth,height/blat,
width,height,
width/72.0,height/72.0,
width/28.34646,height/28.34646,
llx,lly,
llx/72.0,lly/72.0,
llx/28.34646,lly/28.34646);
/* write prologue */
fprintf(stdout,
"%%!PS-Adobe-2.0 EPSF-2.0"
"\n%%%%Title: (unknown)"
"\n%%%%Creator: wmap2ps by Patrick Dockhorn - WORLDMAP data (C) 1986 John B. Allison"
"\n%%%%BoundingBox: %g %g %g %g"
"\n%%%%Pages: 1"
"\n%%%%DocumentFonts:"
"\n%%%%EndComments"
"\n%%%%EndProlog\n"
"\n%% remember original state"
"\n/origstate save def\n"
"\n%% build a temporary dictionary"
"\n20 dict begin\n"
"\n%% scale to size desired by user"
"\n%% (%g x %g points ="
"\n%% %g x %g inches ="
"\n%% %g x %g centimeter)"
"\n%g %g scale\n"
"\n%% set color to black and select thinnest line\n"
"\n0 setlinewidth 0 setgray\n\n"
"\n%c newpath %g %g moveto %g 0 rlineto %% show bounding box"
"\n%c 0 %g rlineto %g 0 rlineto closepath stroke\n"
"\n%% lower left corner"
"\n%g %g translate\n"
"\n/M {%smoveto } def"
"\n/L { lineto%s} def\n",
llx,lly,llx+width,lly+height,
width,height,
width/72.0,height/72.0,
width/28.34646,height/28.34646,
width/bwidth,height/blat,
showbox ? ' ' : '%',
(llx*bwidth/width),
(lly*blat/height),bwidth,
showbox ? ' ' : '%',
blat,-1.0*bwidth,
(llx*bwidth/width)-minlong,
(lly*blat/height)-minlat,
drawsegs ? " newpath " : " ",
drawsegs ? " currentpoint stroke moveto " : " ");
if ((ftmp = fopen(TEMPFILE,"r")) == (FILE *) NULL)
{
fprintf(stderr,
"\nCouldn't open temporary file %s for reading - abort.\n",
TEMPFILE);
return(-1);
}
/* copy from temporary file to stdout */
c = fgetc(ftmp);
while (!(feof(ftmp)))
{
fputc(c,stdout);
c = fgetc(ftmp);
}
/* write closing */
fprintf(stdout,
"%sshowpage"
"\n%% stop using temporary dictionary"
"\nend\n"
"\n%% restore original state"
"\norigstate restore"
"\n\n%%%%Trailer\n",
drawsegs ? "\n" : "\nstroke\n");
unlink(TEMPFILE); /* remove temporary file */
return(0);
} /* end main */