[comp.lang.postscript] Geographical maps in PostScript

smithda@cpsvax.cps.msu.edu (J. Daniel Smith) (04/06/90)

In article <5040@aplcen.apl.jhu.edu> mjj@aplvax.UUCP (Marshall Jose) writes:
>In article <470@ntpal.UUCP> herrage@ntpal.UUCP (Robert Herrage) writes:
>>Does anyone know of any public geographical maps in PostScript of
>
>This is what I did when I simply wanted to locate Things relative to
>Political boundaries (specifically, ham packet radio stations in
>the area):
>
>[..]
>
>Nevertheless this will probably do you well as a start, since you

I took this bit of PostScript code and translated most of it into a
small C program.  The program below takes as input a map file like
those from charon.mit.edu and writes a PostScript file on stdout.  Its
not the greatest, but its easier than doing all that hand editing.

   Dan
---- map2ps.c ----
/* map2ps.c */

/* Convert map coordinates to PostScript. */

/* C program by J. Daniel Smith. (smithda@cpsvax.cps.msu.edu)
   Bassed on PostScript code by Marshall Jose */

/**************************************************************************
  Copyright (c) 1990 J. Daniel Smith.  All rights reserved.
  
  Permission is hereby granted to use this program in any way desired 
  provided such use is strictly non-commercial in nature. 
*************************************************************************/

/* Modification history:
   JDS  4 Apr 90 1.0   Orginal coding.
   */

/* Bugs:
   * The input file is read in twice.  This should be fixed, but I
     don't have time to figure out how to do it in C.
   * There is no provision for clipping as there was in the orginal
     PostScript program.
   * It would be nice to take the input file from stdin.
   * The Mercator correction might not be quite right.
*/
   

/* Each line of the input file contains four points:
      -77.1370 38.9412 -77.0624 38.9976
   This program is designed to work with map data from charon.mit.edu
   (18.80.0.13).  The input file name must be specified on the command
   line, the PostScript file is written to stdout.
*/

#define VERSION 1.0
#ifndef __DATE__
#define __DATE__ "5 April 1990"
#endif
#ifndef __TIME__
#define __TIME__ " "
#endif

/* default values for north, south, east, and west */
#define NORTH 0
#define SOUTH 90
#define EAST -360
#define WEST 0

#define DEFAULT_SIZE 3   /* default size of 3 inches */

#include <stdio.h>
#include <sys/time.h>
#include <math.h>

float south=SOUTH;

float mercorr (longitude)
     float longitude;

     /* Do the Mercator correction (if not too far north)
        Bassed on the orginal PostScript code */
{
  return ( (1/cos(M_PI/180*longitude)) * (longitude-south) + south); 
} /* mercorr() */

