[comp.sources.misc] v18i003: planet - planet generation simulator, Part03/04

allen@viewlogic.com (Dave Allen) (04/08/91)

Submitted-by: Dave Allen <allen@viewlogic.com>
Posting-number: Volume 18, Issue 3
Archive-name: planet/part03
Supersedes: tec: Volume 10, Issue 77-78

#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of archive 3 (of 4)."
# Contents:  src/Makefile src/clim.h src/fileio.c src/clim.c src/heat.c
#   src/pressure.c src/wind.c src/rain.c src/climate.c
# Wrapped by allen@baja on Sat Mar 23 16:18:37 1991
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f src/Makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/Makefile\"
else
echo shar: Extracting \"src/Makefile\" \(1309 characters\)
sed "s/^X//" >src/Makefile <<'END_OF_src/Makefile'
XLIBS  = -lm -lXaw -lXt -lXmu -lX11 -lXext
XFLAGS =
XCOBJ  = clim.o heat.o pressure.o wind.o rain.o climate.o fileio.o
XTOBJ  = tec1.o tec2.o tec3.o fileio.o
XGOBJ  = globe.o fileio.o
XGRAF  = x
X
X# Change GRAF from x to unix to produce text-only versions
X
Xall: clim tec globe
X
Xclim:       $(COBJ) $(GRAF).o; cc $(FLAGS) -o clim  $(COBJ) $(GRAF).o $(LIBS)
Xtec:        $(TOBJ) $(GRAF).o; cc $(FLAGS) -o tec   $(TOBJ) $(GRAF).o $(LIBS)
Xglobe:      $(GOBJ) $(GRAF).o; cc $(FLAGS) -o globe $(GOBJ) $(GRAF).o $(LIBS)
X
Xtec1.o:     tec1.c const.h tec.h;      cc $(FLAGS) -c tec1.c
Xtec2.o:     tec2.c const.h tec.h;      cc $(FLAGS) -c tec2.c
Xtec3.o:     tec3.c const.h tec.h;      cc $(FLAGS) -c tec3.c
X
Xglobe.o:    globe.c const.h;           cc $(FLAGS) -c globe.c
X
Xclim.o:     clim.c const.h clim.h;     cc $(FLAGS) -c clim.c
Xheat.o:     heat.c const.h clim.h;     cc $(FLAGS) -c heat.c
Xpressure.o: pressure.c const.h clim.h; cc $(FLAGS) -c pressure.c
Xwind.o:     wind.c const.h clim.h;     cc $(FLAGS) -c wind.c
Xrain.o:     rain.c const.h clim.h;     cc $(FLAGS) -c rain.c
Xclimate.o:  climate.c const.h clim.h;  cc $(FLAGS) -c climate.c
X
Xfileio.o:   fileio.c const.h clim.h;   cc $(FLAGS) -c fileio.c
Xunix.o:     unix.c const.h;            cc $(FLAGS) -c unix.c
Xx.o:        x.c const.h clim.h;        cc $(FLAGS) -c x.c
END_OF_src/Makefile
if test 1309 -ne `wc -c <src/Makefile`; then
    echo shar: \"src/Makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/clim.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/clim.h\"
else
echo shar: Extracting \"src/clim.h\" \(675 characters\)
sed "s/^X//" >src/clim.h <<'END_OF_src/clim.h'
X#define MAXB       4
X#define LINE_DIAG  1
X#define LINE_CORN  2
X#define LINE_0V    1
X#define LINE_1V    2
X#define LINE_0H    4
X#define LINE_1H    8
X#define N          LINE_0V
X#define S          LINE_1V
X#define E          LINE_0H
X#define W          LINE_1H
X#define PR_LOW     1
X#define PR_HIGH    2
X#define PR_HEQ     3
X#define M_MAIN     0
X#define M_HEAT     1
X#define M_PRESS    2
X#define M_WIND     3
X#define M_RAIN     4
X#define M_CLIM     5
X#define C_OCEAN    0
X#define C_BARELAND 1
X#define C_MOUNTAIN 2
X#define C_OCEANICE 3
X#define C_TUNDRA   4
X#define C_STEPPE   5
X#define C_DESERT   6
X#define C_SAVANA   7
X#define C_DECID    8
X#define C_JUNGLE   9
X#define C_SWAMP   10
END_OF_src/clim.h
if test 675 -ne `wc -c <src/clim.h`; then
    echo shar: \"src/clim.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/fileio.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/fileio.c\"
