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 (<ILT, 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.