main (argc, argv)
     int argc;
     char **argv;
     /* Command line arguments:
	1 - input file name
	2 - image size (in inches) */
{
  float north=NORTH, east=EAST, west=WEST;
  float w, x, y, z;
  float scale, size=DEFAULT_SIZE;
  int llx, lly, urx, ury;
  FILE *input_file;
  char *userid[L_cuserid];
  struct timeval tz;
  struct timezone tzp;
  
  if ((argc < 2) || (argc > 3)) {
    fprintf (stderr, "\nusage: %s input-file [size]\n",
	     argv[0]);
    exit (-1);
  }
 
  if (argc == 3) 
    sscanf (argv[2], "%f", &size);
  
  /* read though file to determine values */
  if ((input_file = fopen (argv[1], "r")) == NULL) {
    fprintf (stderr, "\nError opening file %s\n", argv[1]);
    exit (-1);
  }
  while (fscanf (input_file, "%f %f %f %f", &w, &x, &y, &z) != EOF) {
    if (w < west) west = w;
    if (x < south) south = x;
    if (y > east) east = y;
    if (z > north) north = z;
  }
  fclose (input_file);
  
  
  /* figure out scale factor */
  if ((east-west) > (mercorr (north) - south)) 
    scale = east-west;
  else
    scale = mercorr (north) - south;
  
  /* compute BoundingBox */
  llx = lly = (int) 72 * 0.25;
  urx = (int) ((east-west)/scale * (72*size) + 72*0.25);
  ury = (int) ((mercorr (north)-south)/scale * (72*size) + 72*0.25);
  
  /******** Write the PostScript file ********/
  /* Initial comments */
  printf ("%%!\n");
  printf ("%%!PS-Adobe-2.0 EPSF-1.2\n");
  printf( "%% map2ps Version %4.2f (%s %s)\n", VERSION,
	 __DATE__, __TIME__);
  printf ("%% Copyright (c) 1990 J. Daniel Smith.  All rights reserved.\n");
  printf ("%%%%Title: %s\n", argv[1]);
  printf ("%%%%Creator: %s Version %4.2f\n", argv[0], VERSION);
  gettimeofday (&tz, &tzp);
  printf ("%%%%CreationDate: %s", ctime (&tz.tv_sec));
  printf ("%%%%For: %s\n", cuserid(userid));
  printf ("%%%%BoundingBox: %d %d %d %d\n", llx, lly, urx, ury);
  printf ("%%%%Pages: 1\n");
  printf ("%%%%EndComments\n");
  
  /* PostScript prologe */
  printf ("/D2 { moveto lineto stroke} bind def\n");
  printf ("%%%%EndProlog\n");
  
  /* Document Setup */
  /* Since this is only a one page document, its a bit difficult to */
  /* decide what is "Document Setup" and what is "Page Setup".  */
  printf ("%%%%BeginSetup\n");
  printf ("gsave  %% save orginal graphics state\n");
  printf ("72 72 scale %% work in inches\n");
  printf ("0.25 0.25 translate %% move in 0.25 inch\n");
  printf ("%9.4f %9.4f scale\n", size/scale, size/scale);
  printf ("%9.4f %9.4f translate\n", -west, -south);
  printf ("%9.7f setlinewidth %% a thin line\n", 1/(300 * scale) );
  printf ("%%%%EndSetup\n");
  
  /* Page Setup */
  /* See comments under 'Document Setup' above */
  printf ("%%%%Page: one 1\n");
  printf("%%%%PageBoundingBox: %d %d %d %d\n", llx, lly, urx, ury);
  printf ("%%%%BeginPageSetup\n");
  printf("save  %% save at start of every new page\n");
  
  /* Process input data and write PostScript file */
  printf ("%%%%BeginObject: %s\n", argv[1]);
  if ((input_file = fopen (argv[1], "r")) == NULL) {
    fprintf (stderr, "\nError opening file %s\n", argv[1]);
    exit (-1);
  }
  while (fscanf (input_file, "%f %f %f %f",  &w, &x, &y, &z) != EOF) {
    printf ("%9.4f %9.4f %9.4f %9.4f D2\n", w, mercorr(x), y,
	    mercorr(z));
  }
  fclose (input_file);
  printf ("%%%%EndObject\n");
  
  printf("restore  %% end of page\n");
  printf("showpage\n");
  printf ("%%%%PageTrailer\n");
  
  /* The document Trailer */
  printf ("%%%%Trailer\n");
  printf ("grestore  %% return to orginal graphics state\n");
  
  exit(0);
}

=========================================================================
J. Daniel Smith                      Internet: smithda@cpsvax.cps.msu.edu
Michigan State University              BITNET: smithdan@msuegr
East Lansing, Michigan                 Usenet: uunet!frith!smithda

People always get what they ask for; the only trouble is that they never
know, until they get it, what they have asked for.
                                    - Aldous Huxley
=========================================================================

jrstremikis@vms.macc.wisc.edu (John Stremikis) (04/13/90)

I have appreciated the discussion and pointers to ftp
sources of world map coordinates.

While I've tried the PS programs posted, and like the 
results... I'm really not a PS programmer or hacker
(well... not very much of one).

Alt. 1: I've been very satisfied with using a combination of
McSink and Wingz (or Excel) to take the coordinates
and prepare a file for import to Super3D. (You may want to
scale the points up). 

Alt. 2: I've also been very satisfied to use McSink to add
tabs to the file, and then use Wingz' XY or Scatter graphing 
functions. Wingz does a _very nice_ job of labeling the
axes.

Alt. 3: Finally, I'm using Adobe Illustrator to create a "PostScript
template" of a very, very crude map. I open the "template"
in McSink, and focus on the very end, to get an idea of the
format Illustrator likes. Then, I use McSink to make the
geographical coordinates file "look like" what Illustrator
wants. (A lot like Marshall Jose suggested.) Finally, I
paste into the Illustrator file what McSink has assembled.

Illustrator will open the file nicely... for screen preview,
though, again, you may want to scale the points up 
somewhere in your process. It's also possible to add
singular points (such as a station location), and use
Illustrator's text tools to affix labels. Again, Marshall
Jose has done well in suggesting a way of getting started.
(For those of us once or twice removed from actual programming.)

John Stremikis