PostScript generating subsector maps

By Yngve Larsson ·

TML message #282From bundle 26

Actually, I hacked out a Poscscript program to draw 'subsec' genrated maps
some time ago. Here it is, no strings attached above James'.


These are to be considered as alterations to James' program
- ------------------------------------------------------------
psmapsub.c:
- ------------------------------------------------------------
/*
 * mapsub - produce a subsector hex-grid map from subsector data
 *
 * SYNOPSIS
 *   mapsub <Subsector.dat >Subsector.hex
 *
 * DESCRIPTION
 *   Mapsub processes the star system information on the standard input and
 *   produces a hex-grid map on the standard output.  The format expected is
 *   very precise, consisting of one formatted line for each system, each
 *   exactly 59 bytes followed by a newline.  Example:
 *
 *   "0102 Gruenwald          B775400-9 N TN NI           TI   GP"
 *
 *    XXYY System_Name_______ UPP______ B Trade_Codes___  Al Z GP
 *
 *   Where:
 *	XXYY is the system coordinates, in the range 0101-3240
 *	System_Name is the 18-character system name
 *	UPP is the Universal Planetary profile
 *	B is the base code: 'N' navy, 'S' scout, 'A' both
 *	Trade_Codes is up to fifteen characters worth of Trading codes,
 *	   from this list: TN (Terran-Norm), TP (Terran-Prime), AG
 *	   (Agricultural), NA (Non-AG), IN (Industrial), NI (Non-IN), RI
 *	   (Rich), PO (Poor), WA (Water world), DE (Desert World), VA
 *	   (Vacuum World), AS (Asteroid Belt), IC (Ice-capped), CA (Subsector
 *	   Capitol)
 *	   The only Trade_Code that does anything is CA, which causes
 *	   "Capitol" to be written into the system's hex.
 *	Al is the system alignment.  "IM" is the official alignment for the
 *	   Imperium.  I use "IN" for independent worlds.
 *	Z is the travel zone, either " " (Green), "A" (Amber), "R" (Red).
 *	G is the gas-giant-present flag, either " " (None), or "G" (exists).
 *	P is the planetoids-present flag, either " " (None), or "P" (exists).
 *
 *   The output is an array of empty and filled hexes, which look like this:
 *	   ______
 *	  / XXYY \	XXYY - System coordinates
 *	 /  * S   \	* - Navy base, S - Starport class
 *	/  ^ O .   \	^ - Scout base, "O" "@" or "%" - Desert or Non-desert
 *	\  System  /        world or Asteroid belt, . - Gas giant
 *	 \  Name  /
 *        \Zone__/	Zone - blank for green or circle for "amber" or
 *                             filled circle for "RED"
 *
 * WARNING
 *    Mapsub assumes that the input is only one subsector's worth of worlds.
 *    if you give it a sector's worth of worlds (Example: "gensec | mapsub")
 *    it will print them all, overlapping many worlds!
 *
 *    Ergo, if you want to generate worlds automatically, use gensec to
 *    produce a sector file of systems, then glean all the worlds belonging
 *    to a particular sector out of that file and put it in a subsector file,
 *    then use mapsub on the new subsector file.
 *
 * TO COMPILE
 *    On BSD systems, use:	cc -O -s -o mapsub mapsub.c
 *    On SYSV systems, use:	cc -O -DSYSV -s -o mapsub mapsub.c
 *
 * FILES
 *    Needs a blank hex map template, defined by default to be "./subhex".
 *    Change the MAP_TEMPLATE parameter to change this file's location.
 *
 * SEE ALSO
 *    gensec - the sector generator program (produces compatible format)
 *
 * AUTHOR
 *    James T. Perkins, [email removed], [email removed]
 *    Yngve Larsson, [email removed], ..!enea!liuida!yla
 *
 * BUGS
 *    The code is somewhat messy, as it was hacked out on a whim.
 *
 *    As stated above, one cannot simply use the output of gensec as input
 *    to mapsub -- the gensec output must be edited.
 */
/*

Copyright 1987 James T. Perkins
PostScript additions by Yngve Larsson

	This notice and any statement of authorship must be reproduced
	on all copies.  The author does not make any warranty expressed
	or implied, or assumes any liability or responsiblity for the
	use of this software.

	Any distributor of copies of this software shall grant the
	recipient permission for further redistribution as permitted
	by this notice.	 Any distributor must distribute this software
	without any fee or other monetary gains, unless expressed written
	permission is granted by the author.

	This software or its use shall not be: sold, rented, leased,
	traded, or otherwise marketed without the expressed written
	permission of the author.

	If the software is modified in a manner creating derivative
	copyrights, appropriate legends may be placed on derivative
	work in addition to that set forth above.

	Permission is hereby granted to copy, reproduce, redistribute or
	otherwise use this software as long as the conditions above
	are met.

	All rights not granted by this notice are reserved.

*/