else
echo shar: Extracting \"src/fileio.c\" \(12090 characters\)
sed "s/^X//" >src/fileio.c <<'END_OF_src/fileio.c'
X/* This program is Copyright (c) 1991 David Allen.  It may be freely
X   distributed as long as you leave my name and copyright notice on it.
X   I'd really like your comments and feedback; send e-mail to
X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
X   Avenue, Maynard, MA 01754. */
X
X/* This file contains all of the file input and output routines; putmat()
X   is the output routine.  The function getparam() is called to start the
X   parameter file input; the routines to read in the parameters follow. */
X
X#include "const.h"
X#include "clim.h"
X#include <stdio.h>
X
X/* The input is handled by one function, gettoken(), which returns one
X   of the following codes each time it is called. */
X#define TOK_EOF 0
X#define TOK_OPEN 1
X#define TOK_CLOSE 2
X#define TOK_WORD 3
X
X
X/* These parameters are needed by every source file; they are defined
X   in main.c and described in params.doc */
X
Xextern int XSIZE, YSIZE, BSIZE, ZCOAST, PRINTMODE;
X
X/* The file pointer is used to read the parameters from a file.  Linecount
X   is incremented each time a newline is read from the file, so error
X   messages can refer to a line number.  Getbuf is the buffer each word
X   is read into.  Getfname is a private copy of the filename used, so it
X   can be reread if needed.   The two lookup tables are used by putmat();
X   scalelut is set up by init().  Change is set by any of the parameter
X   input routines which change a parameter. */
Xstatic FILE *fp;
Xstatic int linecount = 1;
Xstatic char getbuf [256];
Xchar scalelut[256], shortlut[] = "0123456789ABCDEF";
Xextern int change[];
X
X
Xusermessage (s) char *s; { fprintf (stderr, "%s\n", s); }
X
X
Xfileinit () { int i; for (i=0; i<256; i++) scalelut[i] = shortlut[i>>4]; }
X
X
Xputmat (s, buf, mode, cra, lra)
X   char *s; int buf, mode; unsigned char cra[MAXX][MAXY], lra[MAXX][MAXY]; {
X   register int i, j, k;
X
X   if (mode == PRINTMODE_CLIM) { psprint (cra, lra, 1); return (0); }
X   else if (PRINTMODE == PRINTMODE_GREY) {
X      psprint (cra, lra, 0); return (0); }
X
X   if (buf > -1) printf ("(%s %d (\n", s, buf);
X   else printf ("(%s (\n", s);
X
X   if (PRINTMODE == PRINTMODE_LONG)
X      for (j=0, k=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
X         printf ("%4d", cra[i][j]); if (++k == 15) { printf ("\n"); k = 0; } }
X   else if (mode == PRINTMODE_SHORT) for (j=0; j<YSIZE; j++) {
X      for (i=0; i<XSIZE; i++) printf ("%c", shortlut[cra[i][j]]);
X      if (j < YSIZE-1) printf ("\n"); }
X   else if (mode == PRINTMODE_SCALE) for (j=0; j<YSIZE; j++) {
X      for (i=0; i<XSIZE; i++) printf ("%c", scalelut[cra[i][j]]);
X      if (j < YSIZE-1) printf ("\n"); }
X   printf ("))\n"); return (0); }
X
X
Xgetparams (s) char *s; {
X   /* This function is called either by init() or picktype(), in main.c.
X   In either case, the argument is a string which is supposed to be either
X   "-", in which case stdin is opened, or a filename.  If the file doesn't
X   exist, the program exits via panic().  Once the file is open, the loop
X   expects to find paren-delimited pairs of (name value).  Value could be
X   a vector, like (name (val1 val2)).  After a name is found, params(),
X   above, is called to recognize the parameter.  If there is a syntax
X   error or an unrecognized parameter, the program exits via panic().
X   Each computation source file has its own parameter function; if all of
X   them fail the parameter name is unknown. */
X
X   int x;
X
X   if (!strcmp (s, "-")) fp = stdin;
X   else if (!(fp = fopen (s, "r"))) panic ("Can't find input file");
X   while ((x = gettoken (getbuf)) != TOK_EOF) {
X      if (x != TOK_OPEN) geterr ("expected open paren");
X      if (gettoken (getbuf) != TOK_WORD) geterr ("expected param name");
X      if (!mainpar  (getbuf)) geterr ("unknown parameter name");
X      if (gettoken  (getbuf) != TOK_CLOSE) geterr ("expected close paren"); }
X   fclose (fp); }
X
X
Xgettoken (s) char *s; {
X   /* This is the only function which actually reads from the file.  It
X   maintains a one-character private unget buffer.  It ignores initial
X   whitespace, but counts newlines in order to maintain an accurate linecount.
X   Open or close parentheses count as tokens, and so does any amount of text
X   with no white space or parens.  The return code indicates whether an
X   open or close paren, end of file, or a word was found.  If a word was
X   found, it is copied into the string pointed to by s.  When a word is found,
X   the character which terminated it (whitespace, EOF, or paren) is put into
X   the unget buffer to be read the next time gettoken() is called. */
X
X   static char buf = 0; char c;
X
X   white: if (buf) { c = buf; buf = 0; } else c = getc (fp);
X   switch (c) {
X      case '\n': linecount++;
X      case '\t':
X      case ' ' : goto white;
X      case EOF : return (TOK_EOF);
X      case '(' : return (TOK_OPEN);
X      case ')' : return (TOK_CLOSE); }
X   text: if ((c==' ')||(c=='\t')||(c=='\n')||(c==')')||(c=='(')||(c==EOF)) {
X      buf = c; *s = 0; return (TOK_WORD); }
X   else { *s++ = c; c = getc (fp); goto text; } }
X
X
Xgeterr (s) char *s; {
X   /* Use panic() to print a nicely formatted message, containing the input
X   file line number, describing why the program just spat up. */
X   sprintf (getbuf, "Par error: %s on line %d", s, linecount);
X   fclose (fp);
X   panic (getbuf); }
X
X
Xgetlng (x, chg) int *x, chg; { int n;
X   /* Called after reading a name associated with a single int, this
X   function just reads a int from the input file and uses atoi() to
X   convert it to a int, stored at the address passed in.  Note that any
X   text, including a string or a real, will be read in; no type checking
X   is performed.  If the value is different from the previous value of the
X   parameter, change[chg] is set to one. */
X
X   if (gettoken (getbuf) != TOK_WORD) geterr ("expected int");
X   n = atoi (getbuf); if (n != *x) change[chg] = 1; *x = n; }
X
X
Xgetdbl (x, chg) double *x; int chg; { double n;
X   /* This function reads in a double format number, like getlng above.  If
X   the value is different from the previous value, change[chg] is set to 1. */
X
X   if (gettoken (getbuf) != TOK_WORD) geterr ("expected double");
X   n = atof (getbuf); if (n != *x) change[chg] = 1; *x = n; }
X
X
Xgetmat (dim1, dim2, chg, m)
X   int *dim1, *dim2, chg; unsigned char m[MAXX][MAXY]; {
X   /* This function expects to find a vector of strings, where each string
X   contains only 0-9, A-Z.  The characters are converted into the numbers
X   0..36 and stored in the character array whose address is passed into the
X   function.  If one of the strings is too long, or if there are too many
X   strings, the function spits up.  Before exiting, the function sets the
X   array limits passed in; dim1 is set to the length of the longest string,
X   while dim2 is set to the number of strings.  If any of the characters,
X   or either dimension, is changed, then change[chg] is set to 1. */
X
X   int x, i = 0, j = 0, imax = -1; char c;
X
X   if (gettoken (getbuf) != TOK_OPEN) geterr ("expected open paren");
X   while ((x = gettoken (getbuf)) == TOK_WORD) {
X      if (j == *dim2) geterr ("matrix too high");
X      for (i=0; getbuf[i]; i++) {
X         if ((c = getbuf[i] - '0') > 9) c = 10 + getbuf[i] - 'A';
X         if (c != m[i][j]) change[chg] = 1; m[i][j] = c; }
X      if (i > *dim1) geterr ("string too long");
X      if (i > imax) imax = i; j++; }
X   if (x != TOK_CLOSE) geterr ("expected close paren");
X   if ((*dim1 != imax) || (*dim2 != j)) change[chg] = 1;
X   *dim1 = imax; *dim2 = j; }
X
X
Xgetlvec (dim, v, chg) int *dim, *v, chg; {
X   /* This function expects to find a list of ints, starting with an open
X   paren and ending with a close paren.  The parameter dim should contain the
X   compiled-in array limit; if the input file contains more than this number
X   of entries, the function spits up.  No type checking is done; atoi() is
X   used to convert any text to an int.  On exit, the dimension is set to
X   the right value.  If either the dimension, or any of the elements, have
X   changed from the previous values, change[chg] is set to one. */
X
X   int x, i = 0, n;
X
X   if (gettoken (getbuf) != TOK_OPEN) geterr ("expected open paren");
X   while ((x = gettoken (getbuf)) == TOK_WORD) {
X      if (i == *dim) geterr ("vector too long");
X      n = atoi (getbuf);
X      if (n != v[i]) change[chg] = 1; v[i++] = n; }
X   if (x != TOK_CLOSE) geterr ("expected close paren");
X   if (i != *dim) change[chg] = 1; *dim = i; }
X
X
Xgetdim (x, chg) int *x, chg; { int y;
X   /* Called right after reading a name associated with an array bound,
X   this function reads one int from the input file; if the value is
X   greater than the default value assigned above, the user is trying
X   to exceed a compiled-in limit.  That's an error. */
X
X   if (gettoken (getbuf) != TOK_WORD) geterr ("expected int");
X   y = atoi (getbuf);
X   if (y > *x) geterr ("dimension exceeds reserved space");
X   *x = y; change[chg] = 1; }
X
X
Xgetdvec (dim, v, chg) int *dim; double *v; int chg; {
X   /* Called right after reading a name associated with a one-dimensional
X   array of doubles, this function expects to find a list of doubles
X   starting with an open paren and ended by a closing paren.  The parameter
X   dim contains the compiled-in array limit; if the input file contains
X   more than this number of entries, the function complains.  No type checking
X   is done; atof() is used to convert any text to a double.  On exit, the
X   dimension is set to the correct value. */
X
X   int x, i = 0;
X
X   if (gettoken (getbuf) != TOK_OPEN)
X      geterr ("expected open paren");
X   while ((x = gettoken (getbuf)) == TOK_WORD) {
X      if (i == *dim) geterr ("vector is too long");
X      v[i++] = atof (getbuf); }
X   if (x != TOK_CLOSE) geterr ("expected close paren");
X   *dim = i; change[chg] = 1; } 
X
X
X#define D ((double) 648 / XSIZE)
X#define XX(x) (72 + ((x) * D))
X#define YY(y) (72 + ((y) * D))
X
Xstatic char *psdef[] = {
X   "/b { setgray moveto d 0 rlineto 0 d rlineto d neg 0 rlineto fill",
X   "/v { moveto d 0 rlineto stroke",
X   "/h { moveto 0 d rlineto stroke", 
X   "/x { moveto d d rlineto d neg 0 rmoveto d d neg rlineto stroke",
X   "/p { moveto e 0 rmoveto 0 d rlineto e neg dup rmoveto d 0 rlineto stroke",
X   0 };
Xstatic double climlut[] = { 0.00, 0.00, 0.00, 0.95, 0.95, 0.85, 0.70, 0.55,
X   0.40, 0.70, 0.70 };
Xextern double greyscale ();
X
X
Xpsprint (cra, lra, doclim)
X   unsigned char cra[MAXX][MAXY], lra[MAXX][MAXY]; int doclim; {
X   register int i, j, k; double z;
X   static int firstpage = 1;
X
X   if (firstpage) {
X      printf ("%%!PS-Adobe-1.0\n/d %4.2f def /e %4.2f def\n", D, D/2);
X      firstpage = 0;
X      for (i=0; psdef[i]; i++) printf ("%s } bind def\n", psdef[i]); }
X   printf ("%6.2f %6.2f moveto\n",         XX(-0.25),      YY(-0.25));
X   printf ("%6.2f %6.2f lineto\n",         XX(YSIZE+0.25), YY(-0.25));
X   printf ("%6.2f %6.2f lineto\n",         XX(YSIZE+0.25), YY(XSIZE+0.25));
X   printf ("%6.2f %6.2f lineto\n",         XX(-0.25),      YY(XSIZE+0.25));
X   printf ("%6.2f %6.2f lineto\nstroke\n", XX(-0.25),      YY(-0.25));
X
X   if (doclim) {
X      for (j=0; j<YSIZE;j++) for (i=0; i<XSIZE; i++) {
X         z = climlut[cra[i][j]];
X         if (z > 0.0) printf ("%6.2f %6.2f %5.4f b\n", XX(j), YY(i), z); }
X      printf ("0 setgray\n");
X      for (j=0; j<YSIZE;j++) for (i=0; i<XSIZE; i++) {
X         if (cra[i][j] == C_JUNGLE)
X            printf ("%6.2f %6.2f p\n", XX(j), YY(i));
X         if (cra[i][j] == C_SWAMP)
X            printf ("%6.2f %6.2f x\n", XX(j), YY(i)); } }
X
X   else for (j=0; j<YSIZE;j++) for (i=0; i<XSIZE; i++) {
X      z = greyscale (cra[i][j]);
X      if (z > 0.0) printf ("%6.2f %6.2f %5.4f b\n", XX(j), YY(i), z); }
X
X   printf ("0 setgray\n");
X   if (lra) for (j=0; j<YSIZE;j++) for (i=0; i<XSIZE; i++) {
X      if (lra[i][j] & LINE_0V) printf ("%6.2f %6.2f v\n", XX(j), YY(i));
X      if (lra[i][j] & LINE_0H) printf ("%6.2f %6.2f h\n", XX(j), YY(i)); }
X
X   printf ("1 setgray\n");
X   if (lra) for (j=0; j<YSIZE;j++) for (i=0; i<XSIZE; i++) {
X      if (lra[i][j] & LINE_1V) printf ("%6.2f %6.2f v\n", XX(j), YY(i));
X      if (lra[i][j] & LINE_1H) printf ("%6.2f %6.2f h\n", XX(j), YY(i)); }
X
X   printf ("\nshowpage\n"); }
END_OF_src/fileio.c
if test 12090 -ne `wc -c <src/fileio.c`; then
    echo shar: \"src/fileio.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/clim.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/clim.c\"
