home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / misc / volume18 / planet / part03 < prev    next >
Internet Message Format  |  1991-04-10  |  55KB

  1. From: allen@viewlogic.com (Dave Allen)
  2. Newsgroups: comp.sources.misc
  3. Subject: REPOST: v18i003:  planet - planet generation simulator, Part03/04
  4. Message-ID: <1991Apr9.041754.8090@sparky.IMD.Sterling.COM>
  5. Date: 9 Apr 91 04:17:54 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: 9e87f929 1fb6a493 125dafc0 59ca8a0d
  8.  
  9. Submitted-by: Dave Allen <allen@viewlogic.com>
  10. Posting-number: Volume 18, Issue 3
  11. Archive-name: planet/part03
  12. Supersedes: tec: Volume 10, Issue 77-78
  13.  
  14. #! /bin/sh
  15. # into a shell via "sh file" or similar.  To overwrite existing files,
  16. # type "sh file -c".
  17. # The tool that generated this appeared in the comp.sources.unix newsgroup;
  18. # send mail to comp-sources-unix@uunet.uu.net if you want that tool.
  19. # Contents:  ./doc/about.tec ./src/clim.c ./src/heat.c ./src/pressure.c
  20. #   ./src/tec1.c ./src/x.c
  21. # Wrapped by kent@sparky on Mon Apr  8 22:39:15 1991
  22. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  23. echo If this archive is complete, you will see the following message:
  24. echo '          "shar: End of archive 3 (of 4)."'
  25. if test -f './doc/about.tec' -a "${1}" != "-c" ; then 
  26.   echo shar: Will not clobber existing file \"'./doc/about.tec'\"
  27. else
  28.   echo shar: Extracting \"'./doc/about.tec'\" \(10300 characters\)
  29.   sed "s/^X//" >'./doc/about.tec' <<'END_OF_FILE'
  30. XI.  MOTIVATION AND APPROACH
  31. X
  32. XI wanted to write a program to generate maps of many imaginary worlds using
  33. Xa microcomputer.  Fractal techniques produce unacceptably random-looking maps.
  34. XIn other related fields, people have used simplified models of physical
  35. Xprocesses and then tweaked the model parameters to give results that "looked
  36. Xright".  Dole [1] simulated accretion of planets around stars.  Hart [2]
  37. Xsimulated the evolution of a planetary atmosphere.  Forrester [3] simulated
  38. Xpopulation dynamics for near-future Earth.  My approach was to find a physical
  39. Xmodel for continent formation, and then write a program to implement that model.
  40. X
  41. XGeologists have proposed [4] that several times in history, the continents
  42. Xof Earth have drifted together to form a single "supercontinent", which later
  43. Xbroke apart.  A recent paper [5] suggested a physical model for this
  44. X"supercontinent cycle", and I used that model for my program.
  45. X
  46. XTheir hypothesis runs like this.  (Disclaimer - I don't know anything about
  47. Xgeology except what I got from reading a few papers.)  The Earth generates
  48. Xheat by radioactive decay; this heat is conducted away more slowly by
  49. Xcontinental crust than by oceanic crust.  Heat accumulates under large
  50. Xcontinents, causing them to dome upwards and eventually break apart.  After
  51. Xa certain amount of heat has escaped through the new ocean basin, the
  52. Xcontinental fragments are drawn back together by the subsiding basin.
  53. XOver long periods of time, many oceans should open and close in the center
  54. Xof the land area, while the original superocean should remain about the same.
  55. X
  56. XAny map of the Earth shows evidence to support this hypothesis.  The Atlantic
  57. Xand Mediterranean oceans are fairly recent, while the Pacific could be
  58. Xconsidered the superocean.  The Himalayas, the Pyrenees, and the Ukraine
  59. Xmountain ranges could have been formed by collisions between continental
  60. Xfragments.  The "Ring of Fire" around the Pacific represents subduction zones
  61. Xwhere new mountains, such as the Rockies, are forming as the continents drift
  62. Xfurther apart.  The older, lower Appalachian mountains might have been created
  63. Xduring a collision between Europe and North America in the last supercontinent
  64. Xcycle.
  65. X
  66. X
  67. XII.  REPRESENTATION
  68. X
  69. XOne data structure well-suited for storing topographic maps is a simple
  70. Xtwo-dimensional array, where each array element represents the height
  71. Xof the terrain at that point.  However, the Earth is spherical and a sphere
  72. Xcan't be mapped onto a plane without some distortion.  After trying many
  73. Xmapping methods, I came back to the simplest:  I pretend Columbus was wrong,
  74. Xand the world really is flat.  Since the continents in the physical model
  75. Xdrift toward and away from some central point, it is reasonable, if the map
  76. Xis large enough, to simply throw away the land area that falls off the
  77. Xedge of the map.  I used a simple square, flat surface with no "wraparound."
  78. X
  79. XI could, and probably will at some point, write a couple of paragraphs about
  80. Xwhy doing plate movement on a sphere is so hard.  All of the methods I
  81. Xtried required too much data storage for each point, or too much real
  82. Xnumber computation, or resulted in unacceptable distortion.  The criterion
  83. XI used was to place a small continent, say a 5 x 5 square, anywhere on
  84. Xthe surface.  It should be able to travel one great circle in any direction
  85. Xand remain undisturbed though the entire journey.  The method should not
  86. Xrequire _any_ floating point computation once the initial velocity is
  87. Xcomputed since I want to do many iterations on a microcomputer.
  88. X
  89. XA second representation issue is how to cause plates to drift apart and
  90. Xback together.  Maintaining the detailed structure of the ocean basin is
  91. Xcomplicated; consider a circular landmass which splits along a diameter.
  92. XThe ocean basin structure here is clear, since the rift remains in place and
  93. Xthe new basin extends out from it in both directions.  Now suppose one of
  94. Xthe semicircular fragments splits in half perpendicular to the first split.
  95. XThe motion of the landmasses can be computed easily, but the new rift must
  96. Xdrift as well and the required motions in the basin seem self-contradictory.
  97. X
  98. XI chose to ignore the ocean basin and concentrate on the landmasses.  Thus,
  99. Xrifts are not recorded in any way and the ocean floor does not move.  Since
  100. Xthe basins are not simulated, some mechanism is needed to replace the physical
  101. Xmechanism of the sinking basin sucking the landmasses back together.  This
  102. Xis done by a velocity scaling profile which is coded directly into the
  103. Xmovement routine.  The profile says that after a short time, forward motion
  104. Xof a landmass slows and then stops; after this point the landmass begins to
  105. Xmove backwards towards its origin.
  106. X
  107. X
  108. XIII. ALGORITHM
  109. X
  110. XThe initial supercontinent is generated by a simple fractal algorithm; a
  111. Xfractal mountain is created by superimposing four two-dimensional fractal
  112. Xlines.  The mountain is then turned into a binary blob, that is, everything
  113. Xabove a certain altitude is declared to be land, and everything else becomes
  114. Xwater.  The blob is then "improved" by removing islands and internal oceans.
  115. XThis technique produces very irregular circular blobs of varying sizes.
  116. X
  117. XThe program then repeats a sequence of operations for each timestep.  First,
  118. Xa rift may be generated, splitting some continent into pieces; new velocities
  119. Xare generated for the new landmasses.  Second, the distance each landmass will
  120. Xmove this timestep is determined by applying the velocity profile described
  121. Xabove to the landmass velocity.  Third, the landmasses are moved and mountains
  122. Xare built.  Fourth, where the movement routine has caused landmasses to
  123. Xoverlap, new velocities are computed for the overlapping landmasses, and they
  124. Xmay be merged into a single landmass if they overlap sufficiently.  Fifth, the
  125. Xentire topography is eroded; if a square is higher than the square next to
  126. Xit, the altitudes are made more equal.  Finally, the screen is redrawn.
  127. X
  128. XIn step one, random coordinates are generated until a location is found
  129. Xwhich is at least five squares from any ocean.  This location will be the
  130. Xcenter of a rift, which is represented as a randomly curving line.  The
  131. Xdistance requirement is there to ensure that if a rift occurs, it occurs
  132. Xon a fairly large continent where internal heat would accumulate.  When
  133. Xthe rift is drawn, it is allowed to bend randomly but is drawn using
  134. Xconventional digital line-drawing techniques (i.e. Bresenham's algorithm).
  135. XThe rift drawing routine terminates when the rift hits ocean.  If the growing
  136. Xrift hits another landmass, which could occur if two landmasses were touching
  137. Xbut had not yet merged, the rift is aborted since the result would be a very
  138. Xunnatural looking U-shaped continent.
  139. X
  140. XOnce the rift is created, a segmentation algorithm determines how
  141. Xmany new landmasses were formed.  There should only be two new landmasses,
  142. Xbut splinters can be formed if the rift runs along a narrow peninsula or
  143. Xtoo close to a coast.  The algorithm detects and erases such splinters.
  144. XThe landmasses are given an initial velocity which makes them drift directly
  145. Xaway from the rift.  The velocities are inversely dependent on the area
  146. Xof the landmass so that smaller masses move faster.  After the initial
  147. Xvelocities have been determined, the rift is erased.
  148. X
  149. XThe second and third steps are concerned with moving the landmasses.  This
  150. Xis done with a slightly simpler version of Bresenham's algorithm.  The velocity
  151. Xprofile described in Section II is applied so that landmasses will drift
  152. Xapart at first, but will then slow down and come back together.  Because a
  153. Xlandmass can split up again, the process does not simply reassemble the
  154. Xoriginal supercontinent when they drift back together.
  155. X
  156. XMountains are built under two conditions: where two landmasses collide, and
  157. Xwhere landmass subsumes ocean basin.  Both conditions are detected and resolved
  158. Xin the movement routine.  Movement is performed from a source array to a
  159. Xdestination array.  A loop steps over every square in the source array.  If
  160. Xthere is land in a square, its new position is computed based on what
  161. Xlandmass the square belongs to.  If there is ocean basin there in the source
  162. Xarray, the square belongs to the leading edge of a landmass which is subsuming
  163. Xocean basin.  A constant is added to the height of the land in that square.
  164. XIf there is land there in the destination array, then the two landmasses are
  165. Xcolliding.  There is a collision array which records how many times each
  166. Xpair of landmasses collide in any given timestep, and the movement routine
  167. Xincrements the appropriate element of this array for each collision.
  168. XMountains are built in this case by adding half the height of the lower
  169. Xterrain to the height of the higher terrain.
  170. X
  171. XStep four uses the collision information provided by the movement routine
  172. Xto adjust the velocities of colliding landmasses and perhaps merge them.
  173. XFor each pair of colliding landmasses, the routine determines how "strong"
  174. Xthe collision is this timestep.  The velocities are adjusted, again in
  175. Xinverse proportion to the landmass areas, so that the continents begin
  176. Xto come to rest with respect to each other.  If the relative velocity of
  177. Xthe two landmasses, after adjustment, is small enough, then the masses
  178. Xare merged.  This is the mechanism that reassembles the continental
  179. Xfragments into a supercontinent.
  180. X
  181. XErosion is the final, and most computation-intensive, step of the simulation.
  182. XEach pair of adjacent squares is considered exactly once.  If either square
  183. Xis part of a landmass, erosion occurs.  Some fraction of the difference between
  184. Xthe two squares' altitudes is subtracted from the taller and added to the
  185. Xshorter.  This is a very simple algorithm since it ignores many factors,
  186. Xbut more detail would make the simulation even slower.
  187. X
  188. X
  189. XIV.  REFERENCES
  190. X
  191. X1.  Dole, Stephen H., "Computer Simulation of the Formation of Planetary
  192. X    Systems", Icarus 13 (1970), pp 494-508.
  193. X2.  Hart, Michael H., ""The Evolution of the Atmosphere of the Earth", Icarus
  194. X    33 (1978), pp 23-39.
  195. X3.  Forrester, J.W., World Dynamics, Wright-Allen Press (1973).
  196. X4.  Wilson, J. Tuzo, "Continental Drift", Scientific American 208, 4 (April
  197. X    1963), pp 86-100.
  198. X5.  Nance, R.D., Worsley, T.R., and Moody, J.B., "The Supercontinent Cycle",
  199. X    Scientific American (July 1988), pp 72-79.
  200. END_OF_FILE
  201.   if test 10300 -ne `wc -c <'./doc/about.tec'`; then
  202.     echo shar: \"'./doc/about.tec'\" unpacked with wrong size!
  203.   fi
  204.   # end of './doc/about.tec'
  205. fi
  206. if test -f './src/clim.c' -a "${1}" != "-c" ; then 
  207.   echo shar: Will not clobber existing file \"'./src/clim.c'\"
  208. else
  209.   echo shar: Extracting \"'./src/clim.c'\" \(5481 characters\)
  210.   sed "s/^X//" >'./src/clim.c' <<'END_OF_FILE'
  211. X/* This program is Copyright (c) 1991 David Allen.  It may be freely
  212. X   distributed as long as you leave my name and copyright notice on it.
  213. X   I'd really like your comments and feedback; send e-mail to
  214. X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
  215. X   Avenue, Maynard, MA 01754. */
  216. X
  217. X/* This file contains all of the general-purpose routines which are not
  218. X   machine specific: init, mainpar (called by fileio), onestep (called
  219. X   by the machine-specific control routine), and the range-finding
  220. X   function called by several computation routines. */
  221. X
  222. X#include "const.h"
  223. X#include "clim.h"
  224. X
  225. X/* L holds the land values everybody starts with; lm is an edge map with
  226. X   continents outlined in black and mountains outlined in white. */
  227. Xunsigned char l[MAXX][MAXY], lm[MAXX][MAXY];
  228. X
  229. X
  230. X/* These are the parameters used by all of the climate functions.  They are
  231. X   described in params.doc. */
  232. Xint XSIZE = MAXX, YSIZE = MAXY, BSIZE = MAXB;
  233. Xint PRINTMODE = PRINTMODE_SHORT, MAXRANGE = 15;
  234. Xint MAXSTEP = 10000, ZCOAST = 0;
  235. X
  236. Xint change[] = { 1, 1, 1, 1, 1, 1 }, step = 0;
  237. Xextern int picktype;
  238. X
  239. X
  240. Xinit (s) char *s; {
  241. X   if (s && *s) getparams (s);
  242. X   fileinit ();
  243. X   heatcomp (); presscomp (); windcomp ();
  244. X   raincomp (); climcomp (); }
  245. X
  246. X
  247. Xonestep () {
  248. X   switch (picktype) {
  249. X      case M_HEAT:  heatdraw  (step % MAXB); break;
  250. X      case M_PRESS: pressdraw (step % MAXB); break;
  251. X      case M_WIND:  windraw   (step % MAXB); break;
  252. X      case M_RAIN:  raindraw  (step % MAXB); break;
  253. X      case M_CLIM:  climdraw  ();            break; } }
  254. X   
  255. X
  256. Xmainpar (s) char *s; {
  257. X   /* This function is called by getparams() in fileio.c; it looks at each
  258. X   parameter name read from the input file.  If it recognizes the name,
  259. X   the right function is called to set that parameter.  The function
  260. X   returns true if it recognizes the parameter name, and false otherwise. */
  261. X
  262. X   if      (CMP ("LAND"))       getland ();
  263. X   else if (CMP ("BSIZE"))      getlng  (&BSIZE,     M_MAIN);
  264. X   else if (CMP ("MAXRANGE"))   getlng  (&MAXRANGE,  M_MAIN);
  265. X   else if (CMP ("PRINTMODE"))  getlng  (&PRINTMODE, M_MAIN);
  266. X   else if (heatpar  (s)) { }
  267. X   else if (presspar (s)) { }
  268. X   else if (windpar  (s)) { }
  269. X   else if (rainpar  (s)) { }
  270. X   else if (climpar  (s)) { }
  271. X   else return (0);
  272. X   return (1); }
  273. X
  274. X
  275. Xgetland () { register int i, j, x;
  276. X   /* This function is called by mainpar, above, when the LAND parameter
  277. X   is encountered.  It just calls getmat in fileio.c to do the work, but
  278. X   then it also creates an edge map lm; this is used by a couple of the
  279. X   drawing routines as background. */
  280. X
  281. X   getmat  (&XSIZE, &YSIZE, M_MAIN, l);
  282. X
  283. X   for (j=0; j<YSIZE; j++) for (i=0, x=0; i<XSIZE; i++, x=0) {
  284. X      /* Draw a white line if a mountain is present */
  285. X      if (i) if ((l[i][j] == 2) != (l[i-1][j] == 2)) x |= LINE_1V;
  286. X      if (j) if ((l[i][j] == 2) != (l[i][j-1] == 2)) x |= LINE_1H;
  287. X
  288. X      /* Draw a black line if a coast is present */
  289. X      if (i) if ((l[i][j] > 0) != (l[i-1][j] > 0))   x |= LINE_0V;
  290. X      if (j) if ((l[i][j] > 0) != (l[i][j-1] > 0))   x |= LINE_0H;
  291. X
  292. X      /* If both black and white lines are present, white wins */
  293. X      if ((x & LINE_0V) && (x & LINE_1V)) x &= (~LINE_0V);
  294. X      if ((x & LINE_0H) && (x & LINE_1H)) x &= (~LINE_0H);
  295. X      lm[i][j] = x; } }
  296. X
  297. X
  298. Xrange (rr) char rr[MAXX][MAXY]; {
  299. X   /* This function is called by a number of climate routines.  It takes an
  300. X   input array with blobs of -1's on a background of 0's.  The function winds
  301. X   up replacing each 0 with the distance from that square to the nearest -1.
  302. X   The function onerange() does all the work, but it will not compute ranges
  303. X   greater than MAXRANGE.  Therefore, after onerange() is called, any remaining
  304. X   0 values must be replaced with MAXRANGE, indicating that that square is
  305. X   "very far" from any -1 value. */
  306. X
  307. X   register int i, j;
  308. X
  309. X   onerange (rr); checkmouse ();
  310. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
  311. X      if (!rr[i][j]) rr[i][j] = MAXRANGE; }
  312. X
  313. X
  314. Xonerange (rr) char rr[MAXX][MAXY]; {
  315. X   /* This routine consists of a loop.  Each time through the loop, every
  316. X   square is checked.  If the square is zero, it has not yet been updated.
  317. X   In that case, look to see if any adjacent squares were previously updated
  318. X   (or if they were initialized to -1).  If so, set the square to the current
  319. X   distance value, which happens to be identical to the outer loop variable.
  320. X   If, after one loop iteration, no squares have been updated, the matrix
  321. X   must be completely updated.  Stop.  To keep down run-time, a maximum
  322. X   distance value, MAXRANGE, is used as the terminating loop value. */
  323. X
  324. X   register int i, j, x, k, keepgo;
  325. X   for (k=1; k<MAXRANGE; k++) {
  326. X      checkmouse ();
  327. X      for (keepgo=0, j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
  328. X         if (!rr[i][j]) {
  329. X            keepgo = 1;
  330. X            x = rr[i ? i-1 : XSIZE-1][j]; if (x && (x != k)) rr[i][j] = k;
  331. X            x = rr[(i<XSIZE-1) ? i+1 : 0][j]; if (x && (x != k)) rr[i][j] = k;
  332. X            if (j<YSIZE-1) { x = rr[i][j+1]; if (x && (x != k)) rr[i][j] = k; }
  333. X            if (j) { x = rr[i][j-1]; if (x && (x != k)) rr[i][j] = k; } }
  334. X      if (!keepgo) return (0); } return (0); }
  335. X
  336. X
  337. Xstatus (n, i) int n, i; {
  338. X   static char *title[] = { "", "Heat","Pressure","Wind","Rain","Climate" };
  339. X   char t[256];
  340. X   sprintf (t, "%s buffer %d", title[n], i); usermessage (t); }
  341. X
  342. X
  343. Xdouble greyscale (x) int x; {
  344. X   /* This function just returns the 0..1 equivalent of 0..255 */
  345. X   return ((float) ((255 - x) / 320.0) + 0.1); }
  346. END_OF_FILE
  347.   if test 5481 -ne `wc -c <'./src/clim.c'`; then
  348.     echo shar: \"'./src/clim.c'\" unpacked with wrong size!
  349.   fi
  350.   # end of './src/clim.c'
  351. fi
  352. if test -f './src/heat.c' -a "${1}" != "-c" ; then 
  353.   echo shar: Will not clobber existing file \"'./src/heat.c'\"
  354. else
  355.   echo shar: Extracting \"'./src/heat.c'\" \(6893 characters\)
  356.   sed "s/^X//" >'./src/heat.c' <<'END_OF_FILE'
  357. X/* This program is Copyright (c) 1991 David Allen.  It may be freely
  358. X   distributed as long as you leave my name and copyright notice on it.
  359. X   I'd really like your comments and feedback; send e-mail to
  360. X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
  361. X   Avenue, Maynard, MA 01754. */
  362. X
  363. X/* This file contains the routines that compute local temperatures */
  364. X
  365. X#include "const.h"
  366. X#include "clim.h"
  367. X
  368. X/* Some private defines.  FREEZING is 0 degrees C in Kelvin; DEG2RAD is the
  369. X   conversion factor from angular degrees to radians. */
  370. X
  371. X#define FREEZING 273.0
  372. X#define PI 3.14159
  373. X#define DEG2RAD (PI / 180)
  374. X
  375. X/* The input array is l, from main.c; lm is used by heatdraw().  The output
  376. X   array is ts, containing temperatures.  Array t is an unscaled copy of the
  377. X   temperatures; tmin and tmax are used for scaling, and tscale is the
  378. X   computed scale factor.  To convert the unscaled temperatures to degrees K,
  379. X   divide by TEMPSCALE. */
  380. X
  381. Xextern unsigned char l[MAXX][MAXY], lm[MAXX][MAXY];
  382. Xunsigned char ts[MAXB][MAXX][MAXY];
  383. Xint tt[MAXB][MAXX][MAXY], tmax, tmin;
  384. Xdouble tscale; int TEMPSCALE = 10;
  385. X
  386. X/* These parameters are defined in main.c */
  387. X
  388. Xextern int BSIZE, XSIZE, YSIZE, PRINTMODE;
  389. X
  390. X/* These parameters are used here, and are described in params.doc */
  391. X
  392. Xint PRINTEMP = 0;
  393. Xdouble TILT = 23.0, ECCENT = 0.0, ECCPHASE = 0.0;
  394. Xdouble LCOS = 45.0, LCONST = 275.0, LTILT = 1.0, LSMOOTH = 0.6, LDIV = 180.0;
  395. Xdouble OCOS = 30.0, OCONST = 275.0, OTILT = 0.2, OSMOOTH = 0.2, ODIV = 250.0;
  396. X
  397. X
  398. Xheatpar (s) char *s; {
  399. X   /* This function is called by mainpar() in main.c; it simply tests input
  400. X   parameter names to see if they are defined in this file.  Each of the
  401. X   above ints are defined in this file.  If the input string matches here,
  402. X   the function returns true. */
  403. X   if      (CMP ("TILT"))     getdbl  (&TILT,     M_HEAT);
  404. X   else if (CMP ("ECCENT"))   getdbl  (&ECCENT,   M_HEAT);
  405. X   else if (CMP ("ECCPHASE")) getdbl  (&ECCPHASE, M_HEAT);
  406. X
  407. X   else if (CMP ("LCOS"))     getdbl  (&LCOS,     M_HEAT);
  408. X   else if (CMP ("LCONST"))   getdbl  (&LCONST,   M_HEAT);
  409. X   else if (CMP ("LTILT"))    getdbl  (<ILT,    M_HEAT);
  410. X   else if (CMP ("LSMOOTH"))  getdbl  (&LSMOOTH,  M_HEAT);
  411. X   else if (CMP ("LDIV"))     getdbl  (&LDIV,     M_HEAT);
  412. X
  413. X   else if (CMP ("OCOS"))     getdbl  (&OCOS,     M_HEAT);
  414. X   else if (CMP ("OCONST"))   getdbl  (&OCONST,   M_HEAT);
  415. X   else if (CMP ("OTILT"))    getdbl  (&OTILT,    M_HEAT);
  416. X   else if (CMP ("OSMOOTH"))  getdbl  (&OSMOOTH,  M_HEAT);
  417. X   else if (CMP ("ODIV"))     getdbl  (&ODIV,     M_HEAT);
  418. X
  419. X   else if (CMP ("PRINTEMP")) getlng  (&PRINTEMP, M_HEAT);
  420. X   else return (0);
  421. X   return (1); }
  422. X
  423. X
  424. Xheatlut (x, s) int x; char *s; {
  425. X   /* After the heatcomp routine is finished, a scale factor is computed
  426. X   for converting degrees K to 0..255; this routine converts back.  Functions
  427. X   in the machine-dependent code can call here to print map keys.  The caller
  428. X   must provide a char buffer; a string containing degrees F is put there. */
  429. X
  430. X   double temp;
  431. X
  432. X   temp = (((double) x / tscale) + (double) tmin) / TEMPSCALE;
  433. X   temp = (temp - FREEZING) * 1.8 + 32;
  434. X   sprintf (s, "%6.1f", temp); }
  435. X
  436. X
  437. Xheatcomp () {
  438. X   /* This is the main routine for computing temperatures.  After getheat()
  439. X   is called to do all the work, this routine takes the ints from t and
  440. X   finds the smallest and largest values.  These are used to compute a scale
  441. X   factor, tscale; the arrays ts are then filled with scaled values.  Finally,
  442. X   putmat() from main.c is called if needed to print results. */
  443. X
  444. X   register int i, j, buf; char s[20];
  445. X
  446. X   getheat (); tmin = 32000; tmax = 0;
  447. X
  448. X   usermessage ("Scaling heat");
  449. X   /* Find minimum and maximum across all buffers */
  450. X   for (buf=0; buf<BSIZE; buf++) {
  451. X      checkmouse ();
  452. X      for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
  453. X         if (tt[buf][i][j] < tmin) tmin = tt[buf][i][j];
  454. X         if (tt[buf][i][j] > tmax) tmax = tt[buf][i][j]; } }
  455. X
  456. X   /* Compute scale; for every buffer, fill ts from t */
  457. X   tscale = 254.0 / ((double) (tmax - tmin));
  458. X   for (buf=0; buf<BSIZE; buf++) {
  459. X      for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
  460. X         ts[buf][i][j] = (tt[buf][i][j] - tmin) * tscale;
  461. X      checkmouse (); }
  462. X
  463. X   if (PRINTEMP) {
  464. X      if (PRINTMODE != PRINTMODE_GREY) {
  465. X         printf ("(KEY-IN-FAREN (\n");
  466. X         for (i=0; i<8; i++) { heatlut (16 * i, s); printf (" %s", s); }
  467. X         printf ("\n");
  468. X         for (i=8; i<16; i++) { heatlut (16 * i, s); printf (" %s", s); }
  469. X         printf ("))\n"); }
  470. X      for (i=0; i<BSIZE; i++)
  471. X         putmat ("TEMPERATURE", i, PRINTMODE_SCALE, ts[i], lm); } }
  472. X
  473. X
  474. Xheatdraw (n) int n; { draw (DRAW_GREY, LINE_CORN, ts[n], lm); }
  475. X   /* This function calls draw() with the right arguments to display heat */
  476. X
  477. X
  478. Xgetheat () {
  479. X   /* This function does all the work for computing temperatures.  The outermost
  480. X   loop goes through each row of the output array once, computing all buffers
  481. X   at the same time.  The loop has two inner loops: first, tland and tsea are
  482. X   filled with the temperatures found far inland and far at sea for each buffer.
  483. X   In the second loop, the weight function for each point in the latitude line
  484. X   is computed and the temperature is found for each buffer. */
  485. X
  486. X   register int buf, i, j;
  487. X   double lat, lscl, sscl, x, fact, theta, delth, phase;
  488. X   double tland[MAXB], tsea[MAXB];
  489. X
  490. X   lscl = DEG2RAD * 180.0 / (90.0 + LTILT * TILT);
  491. X   sscl = DEG2RAD * 180.0 / (90.0 + OTILT * TILT);
  492. X   delth = 2.0 * PI / (double) BSIZE;
  493. X   for (j=0; j<YSIZE; j++) {
  494. X      status (M_HEAT, j); checkmouse ();
  495. X      lat = 90.0 - 180.0 * (double) j / (double) YSIZE;
  496. X      for (buf=0, theta=0; buf<BSIZE; buf++, theta+=delth) {
  497. X         phase = theta + ECCPHASE; if (phase > 2.0 * PI) phase -= (2 * PI);
  498. X         fact = (1.0 + ECCENT * cos (phase)) * TEMPSCALE;
  499. X         x = (lat + cos (theta) * TILT * LTILT) * lscl;
  500. X         tland[buf] = (LCONST + LCOS * cos (x)) * fact;
  501. X         x = (lat + cos (theta) * TILT * OTILT) * sscl;
  502. X         tsea[buf]  = (OCONST + OCOS * cos (x)) * fact; }
  503. X      for (i=0; i<XSIZE; i++) {
  504. X         if (!l[i][j]) x = OSMOOTH + (countland (i, j) / ODIV);
  505. X         else x = LSMOOTH + (countland (i, j) / LDIV);
  506. X         for (buf=0; buf<BSIZE; buf++)
  507. X            tt[buf][i][j] = tsea[buf] + (tland[buf] - tsea[buf]) * x; } } }
  508. X
  509. X
  510. Xcountland (x, y) int x, y; {
  511. X   /* Called by getheat() for each square, this function looks in a 11 wide
  512. X   by 5 high box and counts the number of land squares found there.  It
  513. X   compensates for y values off the map, and wraps x values around.   The
  514. X   answer is returned. */
  515. X
  516. X   register int sum=0; int jmin, jmax, j1, i0, i1;
  517. X
  518. X   jmin = y - 2; if (jmin < 0) jmin = 0;
  519. X   jmax = y + 2; if (jmax >= YSIZE) jmax = YSIZE-1;
  520. X   for (j1=jmin; j1<=jmax; j1++) for (i0=-5; i0<6; i0++) {
  521. X      i1 = i0 + x; if (i1 < 0) i1 += XSIZE;
  522. X      if (i1 >= XSIZE) i1 -= XSIZE;
  523. X      sum += l[i1][j1]; }
  524. X   return (sum); }
  525. END_OF_FILE
  526.   if test 6893 -ne `wc -c <'./src/heat.c'`; then
  527.     echo shar: \"'./src/heat.c'\" unpacked with wrong size!
  528.   fi
  529.   # end of './src/heat.c'
  530. fi
  531. if test -f './src/pressure.c' -a "${1}" != "-c" ; then 
  532.   echo shar: Will not clobber existing file \"'./src/pressure.c'\"
  533. else
  534.   echo shar: Extracting \"'./src/pressure.c'\" \(9001 characters\)
  535.   sed "s/^X//" >'./src/pressure.c' <<'END_OF_FILE'
  536. X/* This program is Copyright (c) 1991 David Allen.  It may be freely
  537. X   distributed as long as you leave my name and copyright notice on it.
  538. X   I'd really like your comments and feedback; send e-mail to
  539. X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore
  540. X   Avenue, Maynard, MA 01754. */
  541. X
  542. X/* This file contains the routines to compute global high and low
  543. X   pressure areas. */
  544. X
  545. X#include "const.h"
  546. X#include "clim.h"
  547. X
  548. X/* These are the data arrays required: l is an input array defining the
  549. X   ocean, land and mountain areas; ts is the temperature array computed
  550. X   by the functions in heat.c.  Array pr is filled by ocean(), land() and
  551. X   heateq(), below; PR_HIGH indicates a high pressure zone, PR_LOW indicates
  552. X   a low, and PR_HEQ indicates the heat equator, a low zone.  Array pm is
  553. X   the output array for this file, and it contains an edge map which has
  554. X   edges in color 1 surrounding lows and color 0 around highs.  Array r is
  555. X   temporary storage for local calls to range() in main.c. */
  556. X
  557. Xextern unsigned char l[MAXX][MAXY], ts[MAXB][MAXX][MAXY];
  558. Xstatic char r[MAXX][MAXY];
  559. Xstatic unsigned char pm[MAXB][MAXX][MAXY];
  560. Xunsigned char pr[MAXB][MAXX][MAXY];
  561. X
  562. X
  563. X/* The externs below are declared in main.c; they represent global parameters.
  564. X   The ints are described in params.doc. */
  565. X
  566. Xextern int BSIZE, XSIZE, YSIZE, PRINTMODE;
  567. Xint OOTHRESH = 5, OLTHRESH = 1, LOTHRESH = 3, LLTHRESH = 7;
  568. Xint OHMIN = 130, OHMAX = 180, OLMIN =  40, OLMAX =  65;
  569. Xint LHMIN =   0, LHMAX =  20, LLMIN = 220, LLMAX = 255;
  570. Xint PRINTPR = 0;
  571. X
  572. X
  573. Xpresspar (s) char *s; {
  574. X   /* This function is called by mainpar() in main.c; it simply tests input
  575. X   parameters to see if they are defined in this file.  Each of the above
  576. X   ints is referred to in this function.  If an input string matches here,
  577. X   the function returns true. */
  578. X   if      (CMP ("OOTHRESH")) getlng  (&OOTHRESH, M_PRESS);
  579. X   else if (CMP ("OLTHRESH")) getlng  (&OLTHRESH, M_PRESS);
  580. X   else if (CMP ("OHMIN"))    getlng  (&OHMIN,    M_PRESS);
  581. X   else if (CMP ("OHMAX"))    getlng  (&OHMAX,    M_PRESS);
  582. X   else if (CMP ("OLMIN"))    getlng  (&OLMIN,    M_PRESS);
  583. X   else if (CMP ("OLMAX"))    getlng  (&OLMAX,    M_PRESS);
  584. X
  585. X   else if (CMP ("LOTHRESH")) getlng  (&LOTHRESH, M_PRESS);
  586. X   else if (CMP ("LLTHRESH")) getlng  (&LLTHRESH, M_PRESS);
  587. X   else if (CMP ("LHMIN"))    getlng  (&LHMIN,    M_PRESS);
  588. X   else if (CMP ("LHMAX"))    getlng  (&LHMAX,    M_PRESS);
  589. X   else if (CMP ("LLMIN"))    getlng  (&LLMIN,    M_PRESS);
  590. X   else if (CMP ("LLMAX"))    getlng  (&LLMAX,    M_PRESS);
  591. X
  592. X   else if (CMP ("PRINTPR"))  getlng  (&PRINTPR,  M_PRESS);
  593. X   else return (0);
  594. X   return (1); }
  595. X
  596. X
  597. Xpresscomp () {
  598. X   /* The main routine for this file.  It just calls the four routines
  599. X   which do all the work.  Ocean() finds pressure extremes on the ocean;
  600. X   land() does the same for land; heateq() defines the heat equator, and
  601. X   setpm() computes pm[][] from pr[][]. */
  602. X
  603. X   int buf;
  604. X
  605. X   for (buf=0; buf<BSIZE; buf++) {
  606. X      status (M_PRESS, buf); ocean (buf); land (buf);
  607. X      checkmouse (); findheq (buf); setpm (buf); }
  608. X   if (PRINTPR) for (buf=0; buf<BSIZE; buf++) {
  609. X      if (PRINTMODE == PRINTMODE_GREY)
  610. X         putmat ("PRESSURE", buf, PRINTMODE_SHORT, l, pm[buf]);
  611. X      else putmat ("PRESSURE", buf, PRINTMODE_SHORT, pr[buf], 0); } }
  612. X
  613. X
  614. Xpressdraw (n) int n; { draw (DRAW_LAND, LINE_CORN, l, pm[n]); }
  615. X   /* This function calls draw with the right arguments to display pressure */
  616. X
  617. X
  618. Xocean (buf) int buf; {
  619. X   /* Determine ocean highs and lows.  An ocean high or low must occur over
  620. X   ocean, far away from major land masses.  Two calls to range() are made
  621. X   to find the qualifying ocean areas; then temperature criteria are used
  622. X   to select the actual pressure zones. */
  623. X
  624. X   register int i, j; int x;
  625. X
  626. X   /* Set r to the distance on land from the coast. */
  627. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) r[i][j] = l[i][j] ? 0 : -1;
  628. X   range (r);
  629. X
  630. X   /* Initialize r to contain blobs on land which are at least OLTHRESH squares
  631. X      away from the coast.  Then set r to the distance from these.  The result
  632. X      in r is the distance from the nearest big piece of land (ignoring
  633. X      islands). */
  634. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
  635. X      r[i][j] = (r[i][j] > OLTHRESH) ? -1 : 0;
  636. X   range (r);
  637. X
  638. X   /* For each array element, if it is at least OOTHRESH squares from the
  639. X      nearest big piece of land, it might be the center of an ocean pressure
  640. X      zone.  The pressure zones are defined by temperature ranges; if the
  641. X      temperature in ts is between OLMIN and OLMAX, a low is recorded, while
  642. X      if the temperature is between OHMIN and OHMAX, a high is recorded. */
  643. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
  644. X      pr[buf][i][j] = 0; x = ts[buf][i][j];
  645. X      if (r[i][j] > OOTHRESH) {
  646. X         if ((x >= OLMIN) && (x <= OLMAX)) pr[buf][i][j] = PR_LOW;
  647. X         if ((x >= OHMIN) && (x <= OHMAX)) pr[buf][i][j] = PR_HIGH; } } }
  648. X
  649. X
  650. Xland (buf) int buf; {
  651. X   /* This function is simply the complement of ocean(): it finds land highs
  652. X   and lows.  A land high or low must occur over land, far from major oceans.
  653. X   Two calls to range() are made to find the qualifying land areas; then
  654. X   temperature criteria are used to select the actual pressure zones. */
  655. X
  656. X   register int i, j; int x;
  657. X
  658. X   /* Set r to distance on water from coast. */
  659. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) r[i][j] = l[i][j] ? -1 : 0;
  660. X   range (r);
  661. X
  662. X   /* Initialize r to contain blobs on ocean which are at least LOTHRESH
  663. X      squares away from the coast.  Then set r to the distance from these.  The
  664. X      result in r is the distance from the nearest ocean, ignoring lakes. */
  665. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
  666. X      r[i][j] = (r[i][j] > LOTHRESH) ? -1 : 0;
  667. X   range (r);
  668. X
  669. X   /* For each array element, if it is at least LLTHRESH squares from the
  670. X      nearest large ocean, it might be the center of a land pressure zone.
  671. X      The pressure zones are defined by temperature ranges; if the temperature
  672. X      in ts is between LLMIN and LLMAX, a low is recorded, while if the
  673. X      temperature is between LHMIN and LHMAX, a high is recorded. */
  674. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
  675. X      x = ts[buf][i][j];
  676. X      if (r[i][j] > LLTHRESH) {
  677. X         if ((x >= LLMIN) && (x <= LLMAX)) pr[buf][i][j] = PR_LOW;
  678. X         if ((x >= LHMIN) && (x <= LHMAX)) pr[buf][i][j] = PR_HIGH; } } }
  679. X
  680. X
  681. Xfindheq (buf) int buf; {
  682. X   /* This function finds the heat equator and marks it in pr.  For each
  683. X   vertical column of ts, the median position is found and marked.  To
  684. X   make the heat equator continuous, jlast is set to the position of the
  685. X   heat equator in the previous column; a connection is made in the present
  686. X   column to ensure continuity. */
  687. X
  688. X   register int i, j; int sum, jlast = 0, jnext;
  689. X
  690. X   for (i=0; i<XSIZE; i++) {
  691. X      /* Find the total of the temperatures in this column */
  692. X      for (sum=0, j=0; j<YSIZE; j++) sum += ts[buf][i][j];
  693. X
  694. X      /* Step through the column again until the total so far is exactly
  695. X         half the total for the column.  This is the median position. */
  696. X      for (sum>>=1, j=0; j<YSIZE && sum>0; j++) sum -= ts[buf][i][j];
  697. X
  698. X      /* Mark this position and remember it with jnext */
  699. X      pr[buf][i][j] = PR_HEQ; jnext = j;
  700. X
  701. X      /* For each column except the first (where i = 0), if the last heat
  702. X         equator is above this one, move upwards to it, marking each square,
  703. X         to ensure continuity; if below this one, move downwards to it. */
  704. X
  705. X      if (i && (j > jlast)) for (; j>=jlast; j--) pr[buf][i][j] = PR_HEQ;
  706. X      else if (i && (j < jlast)) for (; j<=jlast; j++) pr[buf][i][j] = PR_HEQ;
  707. X
  708. X      /* Remember this position for the next column.  Note that no check is
  709. X         done to ensure continuity at the wraparound point; this is bad. */
  710. X      jlast = jnext; } }
  711. X
  712. X
  713. Xsetpm (buf) int buf; {
  714. X   /* Setpm() is called after the above three functions have filled pr with
  715. X   the codes for high, low and heat equator.  The purpose of this function
  716. X   is to create an edge map surrounding lows with color 1 and highs with
  717. X   color 0. */
  718. X
  719. X   register int i, j, k; int col;
  720. X
  721. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
  722. X      k = pr[buf][i][j]; col = 0;
  723. X
  724. X      /* If not at the top edge, and if the pressure status here is not equal
  725. X         to the pressure status one square up, then put a horizontal line in
  726. X         this square.  The color is zero if there is a high here; if a low or
  727. X         heat equator (a type of low) is here, the color is one. */
  728. X      if (j) if (k != pr[buf][i][j-1]) col =
  729. X         ((k == PR_HIGH) || (pr[buf][i][j-1] == PR_HIGH)) ? LINE_0H : LINE_1H;
  730. X      /* Similarly, if not at the left edge, put a vertical line in the right
  731. X         color.  Notice that this color is OR'ed with the previous color. */
  732. X      if (i) if (k != pr[buf][i-1][j]) col |=
  733. X         ((k == PR_HIGH) || (pr[buf][i-1][j] == PR_HIGH)) ? LINE_0V : LINE_1V;
  734. X
  735. X      /* Set the square in the pm array to the resultant color */
  736. X      pm[buf][i][j] = col; } }
  737. X
  738. END_OF_FILE
  739.   if test 9001 -ne `wc -c <'./src/pressure.c'`; then
  740.     echo shar: \"'./src/pressure.c'\" unpacked with wrong size!
  741.   fi
  742.   # end of './src/pressure.c'
  743. fi
  744. if test -f './src/tec1.c' -a "${1}" != "-c" ; then 
  745.   echo shar: Will not clobber existing file \"'./src/tec1.c'\"
  746. else
  747.   echo shar: Extracting \"'./src/tec1.c'\" \(10750 characters\)
  748.   sed "s/^X//" >'./src/tec1.c' <<'END_OF_FILE'
  749. X/* This program is Copyright (c) 1991 David Allen.  It may be freely
  750. X   distributed as long as you leave my name and copyright notice on it.
  751. X   I'd really like your comments and feedback; send e-mail to
  752. X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore Ave,
  753. X   Maynard, MA 01754. */
  754. X
  755. X/* This is the file containing all of the important functions except for
  756. X   trysplit (), which splits a continent into pieces.  Also, all of the main
  757. X   arrays are declared here, even a couple that are only used by functions in
  758. X   tec2.c.  The array declarations are first, followed by the sequencing
  759. X   function onestep () and some miscellaneous routines including the text
  760. X   output routines; initialization routines and the routines that do all
  761. X   the interesting stuff are last. */
  762. X
  763. X#include "const.h"
  764. X#include "tec.h"
  765. X
  766. X/* These are the parameters and their default values; each is defined in
  767. X   params.doc */ 
  768. Xint XSIZE = 100,    YSIZE = 100,    MAXSTEP = 100;
  769. Xint MAXBUMP = 50,    BUMPTOL = 50,    UNDERSCAN = 0;
  770. Xint HYDROPCT = 70,    DRAWEVERY = 0,    PRINTMODE = PRINTMODE_NONE;
  771. Xint ZINIT = 22,        ZSUBSUME = 16,    ZCOAST = 16;
  772. Xint ZSHELF = 8,        ZMOUNTAIN = 48, ZERODE = 16;
  773. Xint RIFTPCT = 40,    DOERODE = 1,    ERODERND = 4;
  774. Xint MAXCTRTRY = 50,    RIFTDIST = 5,    BENDEVERY = 6;
  775. Xint BENDBY = 50,    SPEEDRNG = 300,    SPEEDBASE = 200;
  776. X
  777. Xdouble MR [] = { 1.0,1.0,1.0,0.7,0.4,0.1,-0.2,-0.5,-0.8,-1.0 };
  778. Xint MAXLIFE = 10; /* Length of MR vector */
  779. Xint change[1]; /* needed for fileio */
  780. X
  781. X/* The following arrays are global and most are used by functions in both
  782. X   source files.  The two main ones are m and t.  Each is set up to be two
  783. X   2-d arrays, where each array is the size of the whole world.  M is the
  784. X   map; elements in m are indices of plates, showing which squares are
  785. X   covered by which plate.  T is the topography; elements in t are altitudes. */
  786. Xchar m[2][MAXX][MAXY]; unsigned char t[2][MAXX][MAXY];
  787. X/* Several arrays are used by the binary blob segmenter, segment() in tec2.c.
  788. X   These include r, which is used to store fragment indices; many fragments
  789. X   make up one region during a segmentation.  Kid is a lookup table; fragment
  790. X   k belongs to region kid[k] after a segmentation is finished.  Karea[k]
  791. X   is the area of fragment k. */
  792. Xchar r[MAXX][MAXY], kid[MAXFRAG]; int karea [MAXFRAG];
  793. X/* The merge routine gets information from the move routine; when the move
  794. X   routine puts a square of one plate on top of another plate, that information
  795. X   is recorded in the merge matrix mm. */
  796. Xchar mm[MAXPLATE][MAXPLATE];
  797. X/* The erosion routine needs an array to store delta information; during an
  798. X   erosion, the increases or decreases in elevation are summed in e and then
  799. X   applied all at once to the topography. */
  800. Xchar e[MAXX][MAXY];
  801. X/* Several routines need temporary storage for areas and plate identifiers. */
  802. Xint tarea[MAXPLATE]; int ids[MAXPLATE];
  803. X/* The plates in use are stored in this data structure.  Dx,dy are the
  804. X   values to move by THIS STEP ONLY; odx,ody are the permanent move
  805. X   values; rx,ry are the remainder x and y values used by newdxy() to
  806. X   determine dx,dy; age is the age of the plate, in steps; area is the
  807. X   area of the plate, in squares; id is the value in the m array which
  808. X   corresponds to this plate; next is a pointer to the next occupied
  809. X   element of the plate array. */
  810. Xstruct plate p [MAXPLATE];
  811. X/* The linked list header for available plates and used plates are global,
  812. X   as is the step counter.  */
  813. Xint pavail, phead, step;
  814. Xonestep () {
  815. X   /* This is the sequencing routine called by main once per step.
  816. X   It just calls the important subfunctions in order:
  817. X   - trysplit   finds a plate to break up, and computes new velocities
  818. X   - newdxy     computes the deltas to move each plate this step
  819. X   - move       moves the plates
  820. X   - merge      determines results when plates rub together
  821. X   - erode      erodes the terrain, adding or subtracting altitude
  822. X   - draw       draw the resulting array once every DRAWEVERY steps
  823. X   The m and t arrays are double-buffered in the sense that operations go
  824. X   from m[0] to m[1] or vice-versa; src and dest determine which is which. */
  825. X   int src, dest;
  826. X   src = step % 2; dest = 1 - src;
  827. X   if (rnd (100) < RIFTPCT) trysplit (src);
  828. X   newdxy ();
  829. X   move (src, dest);
  830. X   merge (dest);
  831. X   if (DOERODE) erode (dest);
  832. X   draw (DRAW_TEC, LINE_NONE, t[dest], 0);
  833. X
  834. X   if (DRAWEVERY) if (step && !(step % DRAWEVERY)) tecst (dest);
  835. X   if (!DRAWEVERY && (step == MAXSTEP - 1)) tecst (dest); }
  836. Xpalloc () {
  837. X   /* Allocate a plate from the array and return its index.  All the fields
  838. X   of the plate are initialized to 0, except `next'.  That field is used to
  839. X   link together the plate structures in use.  */
  840. X   int x;
  841. X
  842. X   if (!pavail) panic ("No more objects");
  843. X   x = pavail; pavail = p[x].next;
  844. X   p[x].next = phead; phead = x;
  845. X   p[x].area = 0; p[x].age = 0;
  846. X   p[x].rx = 0; p[x].ry = 0;
  847. X   p[x].odx = 0; p[x].ody = 0;
  848. X   p[x].dx = 0; p[x].dy = 0;
  849. X   return (x); }
  850. Xpfree (n) int n; {
  851. X   /* Return a plate array element to the pool of available elements.
  852. X   To check for infinite loops, the variable guard is incremented
  853. X   at each operation; if the number of operations exceeds the maximum
  854. X   possible number, the program panics. */
  855. X   int i, guard = 0;
  856. X   if (phead == n) phead = p[n].next;
  857. X   else {
  858. X      for (i=phead; p[i].next!=n; i=p[i].next)
  859. X         if (++guard > MAXPLATE) panic ("Infinite loop in pfree");
  860. X      p[i].next = p[n].next; }
  861. X   p[n].next = pavail; pavail = n; }
  862. X
  863. Xmainpar (s) char *s; { 
  864. X   if      (CMP ("XSIZE"))     getdim  (&XSIZE, 0);
  865. X   else if (CMP ("YSIZE"))     getdim  (&YSIZE, 0);
  866. X   else if (CMP ("MOVERATE"))  getdvec (&MAXLIFE, MR, 0);
  867. X   else if (CMP ("MAXSTEP"))   getlng  (&MAXSTEP, 0);
  868. X   else if (CMP ("MAXBUMP"))   getlng  (&MAXBUMP, 0);
  869. X   else if (CMP ("BUMPTOL"))   getlng  (&BUMPTOL, 0);
  870. X   else if (CMP ("DRAWEVERY")) getlng  (&DRAWEVERY, 0);
  871. X   else if (CMP ("PRINTMODE")) getlng  (&PRINTMODE, 0);
  872. X   else if (CMP ("HYDROPCT"))  getlng  (&HYDROPCT, 0);
  873. X   else if (CMP ("ZINIT"))     getlng  (&ZINIT, 0);
  874. X   else if (CMP ("ZSUBSUME"))  getlng  (&ZSUBSUME, 0);
  875. X   else if (CMP ("ZCOAST"))    getlng  (&ZCOAST, 0);
  876. X   else if (CMP ("ZSHELF"))    getlng  (&ZSHELF, 0);
  877. X   else if (CMP ("ZMOUNTAIN")) getlng  (&ZMOUNTAIN, 0);
  878. X   else if (CMP ("ZERODE"))    getlng  (&ZERODE, 0);
  879. X   else if (CMP ("RIFTPCT"))   getlng  (&RIFTPCT, 0);
  880. X   else if (CMP ("DOERODE"))   getlng  (&DOERODE, 0);
  881. X   else if (CMP ("ERODERND"))  getlng  (&ERODERND, 0);
  882. X   else if (CMP ("MAXCTRTRY")) getlng  (&MAXCTRTRY, 0);
  883. X   else if (CMP ("RIFTDIST"))  getlng  (&RIFTDIST, 0);
  884. X   else if (CMP ("BENDEVERY")) getlng  (&BENDEVERY, 0);
  885. X   else if (CMP ("BENDBY"))    getlng  (&BENDBY, 0);
  886. X   else if (CMP ("SPEEDBASE")) getlng  (&SPEEDBASE, 0);
  887. X   else if (CMP ("SPEEDRNG"))  getlng  (&SPEEDRNG, 0);
  888. X   else if (CMP ("UNDERSCAN")) getlng  (&UNDERSCAN, 0);
  889. X   else return (0);
  890. X   return (1); }
  891. X
  892. X
  893. Xtecst (src) int src; {
  894. X   /* This function is called whenever map output is called for.  It looks
  895. X   at the parameter `printmode' to decide between long text, simple text,
  896. X   and PostScript output formats.  Note that the default for this
  897. X   function is no output at all, corresponding to PRINTMODE_NONE.  If only
  898. X   one output map is desired, then move the coastline up or down to meet the
  899. X   desired hydrographic percentage. */
  900. X
  901. X   register int i, j, zcoast; int hist[256], goal; unsigned char sk[MAXX][MAXY];
  902. X
  903. X   if (!PRINTMODE) return (0);
  904. X   if (!DRAWEVERY) {
  905. X      /* Create a histogram of the output array */
  906. X      for (i=0; i<256; i++) hist[i] = 0;
  907. X      for (i=0; i<XSIZE; i++)
  908. X         for (j=0; j<YSIZE; j++) hist[t[src][i][j]]++;
  909. X
  910. X      /* Starting from the highest altitude, move down until number of */
  911. X      /* squares above water is slightly greater than the exact goal */
  912. X      goal = XSIZE * YSIZE;
  913. X      goal = (goal * (100 - HYDROPCT)) / 100;
  914. X      for (zcoast=255, i=0; zcoast>0; zcoast--)
  915. X         if ((i += hist[zcoast]) > goal) break;
  916. X
  917. X      /* If the new coast level is zero, then there wasn't enough land */
  918. X      /* to meet the goal, even going right down to the ocean floor.  The */
  919. X      /* only possible result is to panic since the goal can't be met. */
  920. X      if (!zcoast) panic ("Scaled till oceans dried up");
  921. X      ZCOAST = zcoast; }
  922. X
  923. X   if (PRINTMODE != PRINTMODE_SHORT) putmat ("LAND", -1, PRINTMODE, t[src], 0);
  924. X   else {
  925. X      for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++) {
  926. X         if (t[src][i][j] < ZCOAST) sk[i][j] = 0;
  927. X         else if (t[src][i][j] > ZMOUNTAIN) sk[i][j] = 2;
  928. X         else sk[i][j] = 1; }
  929. X      putmat ("LAND", -1, PRINTMODE, sk, 0); }
  930. X   return (0); }
  931. X
  932. X
  933. Xdouble greyscale (x) int x; {
  934. X   /* Called by the PostScript print routine, this function simply computes
  935. X   the intensity from 0-1 corresponding to the altitude 0-255 */
  936. X   if (x < ZCOAST) return ((float) 0);
  937. X   return (1.0 - ((x > 128) ? 128 : x) / 128.0); }
  938. X
  939. X
  940. Xinit (s) char *s; {
  941. X   /* This is the catchall function that initializes everything.  First,
  942. X   it calls getparams() in fileio.c to allow the user to set parameters.  Next,
  943. X   it links together the plates onto the free list and starts the used list
  944. X   at empty.  The first plate is created by a fractal technique and then
  945. X   improved.  Finally, the fractal is copied to the data array and drawn.
  946. X   There are two kinds of improvement done here.  First, islands are
  947. X   eliminated by segmenting the blob and erasing all the regions except
  948. X   for the biggest.  Second, oceans inside the blob (holes) are eliminated
  949. X   by segmenting the _ocean_ and filling in all regions except the biggest. */
  950. X   int besti, x; register int i, j;
  951. X   if (s) if (*s) getparams (s); fileinit ();
  952. X   for (i=1; i<MAXPLATE; i++) p[i].next = i + 1;
  953. X   p[MAXPLATE-1].next = 0;
  954. X   pavail = 1; phead = 0;
  955. X   /* Allocate a plate structure for the first plate and make a blob */
  956. X   x = palloc (); makefrac (0, x);
  957. X
  958. X   /* Segment m[0] looking for x, set besti to the largest region, */
  959. X   /* and zero out all the other regions.  This eliminates islands. */
  960. X   besti = singlefy (0, x);
  961. X   if (besti > 0) for (i=1; i<XSIZE; i++) for (j=1; j<YSIZE; j++)
  962. X      if (kid[r[i][j]] != besti) m[0][i][j] = 0;
  963. X   /* Segment m[0] looking for 0 (ocean), set besti to the largest region, */
  964. X   /* and fill in all the other regions.  This eliminates holes in the blob. */
  965. X   besti = singlefy (0, 0);
  966. X   if (besti > 0) for (i=1; i<XSIZE; i++) for (j=1; j<YSIZE; j++)
  967. X      if (kid[r[i][j]] != besti) m[0][i][j] = x;
  968. X   /* Fill the topo structure with the blob shape while finding its area */
  969. X   for (i=0; i<XSIZE; i++) for (j=0; j<YSIZE; j++)
  970. X      if (m[0][i][j]) { t[0][i][j] = ZINIT; p[x].area++; }
  971. X   /* Draw the blob */
  972. X   if (DRAWEVERY) draw (DRAW_TEC, LINE_NONE, t[0], 0); }
  973. END_OF_FILE
  974.   if test 10750 -ne `wc -c <'./src/tec1.c'`; then
  975.     echo shar: \"'./src/tec1.c'\" unpacked with wrong size!
  976.   fi
  977.   # end of './src/tec1.c'
  978. fi
  979. if test -f './src/x.c' -a "${1}" != "-c" ; then 
  980.   echo shar: Will not clobber existing file \"'./src/x.c'\"
  981. else
  982.   echo shar: Extracting \"'./src/x.c'\" \(7119 characters\)
  983.   sed "s/^X//" >'./src/x.c' <<'END_OF_FILE'
  984. X/* This program is Copyright (c) 1991 David Allen.  It may be freely
  985. X   distributed as long as you leave my name and copyright notice on it.
  986. X   I'd really like your comments and feedback; send e-mail to
  987. X   allen@viewlogic.com, or send us-mail to David Allen, 10 O'Moore Ave,
  988. X   Maynard, MA 01754.
  989. X
  990. X   Based on code written by by George Ferguson (ferguson@cs.rochester.edu),
  991. X   28 Apr 1990.  That code was intended for an X version of "tec", never
  992. X   released. */
  993. X
  994. X#include <math.h>
  995. X#include <X11/StringDefs.h>
  996. X#include <X11/Intrinsic.h>
  997. X#include <X11/keysym.h>
  998. X#include <X11/Xaw/Box.h>
  999. X#include <X11/Xaw/Command.h>
  1000. X#include <X11/Xaw/Viewport.h>
  1001. X#include <X11/Shell.h>
  1002. X#include "const.h"
  1003. X#include "clim.h"
  1004. X
  1005. X#define SIZE 6
  1006. X#define WINDOW_HEIGHT   (SIZE*MAXX)
  1007. X#define WINDOW_WIDTH    (SIZE*MAXY)
  1008. X
  1009. Xextern int MAXSTEP, XSIZE, YSIZE, step;
  1010. Xint picktype = M_HEAT;
  1011. X
  1012. Xstatic XtAppContext appc;
  1013. Xstatic Display *Dis;
  1014. Xstatic Window Win;
  1015. Xstatic Pixmap Pix;
  1016. Xstatic Pixmap Pixsave;
  1017. Xstatic GC gc_def;
  1018. Xstatic GC Gc[32];
  1019. X
  1020. X
  1021. Xstatic Arg simple_args[] = {
  1022. X   {XtNfromVert, (XtArgVal) NULL},
  1023. X   {XtNheight, (XtArgVal) WINDOW_HEIGHT},
  1024. X   {XtNwidth, (XtArgVal) WINDOW_WIDTH} };
  1025. X
  1026. X
  1027. Xunsigned char landcols [] = { 11, 28, 3 }, greycols[256], tecols[256];
  1028. Xunsigned char climcols [] = { 9, 20, 18, 2, 3, 18, 22, 26, 14, 17, 12 };
  1029. Xstatic char *color_names[] = {
  1030. X   "black","white","grey75", "grey50",
  1031. X   "MediumPurple1","purple4","purple3","purple2","purple1",
  1032. X   "blue4","blue3","blue2","blue1",
  1033. X   "DarkGreen","green4","green3","green2","green1",
  1034. X   "DarkGoldenrod4","yellow4","yellow3","yellow2","yellow1",
  1035. X   "orange4","orange3","orange2","orange1",
  1036. X   "brown4","red4","red3","red2","red1" };
  1037. X
  1038. X
  1039. Xmain (argc,argv) int argc; char **argv; {
  1040. X   Widget toplevel, top_form, surface;
  1041. X   XWindowAttributes wattr; ushort seed16v[3];
  1042. X
  1043. X   XtToolkitInitialize ();
  1044. X   appc = XtCreateApplicationContext ();
  1045. X
  1046. X   Dis = XtOpenDisplay (appc, NULL, NULL, "Demo", NULL, 0, &argc, argv);
  1047. X   toplevel = XtAppCreateShell (NULL, NULL, applicationShellWidgetClass,
  1048. X      Dis, NULL, 0);
  1049. X   top_form = XtCreateManagedWidget ("top form", formWidgetClass,
  1050. X      toplevel, NULL, 0);
  1051. X   surface = XtCreateManagedWidget ("drawing surface", simpleWidgetClass,
  1052. X      top_form, simple_args, XtNumber(simple_args));
  1053. X   XtRealizeWidget (toplevel);
  1054. X
  1055. X   Win = XtWindow (surface);
  1056. X   XGetWindowAttributes (Dis, Win, &wattr);
  1057. X   Pix = XCreatePixmap (Dis, Win, WINDOW_WIDTH, WINDOW_HEIGHT, wattr.depth);
  1058. X   Pixsave = XCreatePixmap (Dis, Win, WINDOW_WIDTH, WINDOW_HEIGHT, wattr.depth);
  1059. X   XSelectInput (Dis, Win,
  1060. X      ExposureMask | ButtonPressMask | ButtonReleaseMask |
  1061. X      KeyPressMask | StructureNotifyMask );
  1062. X
  1063. X   gc_def = DefaultGC (Dis, DefaultScreen (Dis));
  1064. X   assign_colors ();
  1065. X   XFlush (Dis);
  1066. X
  1067. X   /* Initialize random number generator */
  1068. X   srand (time ((long *) 0));    /* initialize rand() */
  1069. X   seed16v[0] = rand(); seed16v[1] = rand(); seed16v[2] = rand();
  1070. X   seed48 (seed16v);    /* initialize lrand48() */
  1071. X
  1072. X   XFillRectangle (Dis, Pix, Gc[0], 0, 0, MAXX*SIZE, MAXY*SIZE); redraw ();
  1073. X   init (*++argv);
  1074. X   for (step=0; step<MAXSTEP; step++) {
  1075. X      onestep();
  1076. X      redraw();
  1077. X      checkmouse (); }
  1078. X   XtDestroyApplicationContext (appc);
  1079. X   return (0); }
  1080. X
  1081. X
  1082. Xassign_colors () {
  1083. X   Colormap colormap; XColor screen_in_out,exact; int i;
  1084. X
  1085. X   for (i=0; i<256; i++) greycols[i] = 4.0 + (double) i * 27.0 / 254.0;
  1086. X   for (i=0; i<16; i++)  tecols[i] = 0;
  1087. X   for (; i<80; i++)     tecols[i] = 4.0 + (double) (i-16) * 27.0 / 62.0;
  1088. X   for (; i<256; i++)    tecols[i] = 1;
  1089. X
  1090. X   colormap = DefaultColormap (Dis, DefaultScreen(Dis));
  1091. X   for (i=0; i < 32; i++) {
  1092. X      XAllocNamedColor (Dis, colormap, color_names[i], &screen_in_out, &exact);
  1093. X      Gc[i] = XCreateGC (Dis, Win, 0, (XGCValues *) NULL);
  1094. X      XSetForeground (Dis, Gc[i], screen_in_out.pixel);
  1095. X      if (i == 0) XSetForeground (Dis, gc_def, screen_in_out.pixel); } }
  1096. X
  1097. X
  1098. X/* Each call to this routine dispatches any pending events.  We are only
  1099. X   interested in expose events which require a redraw, and the letter 'q'
  1100. X   being pressed to quit.  */
  1101. Xcheckmouse () { XEvent e; char c; KeySym sym; XComposeStatus status;
  1102. X   while (XtAppPending (appc)) { /* while there are events */
  1103. X      XtAppNextEvent (appc, &e);    /* get one */
  1104. X      switch (e.type) {             /* and process it */
  1105. X         case Expose:
  1106. X            if (e.xexpose.window != Win) XtDispatchEvent(&e);
  1107. X            else if (e.xexpose.count == 0) redraw ();
  1108. X            break;
  1109. X         case KeyPress:
  1110. X            XLookupString(&e,&c,1,&sym,&status);
  1111. X            switch (sym) {
  1112. X               case XK_q: step     = MAXSTEP; break;
  1113. X               case XK_h: picktype = M_HEAT;  break;
  1114. X               case XK_p: picktype = M_PRESS; break;
  1115. X               case XK_w: picktype = M_WIND;  break;
  1116. X               case XK_r: picktype = M_RAIN;  break;
  1117. X               case XK_c: picktype = M_CLIM;  break; }
  1118. X            break;
  1119. X         default: XtDispatchEvent(&e); } } }
  1120. X
  1121. X
  1122. Xredraw () {
  1123. X   XCopyArea (Dis, Pix, Win, Gc[0], 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, 0, 0);
  1124. X   XFlush (Dis); }
  1125. X
  1126. X
  1127. Xrnd (top) short top; { return (lrand48 () % top); }
  1128. X
  1129. X
  1130. Xpanic (s) char *s; { printf ("PANIC: %s\n", s); exit (1); }
  1131. X
  1132. X
  1133. Xdraw (ctype, ltype, cra, lra)
  1134. X   int ctype, ltype;
  1135. X   unsigned char cra[MAXX][MAXY], lra[MAXX][MAXY]; {
  1136. X   register short i, j, k, x; unsigned char *lut;
  1137. X
  1138. X   switch (ctype) {
  1139. X      case DRAW_GREY: lut = greycols; break;
  1140. X      case DRAW_LAND: lut = landcols; break;
  1141. X      case DRAW_CLIM: lut = climcols; break;
  1142. X      case DRAW_TEC:  lut = tecols;   break; }
  1143. X   for (j=0; j < YSIZE; j++) for (i=0; i < XSIZE-1; i++) {
  1144. X      x = lut[cra[i][j]]; k = i+1;
  1145. X      while ((lut[cra[k][j]] == x) && (k < XSIZE-1)) k++;
  1146. X      XFillRectangle (Dis, Pix, Gc[x], i*SIZE, j*SIZE, (k-i)*SIZE, SIZE);
  1147. X      i = k-1; }
  1148. X   switch (ltype) {
  1149. X      case LINE_DIAG: diagonal (lra); break;
  1150. X      case LINE_CORN: corner   (lra); break;
  1151. X      case LINE_NONE: break; } }
  1152. X
  1153. X
  1154. X#define LEFT(i,j,x) \
  1155. X   XDrawLine (Dis, Pix, Gc[x], i*SIZE, j*SIZE, i*SIZE, (j+1)*SIZE)
  1156. X#define ABOVE(i,j,x) \
  1157. X   XDrawLine (Dis, Pix, Gc[x], i*SIZE, j*SIZE, (i+1)*SIZE, j*SIZE)
  1158. X#define UPLEFT(i,j,x) \
  1159. X   XDrawLine (Dis, Pix, Gc[x], i*SIZE, j*SIZE, (i+1)*SIZE, (j+1)*SIZE)
  1160. X#define UPRIGHT(i,j,x) \
  1161. X   XDrawLine (Dis, Pix, Gc[x], (i+1)*SIZE, j*SIZE, i*SIZE, (j+1)*SIZE)
  1162. X
  1163. X
  1164. Xdiagonal (ra) unsigned char ra[MAXX][MAXY]; { register short i, j;
  1165. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++)
  1166. X      switch (ra[i][j]) {
  1167. X         case 0:   break;
  1168. X         case N:   LEFT    (i, j, 0); break;
  1169. X         case S:   LEFT    (i, j, 1); break;
  1170. X         case E:   ABOVE   (i, j, 1); break;
  1171. X         case W:   ABOVE   (i, j, 0); break;
  1172. X         case N|E: UPRIGHT (i, j, 0); break;
  1173. X         case N|W: UPLEFT  (i, j, 0); break;
  1174. X         case S|E: UPLEFT  (i, j, 1); break;
  1175. X         case S|W: UPRIGHT (i, j, 1); break; } }
  1176. X
  1177. X
  1178. Xcorner (ra) unsigned char ra[MAXX][MAXY]; { register short i, j, x;
  1179. X   for (j=0; j<YSIZE; j++) for (i=0; i<XSIZE; i++) {
  1180. X      x = ra[i][j];
  1181. X      if      (x & LINE_0V) LEFT  (i, j, 0);
  1182. X      else if (x & LINE_1V) LEFT  (i, j, 1);
  1183. X      if      (x & LINE_0H) ABOVE (i, j, 0);
  1184. X      else if (x & LINE_1H) ABOVE (i, j, 1); } }
  1185. END_OF_FILE
  1186.   if test 7119 -ne `wc -c <'./src/x.c'`; then
  1187.     echo shar: \"'./src/x.c'\" unpacked with wrong size!
  1188.   fi
  1189.   # end of './src/x.c'
  1190. fi
  1191. echo shar: End of archive 3 \(of 4\).
  1192. cp /dev/null ark3isdone
  1193. MISSING=""
  1194. for I in 1 2 3 4 ; do
  1195.     if test ! -f ark${I}isdone ; then
  1196.     MISSING="${MISSING} ${I}"
  1197.     fi
  1198. done
  1199. if test "${MISSING}" = "" ; then
  1200.     echo You have unpacked all 4 archives.
  1201.     rm -f ark[1-9]isdone
  1202. else
  1203.     echo You still must unpack the following archives:
  1204.     echo "        " ${MISSING}
  1205. fi
  1206. exit 0
  1207. exit 0 # Just in case...
  1208. -- 
  1209. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1210. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1211. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1212. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1213.