#define MAP_TEMPLATE "./subps"	/* empty hex grid and PostScript file */

#include <stdio.h>
#include <strings.h>

char map[80];	/* in-memory copy of map that we operate on */

main(ac, av, envp)
int ac;
char *av[], *envp[];
{
  char system[81], name[19], upp[10], trade[16], align[3];
  char base, zone, gas, belt;
  char *s;
  int x, y, i;
  FILE *fp;

  /*
   * Read hex map template into memory
   */

  if ((fp = fopen(MAP_TEMPLATE, "r")) == NULL)
    {
      fprintf(stderr, "%s: cannot open %s.\n", av[0], MAP_TEMPLATE);
      exit(1);
    }
  while (!feof(fp))
    {
      fgets(map, 80, fp);
      printf("%s", map);
    }
  fclose(fp);

  /*
   * Start with empty, null-terminated strings
   */

  bzero(name, sizeof(name));
  bzero(upp, sizeof(upp));
  bzero(trade, sizeof(trade));
  bzero(align, sizeof(align));

  /*
   * Read in each system and place it on the map
   */

  while (!feof(stdin))
    {
      fgets(system, sizeof(system), stdin);
      sscanf(system,
	     "%2d%2d%*c%18c%*c%9c%*c%c%*c%15c%*c%2c%*c%c%*c%c%c\n",
	     &x, &y, name, upp, &base, trade, align,
	     &zone, &gas, &belt);
      rem_trail_sp(name);
      rem_trail_sp(trade);

      /*
       * write hex:
       *      ______
       *     / XXYY \
       *    /  * S   \
       *   /  ^ @ .   \
       *   \  System  /
       *    \  Name  /
       *     \______/
       */

      printf("%2d %2d mapCoords \n", x, y);
      switch (zone) {
      case 'A':
	printf("amberZone \n");
	break;
      case 'R':
	printf("redZone \n");
	break;
      }
      printf("(%.2d%.2d) hexNumber \n", x, y);
      if (upp[1] == '0')
	printf("asteroids \n");
      else if (upp[3] == '0')
	printf("desPlnt \n");
      else
	printf("liqPlnt \n");
      if (upp[4] == '9' || upp[4] == 'A')
	capitalize(name);
      printf("(%s) name \n", name);
      printf("(%c) starPort \n", upp[0]);
      if (base == 'N' || base == 'A')
	printf("navalBase \n");
      if (base == 'S' || base == 'A')
	printf("scoutBase \n");
      if (gas == 'G')
	printf("gasGiant \n");
      printf("\n");
    }

  /*
   * Write out finished map
   */

  printf("showpage \n");
  exit(0);
}

/*
 * Remove all trailing spaces from the given null-terminated string
 */

rem_trail_sp(s)
     char *s;
{
  int i = strlen(s) - 1;

  while (i >= 0 && s[i] == ' ')
    {
      s[i--] = '\0';
    }
}

/*
 * Convert lowercase characters to UPPERCASE
 */

capitalize(s)
     char *s;
{
  int i, k;
  k = strlen(s);
  for (i = 0 ; i != k ; i++)
    if (s[i] >= 'a' && s[i] <= 'z')
      s[i] = s[i] + 'A' - 'a';
}

- ----------------------------------------------------------
subps:
- ----------------------------------------------------------
%! PS-Adobe-1.0
% Traveller subsector map and mapping functions

%-----Constants-----
/cm { 72 mul 2.54 div } def     % cm >> points
/unit { 1 cm mul } def
/topOfPageX 4.5 cm def
/topOfPageY 25 cm def
/nameFont /Times-Roman findfont 12 scalefont def
/portFont /Helvetica findfont 10 scalefont def
/numberFont /Helvetica findfont 8 scalefont def

%-----Basic Functions-----
/hex {                             % - >> -
  gsave
  -1 unit 0 rmoveto
  currentpoint translate
  60 rotate
  5 {
    1 unit 0 lineto
    currentpoint translate
    -60 rotate
  } repeat
  closepath
  stroke
  grestore
} def