else
echo shar: Extracting \"src/clim.c\" \(5481 characters\)
sed "s/^X//" >src/clim.c <<'END_OF_src/clim.c'
X/* This program is Copyright (c) 1991 David Allen.  It may be freely
X   distributed as long as you leave my name and copyright notice on it.
X   I'd really like your comments and feedback; send e-mail to
X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
X   Avenue, Maynard, MA 01754. */
X
X/* This file contains all of the general-purpose routines which are not
X   machine specific: init, mainpar (called by fileio), onestep (called
X   by the machine-specific control routine), and the range-finding
X   function called by several computation routines. */
X
X#include "const.h"
X#include "clim.h"
X
X/* L holds the land values everybody starts with; lm is an edge map with
X   continents outlined in black and mountains outlined in white. */
Xunsigned char l[MAXX][MAXY], lm[MAXX][MAXY];
X
X
X/* These are the parameters used by all of the climate functions.  They are
X   described in params.doc. */
Xint XSIZE = MAXX, YSIZE = MAXY, BSIZE = MAXB;
Xint PRINTMODE = PRINTMODE_SHORT, MAXRANGE = 15;
Xint MAXSTEP = 10000, ZCOAST = 0;
X
Xint change[] = { 1, 1, 1, 1, 1, 1 }, step = 0;
Xextern int picktype;
X
X
Xinit (s) char *s; {
X   if (s && *s) getparams (s);
X   fileinit ();
X   heatcomp (); presscomp (); windcomp ();
X   raincomp (); climcomp (); }
X
X
Xonestep () {
X   switch (picktype) {
X      case M_HEAT:  heatdraw  (step % MAXB); break;
X      case M_PRESS: pressdraw (step % MAXB); break;
X      case M_WIND:  windraw   (step % MAXB); break;
X      case M_RAIN:  raindraw  (step % MAXB); break;
X      case M_CLIM:  climdraw  ();            break; } }
X   
X
Xmainpar (s) char *s; {
X   /* This function is called by getparams() in fileio.c; it looks at each
X   parameter name read from the input file.  If it recognizes the name,
X   the right function is called to set that parameter.  The function
X   returns true if it recognizes the parameter name, and false otherwise. */
X
X   if      (CMP ("LAND"))       getland ();
X   else if (CMP ("BSIZE"))      getlng  (&BSIZE,     M_MAIN);
X   else if (CMP ("MAXRANGE"))   getlng  (&MAXRANGE,  M_MAIN);
X   else if (CMP ("PRINTMODE"))  getlng  (&PRINTMODE, M_MAIN);
X   else if (heatpar  (s)) { }
X   else if (presspar (s)) { }
X   else if (windpar  (s)) { }
X   else if (rainpar  (s)) { }
X   else if (climpar  (s)) { }
X   else return (0);
X   return (1); }
X
X
Xgetland () { register int i, j, x;
X   /* This function is called by mainpar, above, when the LAND parameter
X   is encountered.  It just calls getmat in fileio.c to do the work, but
X   then it also creates an edge map lm; this is used by a couple of the
X   drawing routines as background. */
X
X   getmat  (&XSIZE, &YSIZE, M_MAIN, l);
X
X   for (j=0; j<YSIZE; j++) for (i=0, x=0; i<XSIZE; i++, x=0) {
X      /* Draw a white line if a mountain is present */
X      if (i) if ((l[i][j] == 2) != (l[i-1][j] == 2)) x |= LINE_1V;
X      if (j) if ((l[i][j] == 2) != (l[i][j-1] == 2)) x |= LINE_1H;
X
X      /* Draw a black line if a coast is present */
X      if (i) if ((l[i][j] > 0) != (l[i-1][j] > 0))   x |= LINE_0V;
X      if (j) if ((l[i][j] > 0) != (l[i][j-1] > 0))   x |= LINE_0H;
X
X      /* If both black and white lines are present, white wins */
X      if ((x & LINE_0V) && (x & LINE_1V)) x &= (~LINE_0V);
X      if ((x & LINE_0H) && (x & LINE_1H)) x &= (~LINE_0H);
X      lm[i][j] = x; } }
X
X
Xrange (rr) char rr[MAXX][MAXY]; {
X   /* This function is called by a number of climate routines.  It takes an
X   input array with blobs of -1's on a background of 0's.  The function winds
X   up replacing each 0 with the distance from that square to the nearest -1.
X   The function onerange() does all the work, but it will not compute ranges
X   greater than MAXRANGE.  Therefore, after onerange() is called, any remaining
X   0 values must be replaced with MAXRANGE, indicating that that square is
X   "very far" from any -1 value. */
X
X   register int i, j;
X
X   onerange (rr); checkmouse ();
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
X      if (!rr[i][j]) rr[i][j] = MAXRANGE; }
X
X
Xonerange (rr) char rr[MAXX][MAXY]; {
X   /* This routine consists of a loop.  Each time through the loop, every
X   square is checked.  If the square is zero, it has not yet been updated.
X   In that case, look to see if any adjacent squares were previously updated
X   (or if they were initialized to -1).  If so, set the square to the current
X   distance value, which happens to be identical to the outer loop variable.
X   If, after one loop iteration, no squares have been updated, the matrix
X   must be completely updated.  Stop.  To keep down run-time, a maximum
X   distance value, MAXRANGE, is used as the terminating loop value. */
X
X   register int i, j, x, k, keepgo;
X   for (k=1; k<MAXRANGE; k++) {
X      checkmouse ();
X      for (keepgo=0, j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
X         if (!rr[i][j]) {
X            keepgo = 1;
X            x = rr[i ? i-1 : XSIZE-1][j]; if (x && (x != k)) rr[i][j] = k;
X            x = rr[(i<XSIZE-1) ? i+1 : 0][j]; if (x && (x != k)) rr[i][j] = k;
X            if (j<YSIZE-1) { x = rr[i][j+1]; if (x && (x != k)) rr[i][j] = k; }
X            if (j) { x = rr[i][j-1]; if (x && (x != k)) rr[i][j] = k; } }
X      if (!keepgo) return (0); } return (0); }
X
X
Xstatus (n, i) int n, i; {
X   static char *title[] = { "", "Heat","Pressure","Wind","Rain","Climate" };
X   char t[256];
X   sprintf (t, "%s buffer %d", title[n], i); usermessage (t); }
X
X
Xdouble greyscale (x) int x; {
X   /* This function just returns the 0..1 equivalent of 0..255 */
X   return ((float) ((255 - x) / 320.0) + 0.1); }
END_OF_src/clim.c
if test 5481 -ne `wc -c <src/clim.c`; then
    echo shar: \"src/clim.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/heat.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/heat.c\"
else
echo shar: Extracting \"src/heat.c\" \(6893 characters\)
sed "s/^X//" >src/heat.c <<'END_OF_src/heat.c'
X/* This program is Copyright (c) 1991 David Allen.  It may be freely
X   distributed as long as you leave my name and copyright notice on it.
X   I'd really like your comments and feedback; send e-mail to
X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
X   Avenue, Maynard, MA 01754. */
X
X/* This file contains the routines that compute local temperatures */
X
X#include "const.h"
X#include "clim.h"
X
X/* Some private defines.  FREEZING is 0 degrees C in Kelvin; DEG2RAD is the
X   conversion factor from angular degrees to radians. */
X
X#define FREEZING 273.0
X#define PI 3.14159
X#define DEG2RAD (PI / 180)
X
X/* The input array is l, from main.c; lm is used by heatdraw().  The output
X   array is ts, containing temperatures.  Array t is an unscaled copy of the
X   temperatures; tmin and tmax are used for scaling, and tscale is the
X   computed scale factor.  To convert the unscaled temperatures to degrees K,
X   divide by TEMPSCALE. */
X
Xextern unsigned char l[MAXX][MAXY], lm[MAXX][MAXY];
Xunsigned char ts[MAXB][MAXX][MAXY];
Xint tt[MAXB][MAXX][MAXY], tmax, tmin;
Xdouble tscale; int TEMPSCALE = 10;
X
X/* These parameters are defined in main.c */
X
Xextern int BSIZE, XSIZE, YSIZE, PRINTMODE;
X
X/* These parameters are used here, and are described in params.doc */
X
Xint PRINTEMP = 0;
Xdouble TILT = 23.0, ECCENT = 0.0, ECCPHASE = 0.0;
Xdouble LCOS = 45.0, LCONST = 275.0, LTILT = 1.0, LSMOOTH = 0.6, LDIV = 180.0;
Xdouble OCOS = 30.0, OCONST = 275.0, OTILT = 0.2, OSMOOTH = 0.2, ODIV = 250.0;
X
X
Xheatpar (s) char *s; {
X   /* This function is called by mainpar() in main.c; it simply tests input
X   parameter names to see if they are defined in this file.  Each of the
X   above ints are defined in this file.  If the input string matches here,
X   the function returns true. */
X   if      (CMP ("TILT"))     getdbl  (&TILT,     M_HEAT);
X   else if (CMP ("ECCENT"))   getdbl  (&ECCENT,   M_HEAT);
X   else if (CMP ("ECCPHASE")) getdbl  (&ECCPHASE, M_HEAT);
X
X   else if (CMP ("LCOS"))     getdbl  (&LCOS,     M_HEAT);
X   else if (CMP ("LCONST"))   getdbl  (&LCONST,   M_HEAT);
X   else if (CMP ("LTILT"))    getdbl  (&LTILT,    M_HEAT);
X   else if (CMP ("LSMOOTH"))  getdbl  (&LSMOOTH,  M_HEAT);
X   else if (CMP ("LDIV"))     getdbl  (&LDIV,     M_HEAT);
X
X   else if (CMP ("OCOS"))     getdbl  (&OCOS,     M_HEAT);
X   else if (CMP ("OCONST"))   getdbl  (&OCONST,   M_HEAT);
X   else if (CMP ("OTILT"))    getdbl  (&OTILT,    M_HEAT);
X   else if (CMP ("OSMOOTH"))  getdbl  (&OSMOOTH,  M_HEAT);
X   else if (CMP ("ODIV"))     getdbl  (&ODIV,     M_HEAT);
X
X   else if (CMP ("PRINTEMP")) getlng  (&PRINTEMP, M_HEAT);
X   else return (0);
X   return (1); }
X
X
Xheatlut (x, s) int x; char *s; {
X   /* After the heatcomp routine is finished, a scale factor is computed
X   for converting degrees K to 0..255; this routine converts back.  Functions
X   in the machine-dependent code can call here to print map keys.  The caller
X   must provide a char buffer; a string containing degrees F is put there. */
X
X   double temp;
X
X   temp = (((double) x / tscale) + (double) tmin) / TEMPSCALE;
X   temp = (temp - FREEZING) * 1.8 + 32;
X   sprintf (s, "%6.1f", temp); }
X
X
Xheatcomp () {
X   /* This is the main routine for computing temperatures.  After getheat()
X   is called to do all the work, this routine takes the ints from t and
X   finds the smallest and largest values.  These are used to compute a scale
X   factor, tscale; the arrays ts are then filled with scaled values.  Finally,
X   putmat() from main.c is called if needed to print results. */
X
X   register int i, j, buf; char s[20];
X
X   getheat (); tmin = 32000; tmax = 0;
X
X   usermessage ("Scaling heat");
X   /* Find minimum and maximum across all buffers */
X   for (buf=0; buf<BSIZE; buf++) {
X      checkmouse ();
X      for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
X         if (tt[buf][i][j] < tmin) tmin = tt[buf][i][j];
X         if (tt[buf][i][j] > tmax) tmax = tt[buf][i][j]; } }
X
X   /* Compute scale; for every buffer, fill ts from t */
X   tscale = 254.0 / ((double) (tmax - tmin));
X   for (buf=0; buf<BSIZE; buf++) {
X      for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
X         ts[buf][i][j] = (tt[buf][i][j] - tmin) * tscale;
X      checkmouse (); }
X
X   if (PRINTEMP) {
X      if (PRINTMODE != PRINTMODE_GREY) {
X         printf ("(KEY-IN-FAREN (\n");
X         for (i=0; i<8; i++) { heatlut (16 * i, s); printf (" %s", s); }
X         printf ("\n");
X         for (i=8; i<16; i++) { heatlut (16 * i, s); printf (" %s", s); }
X         printf ("))\n"); }
X      for (i=0; i<BSIZE; i++)
X         putmat ("TEMPERATURE", i, PRINTMODE_SCALE, ts[i], lm); } }
X
X
Xheatdraw (n) int n; { draw (DRAW_GREY, LINE_CORN, ts[n], lm); }
X   /* This function calls draw() with the right arguments to display heat */
X
X
Xgetheat () {
X   /* This function does all the work for computing temperatures.  The outermost
X   loop goes through each row of the output array once, computing all buffers
X   at the same time.  The loop has two inner loops: first, tland and tsea are
X   filled with the temperatures found far inland and far at sea for each buffer.
X   In the second loop, the weight function for each point in the latitude line
X   is computed and the temperature is found for each buffer. */
X
X   register int buf, i, j;
X   double lat, lscl, sscl, x, fact, theta, delth, phase;
X   double tland[MAXB], tsea[MAXB];
X
X   lscl = DEG2RAD * 180.0 / (90.0 + LTILT * TILT);
X   sscl = DEG2RAD * 180.0 / (90.0 + OTILT * TILT);
X   delth = 2.0 * PI / (double) BSIZE;
X   for (j=0; j<YSIZE; j++) {
X      status (M_HEAT, j); checkmouse ();
X      lat = 90.0 - 180.0 * (double) j / (double) YSIZE;
X      for (buf=0, theta=0; buf<BSIZE; buf++, theta+=delth) {
X         phase = theta + ECCPHASE; if (phase > 2.0 * PI) phase -= (2 * PI);
X         fact = (1.0 + ECCENT * cos (phase)) * TEMPSCALE;
X         x = (lat + cos (theta) * TILT * LTILT) * lscl;
X         tland[buf] = (LCONST + LCOS * cos (x)) * fact;
X         x = (lat + cos (theta) * TILT * OTILT) * sscl;
X         tsea[buf]  = (OCONST + OCOS * cos (x)) * fact; }
X      for (i=0; i<XSIZE; i++) {
X         if (!l[i][j]) x = OSMOOTH + (countland (i, j) / ODIV);
X         else x = LSMOOTH + (countland (i, j) / LDIV);
X         for (buf=0; buf<BSIZE; buf++)
X            tt[buf][i][j] = tsea[buf] + (tland[buf] - tsea[buf]) * x; } } }
X
X
Xcountland (x, y) int x, y; {
X   /* Called by getheat() for each square, this function looks in a 11 wide
X   by 5 high box and counts the number of land squares found there.  It
X   compensates for y values off the map, and wraps x values around.   The
X   answer is returned. */
X
X   register int sum=0; int jmin, jmax, j1, i0, i1;
X
X   jmin = y - 2; if (jmin < 0) jmin = 0;
X   jmax = y + 2; if (jmax >= YSIZE) jmax = YSIZE-1;
X   for (j1=jmin; j1<=jmax; j1++) for (i0=-5; i0<6; i0++) {
X      i1 = i0 + x; if (i1 < 0) i1 += XSIZE;
X      if (i1 >= XSIZE) i1 -= XSIZE;
X      sum += l[i1][j1]; }
X   return (sum); }
END_OF_src/heat.c
if test 6893 -ne `wc -c <src/heat.c`; then
    echo shar: \"src/heat.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/pressure.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/pressure.c\"
else
echo shar: Extracting \"src/pressure.c\" \(9001 characters\)
sed "s/^X//" >src/pressure.c <<'END_OF_src/pressure.c'
X/* This program is Copyright (c) 1991 David Allen.  It may be freely
X   distributed as long as you leave my name and copyright notice on it.
X   I'd really like your comments and feedback; send e-mail to
X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
X   Avenue, Maynard, MA 01754. */
X
X/* This file contains the routines to compute global high and low
X   pressure areas. */
X
X#include "const.h"
X#include "clim.h"
X
X/* These are the data arrays required: l is an input array defining the
X   ocean, land and mountain areas; ts is the temperature array computed
X   by the functions in heat.c.  Array pr is filled by ocean(), land() and
X   heateq(), below; PR_HIGH indicates a high pressure zone, PR_LOW indicates
X   a low, and PR_HEQ indicates the heat equator, a low zone.  Array pm is
X   the output array for this file, and it contains an edge map which has
X   edges in color 1 surrounding lows and color 0 around highs.  Array r is
X   temporary storage for local calls to range() in main.c. */
X
Xextern unsigned char l[MAXX][MAXY], ts[MAXB][MAXX][MAXY];
Xstatic char r[MAXX][MAXY];
Xstatic unsigned char pm[MAXB][MAXX][MAXY];
Xunsigned char pr[MAXB][MAXX][MAXY];
X
X
X/* The externs below are declared in main.c; they represent global parameters.
X   The ints are described in params.doc. */
X
Xextern int BSIZE, XSIZE, YSIZE, PRINTMODE;
Xint OOTHRESH = 5, OLTHRESH = 1, LOTHRESH = 3, LLTHRESH = 7;
Xint OHMIN = 130, OHMAX = 180, OLMIN =  40, OLMAX =  65;
Xint LHMIN =   0, LHMAX =  20, LLMIN = 220, LLMAX = 255;
Xint PRINTPR = 0;
X
X
Xpresspar (s) char *s; {
X   /* This function is called by mainpar() in main.c; it simply tests input
X   parameters to see if they are defined in this file.  Each of the above
X   ints is referred to in this function.  If an input string matches here,
X   the function returns true. */
X   if      (CMP ("OOTHRESH")) getlng  (&OOTHRESH, M_PRESS);
X   else if (CMP ("OLTHRESH")) getlng  (&OLTHRESH, M_PRESS);
X   else if (CMP ("OHMIN"))    getlng  (&OHMIN,    M_PRESS);
X   else if (CMP ("OHMAX"))    getlng  (&OHMAX,    M_PRESS);
X   else if (CMP ("OLMIN"))    getlng  (&OLMIN,    M_PRESS);
X   else if (CMP ("OLMAX"))    getlng  (&OLMAX,    M_PRESS);
X
X   else if (CMP ("LOTHRESH")) getlng  (&LOTHRESH, M_PRESS);
X   else if (CMP ("LLTHRESH")) getlng  (&LLTHRESH, M_PRESS);
X   else if (CMP ("LHMIN"))    getlng  (&LHMIN,    M_PRESS);
X   else if (CMP ("LHMAX"))    getlng  (&LHMAX,    M_PRESS);
X   else if (CMP ("LLMIN"))    getlng  (&LLMIN,    M_PRESS);
X   else if (CMP ("LLMAX"))    getlng  (&LLMAX,    M_PRESS);
X
X   else if (CMP ("PRINTPR"))  getlng  (&PRINTPR,  M_PRESS);
X   else return (0);
X   return (1); }
X
X
Xpresscomp () {
X   /* The main routine for this file.  It just calls the four routines
X   which do all the work.  Ocean() finds pressure extremes on the ocean;
X   land() does the same for land; heateq() defines the heat equator, and
X   setpm() computes pm[][] from pr[][]. */
X
X   int buf;
X
X   for (buf=0; buf<BSIZE; buf++) {
X      status (M_PRESS, buf); ocean (buf); land (buf);
X      checkmouse (); findheq (buf); setpm (buf); }
X   if (PRINTPR) for (buf=0; buf<BSIZE; buf++) {
X      if (PRINTMODE == PRINTMODE_GREY)
X         putmat ("PRESSURE", buf, PRINTMODE_SHORT, l, pm[buf]);
X      else putmat ("PRESSURE", buf, PRINTMODE_SHORT, pr[buf], 0); } }
X
X
Xpressdraw (n) int n; { draw (DRAW_LAND, LINE_CORN, l, pm[n]); }
X   /* This function calls draw with the right arguments to display pressure */
X
X
Xocean (buf) int buf; {
X   /* Determine ocean highs and lows.  An ocean high or low must occur over
X   ocean, far away from major land masses.  Two calls to range() are made
X   to find the qualifying ocean areas; then temperature criteria are used
X   to select the actual pressure zones. */
X
X   register int i, j; int x;
X
X   /* Set r to the distance on land from the coast. */
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) r[i][j] = l[i][j] ? 0 : -1;
X   range (r);
X
X   /* Initialize r to contain blobs on land which are at least OLTHRESH squares
X      away from the coast.  Then set r to the distance from these.  The result
X      in r is the distance from the nearest big piece of land (ignoring
X      islands). */
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
X      r[i][j] = (r[i][j] > OLTHRESH) ? -1 : 0;
X   range (r);
X
X   /* For each array element, if it is at least OOTHRESH squares from the
X      nearest big piece of land, it might be the center of an ocean pressure
X      zone.  The pressure zones are defined by temperature ranges; if the
X      temperature in ts is between OLMIN and OLMAX, a low is recorded, while
X      if the temperature is between OHMIN and OHMAX, a high is recorded. */
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
X      pr[buf][i][j] = 0; x = ts[buf][i][j];
X      if (r[i][j] > OOTHRESH) {
X         if ((x >= OLMIN) && (x <= OLMAX)) pr[buf][i][j] = PR_LOW;
X         if ((x >= OHMIN) && (x <= OHMAX)) pr[buf][i][j] = PR_HIGH; } } }
X
X
Xland (buf) int buf; {
X   /* This function is simply the complement of ocean(): it finds land highs
X   and lows.  A land high or low must occur over land, far from major oceans.
X   Two calls to range() are made to find the qualifying land areas; then
X   temperature criteria are used to select the actual pressure zones. */
X
X   register int i, j; int x;
X
X   /* Set r to distance on water from coast. */
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) r[i][j] = l[i][j] ? -1 : 0;
X   range (r);
X
X   /* Initialize r to contain blobs on ocean which are at least LOTHRESH
X      squares away from the coast.  Then set r to the distance from these.  The
X      result in r is the distance from the nearest ocean, ignoring lakes. */
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
X      r[i][j] = (r[i][j] > LOTHRESH) ? -1 : 0;
X   range (r);
X
X   /* For each array element, if it is at least LLTHRESH squares from the
X      nearest large ocean, it might be the center of a land pressure zone.
X      The pressure zones are defined by temperature ranges; if the temperature
X      in ts is between LLMIN and LLMAX, a low is recorded, while if the
X      temperature is between LHMIN and LHMAX, a high is recorded. */
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
X      x = ts[buf][i][j];
X      if (r[i][j] > LLTHRESH) {
X         if ((x >= LLMIN) && (x <= LLMAX)) pr[buf][i][j] = PR_LOW;
X         if ((x >= LHMIN) && (x <= LHMAX)) pr[buf][i][j] = PR_HIGH; } } }
X
X
Xfindheq (buf) int buf; {
X   /* This function finds the heat equator and marks it in pr.  For each
X   vertical column of ts, the median position is found and marked.  To
X   make the heat equator continuous, jlast is set to the position of the
X   heat equator in the previous column; a connection is made in the present
X   column to ensure continuity. */
X
X   register int i, j; int sum, jlast = 0, jnext;
X
X   for (i=0; i<XSIZE; i++) {
X      /* Find the total of the temperatures in this column */
X      for (sum=0, j=0; j<YSIZE; j++) sum += ts[buf][i][j];
X
X      /* Step through the column again until the total so far is exactly
X         half the total for the column.  This is the median position. */
X      for (sum>>=1, j=0; j<YSIZE && sum>0; j++) sum -= ts[buf][i][j];
X
X      /* Mark this position and remember it with jnext */
X      pr[buf][i][j] = PR_HEQ; jnext = j;
X
X      /* For each column except the first (where i = 0), if the last heat
X         equator is above this one, move upwards to it, marking each square,
X         to ensure continuity; if below this one, move downwards to it. */
X
X      if (i && (j > jlast)) for (; j>=jlast; j--) pr[buf][i][j] = PR_HEQ;
X      else if (i && (j < jlast)) for (; j<=jlast; j++) pr[buf][i][j] = PR_HEQ;
X
X      /* Remember this position for the next column.  Note that no check is
X         done to ensure continuity at the wraparound point; this is bad. */
X      jlast = jnext; } }
X
X
Xsetpm (buf) int buf; {
X   /* Setpm() is called after the above three functions have filled pr with
X   the codes for high, low and heat equator.  The purpose of this function
X   is to create an edge map surrounding lows with color 1 and highs with
X   color 0. */
X
X   register int i, j, k; int col;
X
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
X      k = pr[buf][i][j]; col = 0;
X
X      /* If not at the top edge, and if the pressure status here is not equal
X         to the pressure status one square up, then put a horizontal line in
X         this square.  The color is zero if there is a high here; if a low or
X         heat equator (a type of low) is here, the color is one. */
X      if (j) if (k != pr[buf][i][j-1]) col =
X         ((k == PR_HIGH) || (pr[buf][i][j-1] == PR_HIGH)) ? LINE_0H : LINE_1H;
X      /* Similarly, if not at the left edge, put a vertical line in the right
X         color.  Notice that this color is OR'ed with the previous color. */
X      if (i) if (k != pr[buf][i-1][j]) col |=
X         ((k == PR_HIGH) || (pr[buf][i-1][j] == PR_HIGH)) ? LINE_0V : LINE_1V;
X
X      /* Set the square in the pm array to the resultant color */
X      pm[buf][i][j] = col; } }
X
END_OF_src/pressure.c
if test 9001 -ne `wc -c <src/pressure.c`; then
    echo shar: \"src/pressure.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/wind.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/wind.c\"