/rowOfHex {                       % x y >> -
  moveto
  10 {
    hex
    0 0 3 sqrt unit sub rmoveto
  } repeat
} def

/hexMap {                         % - >> -
  /curX topOfPageX def
  /curY topOfPageY def
  4 {
    curX curY rowOfHex
    /curX curX 1.5 unit add def
    /curY curY 3 sqrt 2 div unit sub def
    curX curY rowOfHex
    /curX curX 1.5 unit add def
    /curY curY 3 sqrt 2 div unit add def
  } repeat
} def

/mapCoords {                   % HexX HexY >> -
  /actY exch 1 sub 10 mod 3 sqrt unit mul topOfPageY exch sub def
  dup 2 mod 0 eq {
    actY 3 sqrt 2 div unit sub def    % displace column if HexX is even
  } if
  /actX exch 1 sub 8 mod 1.5 unit mul topOfPageX add def
} def

/getCoords {                   % - >> x y
  actX actY
} def

/liqPlnt {
  newpath
  getCoords .1 unit 0 360 arc fill
} def

/desPlnt {
  gsave
  newpath
  getCoords .1 unit 0 360 arc
  gsave
  1 setgray fill
  grestore
  .5 setlinewidth stroke
  grestore
} def

/asteroids {
  newpath
  getCoords .1 unit add .04 unit 0 360 arc fill
  getCoords exch .15 unit add exch .02 unit 0 360 arc fill
  getCoords .15 unit sub exch .1 unit add exch .03 unit 0 360 arc fill
  getCoords .04 unit sub exch .15 unit sub exch .05 unit 0 360 arc fill
  getCoords .05 unit sub .02 unit 0 360 arc fill
} def

/name {                   %  name >> -
  getCoords moveto
  nameFont setfont
  dup stringwidth pop 2 div 0 exch sub
    -.5 unit rmoveto
  gsave
  currentpoint translate
  newpath
  0 0 moveto
  dup stringwidth exch pop 0 exch lineto
  dup stringwidth lineto
  dup stringwidth pop 0 lineto
  closepath
  1 setgray fill
  grestore
  show
} def

/starPort {                % code >> -
  getCoords moveto
  portFont setfont
  dup stringwidth pop 2 div 0 exch sub
    .15 unit rmoveto
  show
} def

/navalBase {               % - >> -
  gsave
  getCoords moveto
  -.5 unit .3 unit rmoveto
  currentpoint translate
  4 {
    .2 unit 0 lineto
    currentpoint translate
    -144 rotate
  } repeat
  closepath
  fill
  grestore
} def

/scoutBase {
  gsave
  newpath
  getCoords moveto
  -.5 unit -.125 unit rmoveto
  currentpoint translate
  60 rotate
  .15 unit 0 lineto
  currentpoint translate
  -120 rotate
  .15 unit 0 lineto
  closepath
  fill
  grestore
} def

/gasGiant {
  gsave
  newpath
  getCoords moveto
  .5 unit .3 unit rmoveto
  currentpoint translate
  0 0 .05 unit 0 360 arc fill
  grestore
} def

/redZone {
  newpath
  .8 setgray
  getCoords 2 3 div unit 0 360 arc fill
  0 setgray
} def

/amberZone {
  gsave
  newpath
  3 setlinewidth
  .6 setgray
  getCoords 2 3 div unit 0 360 arc stroke
  grestore
} def

/hexNumber {                 % (XX YY) >> -
  getCoords moveto
  numberFont setfont
  dup stringwidth pop 2 div 0 exch sub
    .6 unit rmoveto
  show
} def

%-----Main-----
hexMap
% Other system specs  (start with zones)

- -----------------------------------------------------------
(Yes, the file is supposed to end like that. It will be appended by
the psmapsub routines.)

Notes:
You might want to fiddle with the constants "topOfPageX" and "topOfPageY"
if you have anything other than A4 paper size. These are the distances
to the highest leftmost hex on the map, counted from bottom and left
side of the page respectively. You can also change the constant "unit",
which is used as scaling factor throughout the program (except for fonts).


One important change is that James' maps had each even column of hexes
displaced upward. I believe GDW's maps displace these column downward, so
I changed this.

Enjoy (if it works.... :-)
				Yngve Larsson
- -----------------------------------------------------------
Yngve Larsson                               UUCP: ...[email removed]
Dept of CIS                                       Internet: [email removed]
Linkoping University, Sweden                          Phone: [phone removed]