else
echo shar: Extracting \"src/wind.c\" \(5268 characters\)
sed "s/^X//" >src/wind.c <<'END_OF_src/wind.c'
X/* This program is Copyright (c) 1991 David Allen.  It may be freely
X   distributed as long as you leave my name and copyright notice on it.
X   I'd really like your comments and feedback; send e-mail to
X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
X   Avenue, Maynard, MA 01754. */
X
X/* This file contains the wind computation routines. */
X
X#include "const.h"
X#include "clim.h"
X#define MAXPRESS 255
X
X/* Input arrays are pr, from pressure.c, and l, from main.c.  The array
X   hl is used as temporary storage for highs and lows, while p is used
X   to store the smoothed pressure map.  The output array, wd, contains
X   an edge map with wind directions. */
X
Xextern unsigned char pr[MAXB][MAXX][MAXY], l[MAXX][MAXY];
Xunsigned char wd[MAXB][MAXX][MAXY];
Xstatic char hl[2][MAXX][MAXY];
Xstatic unsigned char p[MAXX][MAXY];
X
X/* The externs below are parameters defined in main.c.  The other two ints
X   are parameters described in params.doc. */
X
Xextern int XSIZE, YSIZE, BSIZE, PRINTMODE;
Xint BARSEP = 16, PRINTWIND = 0;
X
X
Xwindpar (s) char *s; {
X   /* This function is called by mainpar() in main.c; it simply checks to
X   see if the parameter is defined in this file.  If so, it returns true. */
X   if (CMP ("BARSEP")) getlng (&BARSEP, M_WIND);
X   else if (CMP ("PRINTWIND")) getlng (&PRINTWIND, M_WIND);
X   else return (0);
X   return (1); }
X
X
Xwindcomp () {
X   /* This is the main function in this file; it calls getpress() to create
X   a smoothed pressure map, then getwind() to put isobars (wind lines) on
X   the output map.  The last step makes sure that contradictory winds are
X   removed, such as N and S winds in the same square. */
X
X   register int i, j, x, buf;
X
X   for (buf=0; buf<BSIZE; buf++) {
X      status (M_WIND, buf); getpress (buf); getwind (buf);
X      for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
X         x = wd[buf][i][j];
X         if (x & N) x &= (~S); if (x & E) x &= (~W);
X         wd[buf][i][j] = x; } }
X
X   if (PRINTWIND) for (buf=0; buf<BSIZE; buf++) {
X      if (PRINTMODE == PRINTMODE_GREY) 
X         putmat ("WIND", buf, PRINTMODE_SHORT, l, wd[buf]);
X      else putmat ("WIND", buf, PRINTMODE_SHORT, wd[buf], 0); } }
X
X
Xwindraw (n) int n; { draw (DRAW_LAND, LINE_DIAG, l, wd[n]); }
X   /* This function calls draw with the right arguments to display wind */
X
X
Xgetpress (buf) int buf; {
X   /* This function takes the high and low markings from pressure.c and creates
X   a smoothed function.  Highs turn into MAXPRESS and lows turn into 0. */
X
X   register int i, j;
X
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
X      /* Zero out the arrays to be used */
X      wd[buf][i][j] = 0; hl[0][i][j] = 0; hl[1][i][j] = 0;
X
X      /* Fill hl[0] with the low pressure zones, and hl[1] with highs */
X      if      (pr[buf][i][j] == PR_LOW)  hl[0][i][j] = -1;
X      else if (pr[buf][i][j] == PR_HIGH) hl[1][i][j] = -1;
X      else if (pr[buf][i][j] == PR_HEQ)  hl[0][i][j] = -1; }
X
X   /* Set each square in hl[0] to the distance from that square to the */
X   /* nearest low, and each square in hl[1] to the distance to a high. */
X   range (hl[0]); range (hl[1]);
X
X   /* The final pressure, in array p, is zero if a low is there and */
X   /* MAXPRESS if a high is there.  Otherwise, the pressure in a square is */
X   /* proportional to the ratio of (distance from the square to the nearest */
X   /* low) to (total of distance from nearest high and nearest low).  This */
X   /* gives a smooth curve between the extremes. */
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
X      if (hl[1][i][j] == -1) p[i][j] = MAXPRESS;
X      else if (hl[0][i][j] == -1) p[i][j] = 0;
X      else p[i][j] = (MAXPRESS*hl[0][i][j]) / (hl[0][i][j] + hl[1][i][j]); } }
X
X
Xgetwind (buf) int buf; {
X   /* This function draws isobars around the pressure map created above.  These
X   isobars are the directions of wind flow.  The isobars are given a direction
X   depending on whether the square is above or below the heat equator; north of
X   the heat equator, the winds blow counterclockwise out from a low, while
X   south of it, the opposite is true. */
X
X   register int i, j; int a, b, e, bar;
X
X   /* Step from 0 to MAXPRESS by BARSEP; bar is the pressure for which this */
X   /* isobar will be drawn. */
X   for (bar=BARSEP; bar<=MAXPRESS; bar+=BARSEP) {
X      checkmouse ();
X      for (i=0; i<XSIZE; i++) for (e=0, j=0; j<YSIZE; j++) {
X
X         /* Set e if this square is south of the heat equator */
X         a = p[i][j]; if (pr[buf][i][j] == 3) e = 1;
X
X         /* Provided the square is not at the top of the array, compare the */
X         /* pressure here to the pressure one square up.  This gives the */
X         /* direction of the wind in terms of east / west flow. */
X         if (j) {
X            b = p[i][j-1];
X            if ((a < bar) && (b >= bar)) wd[buf][i][j] |= (e ? E : W);
X            if ((a >= bar) && (b < bar)) wd[buf][i][j] |= (e ? W : E); }
X
X         /* Compare the pressure here to the pressure one square to the left */
X         /* (including wraparound); this gives the wind direction in terms */
X         /* of north / south flow. */
X         b = i ? p[i-1][j] : p[XSIZE-1][j];
X         if ((a < bar) && (b >= bar)) wd[buf][i][j] |= (e ? N : S);
X         if ((a >= bar) && (b < bar)) wd[buf][i][j] |= (e ? S : N); } } }
END_OF_src/wind.c
if test 5268 -ne `wc -c <src/wind.c`; then
    echo shar: \"src/wind.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/rain.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/rain.c\"
else
echo shar: Extracting \"src/rain.c\" \(7151 characters\)
sed "s/^X//" >src/rain.c <<'END_OF_src/rain.c'
X/* This program is Copyright (c) 1991 David Allen.  It may be freely
X   distributed as long as you leave my name and copyright notice on it.
X   I'd really like your comments and feedback; send e-mail to
X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
X   Avenue, Maynard, MA 01754. */
X
X/* This file contains the routines to compute rainfall. */
X
X#include "const.h"
X#include "clim.h"
X
X/* The input data arrays are l and lm, from main.c, wd, from wind.c,
X   and pr, from pressure.c.  Output arrays are rm and rn; fr and fs are
X   used as temporary storage. */
X
Xextern unsigned char l[MAXX][MAXY], lm[MAXX][MAXY], wd[MAXB][MAXX][MAXY];
Xextern unsigned char pr[MAXB][MAXX][MAXY];
Xunsigned char rn[MAXB][MAXX][MAXY];
Xstatic unsigned char fr[2][MAXX][MAXY], fs[MAXX][MAXY];
X
X
X/* The externs below are parameters defined in main.c; the ints are
X   parameters defined here. */
X
Xextern int BSIZE, XSIZE, YSIZE;
Xint MAXFETCH = 5, RAINCONST = 32, LANDEL = 10, MOUNTDEL = 32, FETCHDEL = 4;
Xint NRFDEL = 3, HEQDEL = 32, NRHEQDEL = 24, FLANKDEL = -24, PRINTRAIN = 0;
X
X
Xrainpar (s) char *s; {
X   /* This function is called by mainpar() in main.c; it simply tests input
X   parameter names to see if they are defined in this file.  Each of the
X   above ints are defined in this file.  If the input string matches here,
X   the function returns true. */
X
X   if      (CMP ("MAXFETCH"))  getlng  (&MAXFETCH,  M_RAIN);
X   else if (CMP ("RAINCONST")) getlng  (&RAINCONST, M_RAIN);
X   else if (CMP ("LANDEL"))    getlng  (&LANDEL,    M_RAIN);
X   else if (CMP ("MOUNTDEL"))  getlng  (&MOUNTDEL,  M_RAIN);
X   else if (CMP ("FETCHDEL"))  getlng  (&FETCHDEL,  M_RAIN);
X   else if (CMP ("HEQDEL"))    getlng  (&HEQDEL,    M_RAIN);
X   else if (CMP ("NRHEQDEL"))  getlng  (&NRHEQDEL,  M_RAIN);
X   else if (CMP ("FLANKDEL"))  getlng  (&FLANKDEL,  M_RAIN);
X   else if (CMP ("NRFDEL"))    getlng  (&NRFDEL,    M_RAIN);
X   else if (CMP ("PRINTRAIN")) getlng  (&PRINTRAIN, M_RAIN);
X   else return (0);
X   return (1); }
X
X
Xraincomp () {
X   /* This is the main rain computation function.  It calls the functions
X   getfetch () and getrain () to do all the work for each buffer, then
X   prints out the results if needed. */
X
X   register int buf;
X
X   for (buf=0; buf<BSIZE; buf++) {
X      status (M_RAIN, buf); checkmouse (); 
X      getfetch (buf); checkmouse (); getrain (buf); }
X
X   if (PRINTRAIN) for (buf=0; buf<BSIZE; buf++)
X      putmat ("RAIN", buf, PRINTMODE_SCALE, rn[buf], lm); }
X
X
Xraindraw (n) int n; { draw (DRAW_GREY, LINE_CORN, rn[n], lm); }
X   /* This function calls draw with the right arguments to display rain */
X
X
Xfetchinc (x, y, dest) int x, y, dest; {
X   /* This is the workhorse function for getfetch(), below.  It is called
X   several times per square.  It changes x to account for wraparound, so it
X   won't work as a macro.  If y is out of range it does nothing, else it
X   "marks" the new square in fr[dest] and increments fs to record the number
X   of times the square has been marked. */
X
X   if (x == -1) x = XSIZE-1; else if (x == XSIZE) x = 0;
X   if ((y == -1) || (y == YSIZE)) return (0);
X   fr[dest][x][y] = 1; fs[x][y]++; return (0); }
X
X
Xgetfetch (buf) int buf; {
X   /* "Fetch" is the term that describes how many squares a given wind line
X   travels over water.  It measures how moist the wind is.  The algorithm to
X   measure fetch looks like many simultaneous tree walks, where each water
X   square is a root square, and every wind edge is a tree edge.  A counter
X   for each square determines how many times that square is reached during
X   the tree walks; that is the fetch. */
X
X   register int i, j, k; int src, dest;
X
X   /* Initialize the counter fs to zero.  Array fr, which records the */
X   /* list of active edges in the walks, is set so that all ocean squares */
X   /* are active.  Also, the result array rn is cleared. */
X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
X      fr[0][i][j] = l[i][j] ? 0 : 1; fs[i][j] = 0; rn[buf][i][j] = 0; }
X
X   /* Each time through the loop, each square is examined.  If it's */
X   /* active, disable the mark in the current time step (thus ensuring */
X   /* that when the buffers are flipped, the new destination is empty). */
X   /* If the square is a mountain, don't pass the mark, but instead add */
X   /* some amount to the square -- implementing rain shadows and rainy */
X   /* mountain squares.  Finally, for each of the eight cardinal */
X   /* directions, if there is wind blowing in that direction, carry a */
X   /* marker to that square using fetchinc(), above. */
X
X   for (k=0; k<MAXFETCH; k++) {
X      src = k % 2; dest = 1 - src;
X      for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) if (fr[src][i][j]) {
X         fr[src][i][j] = 0;
X         if (l[i][j] == 2) rn[buf][i][j] += MOUNTDEL;
X         else switch (wd[buf][i][j]) {
X            case N|E: fetchinc (i+1, j-1, dest); break;
X            case N|W: fetchinc (i-1, j-1, dest); break;
X            case S|E: fetchinc (i+1, j+1, dest); break;
X            case S|W: fetchinc (i-1, j+1, dest); break;
X            case N:   fetchinc (i,   j-1, dest); break;
X            case S:   fetchinc (i,   j+1, dest); break;
X            case E:   fetchinc (i+1, j,   dest); break;
X            case W:   fetchinc (i-1, j,   dest); break; } } } }
X
X
X/* This macro is called several times per square by getrain(), below.  It
X   simply tests the square for several conditions: if the square is on the
X   heat equator, itcz is set to one; if the wind blows south in this square,
X   it is on the flank of a circular wind zone (and thus less rainy); the local
X   rain sum, x, is increased according to the fetch sum in the square. */
X#define RAINTEST(xx,yy) \
X   if (pr[buf][xx][yy] == PR_HEQ) itcz = 1; \
X   if (wd[buf][xx][yy] & S) flank = 1; \
X   x += (fs[xx][yy] * NRFDEL);
X
X
Xgetrain (buf) int buf; {
X   /* Once the fetch array is computed, this function looks at each square to
X   determine the amount of rainfall there.  The above macro is called five
X   times, once for the square and each of its four neighbors; this determines
X   whether the square is near the ITCZ or the flank of an air cycle.  The
X   sum of fetches for the neighbors is also determined.   Finally, each of the
X   factors is weighted and added to the rainfall value:  the local fetch value,
X   a land factor, the nearness of the heat equator, and the nearness of a
X   flank.  Note that while rn is zeroed in getfetch(), it may be increased by
X   rain falling on mountains, so it is nonzero when this function is called. */
X
X   register int i, j, x; int itcz, flank;
X
X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
X      flank = 0; itcz = 0; x = rn[buf][i][j];
X      if (i < XSIZE-1) { RAINTEST (i+1, j) } else { RAINTEST (0, j) }
X      if (i) { RAINTEST (i-1, j) } else { RAINTEST (XSIZE-1, j) }
X      if (j < YSIZE-1) { RAINTEST (i, j+1) }
X      if (j) { RAINTEST (i, j-1) }
X      RAINTEST (i, j);
X
X      x += (RAINCONST + FETCHDEL * fs[i][j]);
X      if (l[i][j]) x += LANDEL;
X      if (pr[buf][i][j] == PR_HEQ) x += HEQDEL;
X      if (itcz) x += NRHEQDEL;
X      if (flank) x += FLANKDEL;
X      if (x < 0) x = 0; if (x> 255) x = 255;
X      rn[buf][i][j] = x; } }
END_OF_src/rain.c
if test 7151 -ne `wc -c <src/rain.c`; then
    echo shar: \"src/rain.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f src/climate.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"src/climate.c\"
else
echo shar: Extracting \"src/climate.c\" \(4025 characters\)
sed "s/^X//" >src/climate.c <<'END_OF_src/climate.c'
X/* This program is Copyright (c) 1991 David Allen.  It may be freely
X   distributed as long as you leave my name and copyright notice on it.
X   I'd really like your comments and feedback; send e-mail to
X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
X   Avenue, Maynard, MA 01754. */
X
X/* This file contains the routines that compute local climate */
X
X#include "const.h"
X#include "clim.h"
X
X
X/* Input arrays are l from main.c, rn from rain.c, and t from heat.c.  Note
X   that the unscaled temperatures are used.  The output array is cl.  Array
X   lm (from main.c) is used by the drawing routine.*/
X
Xextern unsigned char l[MAXX][MAXY], lm[MAXX][MAXY], rn[MAXB][MAXX][MAXY];
Xextern int tt[MAXB][MAXX][MAXY];
Xunsigned char cl[MAXX][MAXY];
X
X
X/* These parameters are defined in main.c or heat.c */
Xextern int BSIZE, XSIZE, YSIZE, TEMPSCALE, PRINTMODE;
X
X/* These parameters are used here, and are described in params.doc */
Xint tempcut[] = { 0, 40, 90, 120 }, raincut[] = { 40, 60, 110, 160, 180 };
Xint PRINTCLIM = 0, MTDELTA = 20, TCSIZE = 4, RCSIZE = 5;
Xdouble ICEBERGK = 263.0;
X
X
X/* This array is the heart of the climate routine; temperature increases
X   going down the array, and rainfall increases going from left to right. */
X
Xstatic unsigned char climkey[4][5] = {
X   { C_TUNDRA, C_TUNDRA, C_TUNDRA, C_TUNDRA, C_TUNDRA },
X   { C_STEPPE, C_STEPPE, C_DECID,  C_DECID,  C_DECID  },
X   { C_DESERT, C_SAVANA, C_DECID,  C_JUNGLE, C_SWAMP  },
X   { C_DESERT, C_SAVANA, C_JUNGLE, C_SWAMP,  C_SWAMP  } };
X
X
Xclimpar (s) char *s; {
X   /* This function is called by mainpar() in main.c; it simply tests input
X   parameter names to see if they are defined in this file.  Each of the
X   above ints are defined in this file.  If the input string matches here,
X   the function returns true. */
X   if      (CMP ("ICEBERGK"))    getdbl  (&ICEBERGK,        M_CLIM);
X   else if (CMP ("PRINTCLIM"))   getlng  (&PRINTCLIM,       M_CLIM);
X   else if (CMP ("TEMPCUT"))     getlvec (&TCSIZE, tempcut, M_CLIM);
X   else if (CMP ("RAINCUT"))     getlvec (&RCSIZE, raincut, M_CLIM);
X   else if (CMP ("MTDELTA"))     getlng  (&MTDELTA,         M_CLIM);
X   else if (CMP ("PRINTCLIM"))   getlng  (&PRINTCLIM,       M_CLIM);
X   else return (0);
X   return (1); }
X
X
Xclimdraw () { draw (DRAW_CLIM, LINE_CORN, cl, lm); }
X   /* This routine calls draw with the proper arguments to display climate */
X
X
Xclimcomp () {
X   /* The outer loop looks at each square.  If it is ocean, the climate will
X   be ocean unless the temperature is below ICEBREGK degrees all year round.
X   If it is land, then the average rainfall and temperature (in Farenheit) are
X   computed for the square.  If the square is mountain, it is colder; the
X   temperature is decreased.  These two figures are then turned into array
X   indices by using the tempcut and raincut parameter vectors.  The climate
X   for the square is then simply a table lookup.  Finally, the array is printed
X   if desired. */
X
X   register int i, j, buf;
X   int noice, avetemp, averain, ttt, r;
X
X   usermessage ("Computing climate"); checkmouse ();
X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
X      if (!l[i][j]) { /* ocean */
X         for (noice=0, buf=0; buf<BSIZE; buf++)
X            noice |= (tt[buf][i][j] > TEMPSCALE * ICEBERGK);
X         cl[i][j] = noice ? C_OCEAN : C_OCEANICE; }
X      else { /* land or mountain */
X         for (averain=0, avetemp=0, buf=0; buf<BSIZE; buf++) {
X            averain += rn[buf][i][j]; avetemp += tt[buf][i][j]; }
X         averain /= BSIZE; avetemp /= BSIZE;
X         avetemp = ((double) (avetemp / TEMPSCALE) - 273.0) * 1.8 + 32.0;
X         if (l[i][j] == 2) avetemp -= MTDELTA;
X         ttt = 0; while ((avetemp > tempcut[ttt]) && (ttt < TCSIZE-1)) ttt++;
X         r  = 0; while ((averain > raincut[r])  && (r  < RCSIZE-1)) r++;
X         cl[i][j] = climkey[ttt][r]; } }
X   if (PRINTCLIM) {
X      if (PRINTMODE == PRINTMODE_GREY)
X         putmat ("CLIMATE", -1, PRINTMODE_CLIM, cl, lm);
X      else putmat ("CLIMATE", -1, PRINTMODE_SHORT, cl, lm); } }
END_OF_src/climate.c
if test 4025 -ne `wc -c <src/climate.c`; then
    echo shar: \"src/climate.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of archive 3 \(of 4\).
cp /dev/null ark3isdone
MISSING=""
for I in 1 2 3 4 ; do
    if test ! -f ark${I}isdone ; then
	MISSING="${MISSING} ${I}"
    fi
done
if test "${MISSING}" = "" ; then
    echo You have unpacked all 4 archives.
    rm -f ark[1-9]isdone
else
    echo You still need to unpack the following archives:
    echo "        " ${MISSING}
fi
##  End of shell archive.
exit 0

exit 0 # Just in case...
-- 
Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
Sterling Software, IMD           UUCP:     uunet!sparky!kent
Phone:    (402) 291-8300         FAX:      (402) 291-4362
Please send comp.sources.misc-related mail to kent@uunet.uu.net.