home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Interactive Guide / c-cplusplus-interactive-guide.iso / c_ref / csource1 / ast40dos / xgeneral.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-04  |  40.7 KB  |  1,421 lines

  1. /*
  2. ** Astrolog (Version 4.00) File: xgeneral.c
  3. **
  4. ** IMPORTANT NOTICE: the graphics database and chart display routines
  5. ** used in this program are Copyright (C) 1991-1993 by Walter D. Pullen
  6. ** (cruiser1@stein.u.washington.edu). Permission is granted to freely
  7. ** use and distribute these routines provided one doesn't sell,
  8. ** restrict, or profit from them in any way. Modification is allowed
  9. ** provided these notices remain with any altered or edited versions of
  10. ** the program.
  11. **
  12. ** The main planetary calculation routines used in this program have
  13. ** been Copyrighted and the core of this program is basically a
  14. ** conversion to C of the routines created by James Neely as listed in
  15. ** Michael Erlewine's 'Manual of Computer Programming for Astrologers',
  16. ** available from Matrix Software. The copyright gives us permission to
  17. ** use the routines for personal use but not to sell them or profit from
  18. ** them in any way.
  19. **
  20. ** The PostScript code within the core graphics routines are programmed
  21. ** and Copyright (C) 1992-1993 by Brian D. Willoughby
  22. ** (brianw@sounds.wa.com). Conditions are identical to those above.
  23. **
  24. ** The extended accurate ephemeris databases and formulas are from the
  25. ** calculation routines in the program "Placalc" and are programmed and
  26. ** Copyright (C) 1989,1991,1993 by Astrodienst AG and Alois Treindl
  27. ** (alois@azur.ch). The use of that source code is subject to
  28. ** regulations made by Astrodienst Zurich, and the code is not in the
  29. ** public domain. This copyright notice must not be changed or removed
  30. ** by any user of this program.
  31. **
  32. ** Initial programming 8/28,30, 9/10,13,16,20,23, 10/3,6,7, 11/7,10,21/1991.
  33. ** X Window graphics initially programmed 10/23-29/1991.
  34. ** PostScript graphics initially programmed 11/29-30/1992.
  35. ** Last code change made 12/31/1993.
  36. */
  37.  
  38. #include "astrolog.h"
  39.  
  40. #ifdef GRAPH
  41.  
  42. int xpen, ypen;
  43.  
  44.  
  45. /*
  46. ******************************************************************************
  47. ** Bitmap File Routines.
  48. ******************************************************************************
  49. */
  50.  
  51. /* Write the bitmap array to a previously opened file in a format that   */
  52. /* can be read in by the Unix X commands bitmap and xsetroot. The 'mode' */
  53. /* parameter defines how much white space is put in the file.            */
  54.  
  55. void WriteXBitmap(data, name, mode)
  56. FILE *data;
  57. char *name, mode;
  58. {
  59.   int x, y, i, temp = 0;
  60.   uint value;
  61.  
  62.   fprintf(data, "#define %s_width %d\n" , name, chartx);
  63.   fprintf(data, "#define %s_height %d\n", name, charty);
  64.   fprintf(data, "static %s %s_bits[] = {",
  65.     mode != 'V' ? "char" : "short", name);
  66.   for (y = 0; y < charty; y++) {
  67.     x = 0;
  68.     do {
  69.  
  70.       /* Process each row, eight columns at a time. */
  71.  
  72.       if (y + x > 0)
  73.         fprintf(data, ",");
  74.       if (temp == 0)
  75.         fprintf(data, "\n%s",
  76.           mode == 'N' ? "  " : (mode == 'C' ? " " : ""));
  77.       value = 0;
  78.       for (i = (mode != 'V' ? 7 : 15); i >= 0; i--)
  79.         value = (value << 1) +
  80.           (!(PGET(bm, x+i, y)^(xreverse*15))^xreverse && (x + i < chartx));
  81.       if (mode == 'N')
  82.         putc(' ', data);
  83.       fprintf(data, "0x");
  84.       if (mode == 'V')
  85.         fprintf(data, "%c%c",
  86.           INTTOHEX(value >> 12), INTTOHEX((value >> 8) & 15));
  87.       fprintf(data, "%c%c",
  88.         INTTOHEX((value >> 4) & 15), INTTOHEX(value & 15));
  89.       temp++;
  90.  
  91.       /* Is it time to skip to the next line while writing the file yet? */
  92.  
  93.       if ((mode == 'N' && temp >= 12) ||
  94.           (mode == 'C' && temp >= 15) ||
  95.           (mode == 'V' && temp >= 11))
  96.         temp = 0;
  97.       x += (mode != 'V' ? 8 : 16);
  98.     } while (x < chartx);
  99.   }
  100.   fprintf(data, "};\n");
  101. }
  102.  
  103.  
  104. /* Write the bitmap array to a previously opened file in a simple boolean    */
  105. /* Ascii rectangle, one char per pixel, where '#' represents an off bit and  */
  106. /* '-' an on bit. The output format is identical to the format generated by  */
  107. /* the Unix bmtoa command, and it can be converted into a bitmap with atobm. */
  108.  
  109. void WriteAscii(data)
  110. FILE *data;
  111. {
  112.   int x, y, i;
  113.  
  114.   for (y = 0; y < charty; y++) {
  115.     for (x = 0; x < chartx; x++) {
  116.       i = PGET(bm, x, y);
  117.       if (xcolor)
  118.         putc(INTTOHEX(i), data);
  119.       else
  120.         putc(i ? '-' : '#', data);
  121.     }
  122.     putc('\n', data);
  123.   }
  124. }
  125.  
  126.  
  127. /* Write the bitmap array to a previously opened file in the bitmap format  */
  128. /* used in Microsoft Windows for its .bmp extension files. This is a pretty */
  129. /* efficient format, only requiring one bit per pixel and a small header.   */
  130.  
  131. void WriteBmp(data)
  132. FILE *data;
  133. {
  134.   int x, y;
  135.   dword value;
  136.  
  137.   /* BitmapFileHeader */
  138.   PutByte('B'); PutByte('M');
  139.   PutLong(14+40 + (xcolor ? 64 : 8) +
  140.     (long)4*charty*((chartx-1 >> (xcolor ? 3 : 5))+1));
  141.   PutWord(0); PutWord(0);
  142.   PutLong(14+40 + (xcolor ? 64 : 8));
  143.   /* BitmapInfo / BitmapInfoHeader */
  144.   PutLong(40);
  145.   PutLong(chartx); PutLong(charty);
  146.   PutWord(1); PutWord(xcolor ? 4 : 1);
  147.   PutLong(0 /*BI_RGB*/); PutLong(0);
  148.   PutLong(0); PutLong(0);
  149.   PutLong(0); PutLong(0);
  150.   /* RgbQuad */
  151.   if (xcolor)
  152.     for (x = 0; x < 16; x++) {
  153.       PutByte(RGBB(rgbbmp[x])); PutByte(RGBG(rgbbmp[x]));
  154.       PutByte(RGBR(rgbbmp[x])); PutByte(0);
  155.     }
  156.   else {
  157.     PutLong(0);
  158.     PutByte(255); PutByte(255); PutByte(255); PutByte(0);
  159.   }
  160.   /* Data */
  161.   for (y = charty-1; y >= 0; y--) {
  162.     value = 0;
  163.     for (x = 0; x < chartx; x++) {
  164.       if ((x & (xcolor ? 7 : 31)) == 0 && x > 0) {
  165.         PutLong(value);
  166.         value = 0;
  167.       }
  168.       if (xcolor)
  169.         value |= (dword)PGET(bm, x, y) << ((x & 7 ^ 1) << 2);
  170.       else
  171.         if (PGET(bm, x, y))
  172.           value |= (dword)1 << (x & 31 ^ 7);
  173.     }
  174.     PutLong(value);
  175.   }
  176. }
  177.  
  178.  
  179. /* Output the bitmap in memory to a file. This basically consists of just    */
  180. /* calling some routine to actually write a bitmap to a file, although we    */
  181. /* need to prompt the user for a filename if it wasn't specified beforehand. */
  182.  
  183. void WriteFile()
  184. {
  185.   char line[STRING];
  186.   FILE *data;
  187.  
  188. #ifdef PS
  189.   if (psfile) {
  190.       PSend();
  191.     return;
  192.   }
  193. #endif
  194.   if (outputfile == NULL && (metafile || (xbitmap && bitmapmode == 'B')))
  195.     fprintf(stdout, "(It is recommended to specify an extension of '.%s'.)\n",
  196.       xbitmap ? "bmp" : "wmf");
  197.   loop {
  198.     if (outputfile == NULL) {
  199.       sprintf(line, "Enter name of file to write %s to",
  200.         xbitmap ? "bitmap" : "metafile");
  201.       InputString(line, line);
  202.       outputfile = line;
  203.     }
  204.     data = fopen(outputfile, "wb");
  205.     if (data != NULL)
  206.       break;
  207.     else {
  208.       PrintWarning("Couldn't create output file.");
  209.       outputfile = NULL;
  210.     }
  211.   }
  212.   if (xbitmap) {
  213.     if (bitmapmode == 'B')
  214.       WriteBmp(data);
  215.     else if (bitmapmode == 'A')
  216.       WriteAscii(data);
  217.     else
  218.       WriteXBitmap(data, outputfile, bitmapmode);
  219.   }
  220. #ifdef META
  221.   else
  222.     WriteMeta(data);
  223. #endif
  224.   fclose(data);
  225. }
  226.  
  227.  
  228. /*
  229. ******************************************************************************
  230. ** PostScript File Routines.
  231. ******************************************************************************
  232. */
  233.  
  234. #ifdef PS
  235.  
  236. /* Global variables used by the PostScript generator. */
  237.  
  238. FILE *psdata;
  239. int strokecount = 0, currentlinecap = 0, currentdash = 0, currentfont = 0;
  240. real currentlinewidth = 1.0;
  241.  
  242. /* Table of PostScript header alias lines used by the program. */
  243.  
  244. char PSfunctions[] =
  245. "/languagelevel where{pop languagelevel}{1}ifelse\
  246.  2 lt{\n\
  247. /sf{exch findfont exch\
  248.  dup type/arraytype eq{makefont}{scalefont}ifelse setfont}bind def\n\
  249. /rf{gsave newpath\n\
  250. 4 -2 roll moveto\
  251.  dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath\n\
  252. fill grestore}bind def\n\
  253. /rc{newpath\n\
  254. 4 -2 roll moveto\
  255.  dup 0 exch rlineto exch 0 rlineto neg 0 exch rlineto closepath\n\
  256. clip newpath}bind def\n\
  257. }{/sf/selectfont load def/rf/rectfill load def\
  258. /rc/rectclip load def}ifelse\n\
  259. /center{0 begin gsave dup 4 2 roll\
  260.  translate newpath 0 0 moveto\
  261.  false charpath flattenpath pathbbox\
  262.  /URy exch def/URx exch def/LLy exch def/LLx exch def\
  263.  URx LLx sub 0.5 mul LLx add neg URy LLy sub 0.5 mul LLy add neg\
  264.  0 0 moveto rmoveto\
  265.  show grestore end}bind def\n\
  266. /center load 0 4 dict put\n\
  267. /c{setrgbcolor}bind def\n\
  268. /d{moveto 0 0 rlineto}bind def\n\
  269. /l{4 2 roll moveto lineto}bind def\n\
  270. /t{lineto}bind def\n\
  271. /el{newpath matrix currentmatrix 5 1 roll translate scale\
  272.  0 0 1 0 360 arc setmatrix stroke}bind def\n";
  273.  
  274.  
  275. /* Write a command to flush the PostScript buffer. */
  276.  
  277. void PSforcestroke()
  278. {
  279.   if (strokecount > 0) {            /* render any existing path */
  280.     fprintf(psdata, "stroke\n");
  281.     strokecount = 0;
  282.     xpen = -1;                      /* Invalidate PolyLine cache */
  283.   }
  284. }
  285.  
  286.  
  287. /* Indicate that a certain number of PostScript commands have been done. */
  288.  
  289. void PSstroke(n)
  290. int n;
  291. {
  292.   strokecount += n;
  293.   if (strokecount > 5000)    /* Whenever we reach a certain limit, flush. */
  294.     PSforcestroke();
  295. }
  296.  
  297.  
  298. /* Set the type of line end to be used by PostScript commands. If linecap */
  299. /* is true, then the line ends are rounded, otherwise they are squared.   */
  300.  
  301. void PSlinecap(linecap)
  302. int linecap;
  303. {
  304.   if (linecap != currentlinecap) {
  305.     PSforcestroke();
  306.     fprintf(psdata, "%d setlinecap\n", linecap);
  307.     currentlinecap = linecap;
  308.   }
  309. }
  310.  
  311.  
  312. /* Set the dash length to be used by PostScript line commands. */
  313.  
  314. void PSdash(dashoff)
  315. int dashoff;
  316. {
  317.   if (dashoff != currentdash) {
  318.     PSforcestroke();
  319.     if (dashoff)
  320.       fprintf(psdata, "[%d %d", PSMUL, dashoff * PSMUL);
  321.     else
  322.       fprintf(psdata, "[");
  323.     fprintf(psdata, "]0 setdash\n");
  324.     currentdash = dashoff;
  325.   }
  326. }
  327.  
  328.  
  329. /* Set a linewidth size to be used by PostScript figure primitive commands. */
  330.  
  331. void PSlinewidth(linewidth)
  332. int linewidth;
  333. {
  334.   real oldlinewidth = currentlinewidth;
  335.  
  336.   if (linewidth != currentlinewidth) {
  337.     PSforcestroke();
  338.     fprintf(psdata, "%d setlinewidth\n", linewidth);
  339.     currentlinewidth = linewidth;
  340.   }
  341. }
  342.  
  343.  
  344. /* Set a system font and size to be used by PostScript text commands. */
  345.  
  346. void PSfont(psfont)
  347. int psfont;
  348. {
  349.   int temp;
  350.  
  351.   if (psfont != currentfont && xfont) {
  352.     if (psfont <= 2) {
  353.       temp = psfont == 1 ? 32*PSMUL : 23*PSMUL;
  354.         fprintf(psdata, "/Astro[%d 0 0 -%d 0 0]sf\n", temp, temp);
  355.     } else if (psfont == 3) {
  356.       temp = 26*PSMUL;
  357.       fprintf(psdata, "/Times-Roman[%d 0 0 -%d 0 0]sf\n", temp, temp);
  358.     } else {
  359.       temp = 10*PSMUL;
  360.       fprintf(psdata, "/Courier[%d 0 0 -%d 0 0]sf\n", temp, temp);
  361.     }
  362.     currentfont = psfont;
  363.   }
  364. }
  365.  
  366.  
  367. /* Prompt the user for the name of a file to write the PostScript file to */
  368. /* (if not already specified), open it, and write out file header info.   */
  369.  
  370. void PSbegin()
  371. {
  372.   char line[STRING];
  373.  
  374.   if (outputfile == NULL && epsfile)
  375.     fprintf(stdout,
  376.       "(It is recommended to specify an extension of '.eps'.)\n");
  377.   loop {
  378.     if (outputfile == NULL) {
  379.       sprintf(line, "Enter name of file to write PostScript to");
  380.       InputString(line, line);
  381.       outputfile = line;
  382.     }
  383.     psdata = fopen(outputfile, "w");
  384.     if (psdata != NULL)
  385.       break;
  386.     else {
  387.       PrintWarning("Couldn't create output file.");
  388.       outputfile = NULL;
  389.     }
  390.   }
  391.   fprintf(psdata, "%%!PS-Adobe-2.0");
  392.   if (epsfile)
  393.     fprintf(psdata, " EPSF-2.0");
  394.   fprintf(psdata, "\n%%%%Title: %s\n", outputfile);
  395.   fprintf(psdata, "%%%%Creator: %s %s\n", appname, VERSION);
  396.   fprintf(psdata, "%%%%CreationDate: %s\n", DATE);
  397.   if (epsfile) {
  398.     fprintf(psdata, "%%%%BoundingBox: 0 0 %d %d\n", chartx, charty);
  399.     fprintf(psdata, "%%%%EndComments\n");
  400.     fprintf(psdata, "%%%%BeginSetup\n");
  401.     fprintf(psdata, PSfunctions, 6 * PSMUL, 6 * PSMUL);
  402.     fprintf(psdata, "%%%%EndSetup\n");
  403.     fprintf(psdata, "0 0 %d %d rc\n", chartx, charty);
  404.   } else {
  405.     fprintf(psdata, "%%%%Pages: 1 1\n");
  406.     fprintf(psdata, "%%%%DocumentFonts: (atend)\n");
  407.     fprintf(psdata, "%%%%BoundingBox: 9 9 603 783\n");    /* 8.5" x 11" */
  408.     fprintf(psdata, "%%%%EndComments\n");
  409.     fprintf(psdata, "%%%%BeginProcSet: common\n");
  410.     fprintf(psdata, PSfunctions, 6 * PSMUL, 6 * PSMUL);
  411.     fprintf(psdata, "%%%%EndProcSet\n");
  412.     fprintf(psdata, "%%%%Page: 1 1\n");
  413.   }
  414.   PSfont(2);
  415.   fprintf(psdata, "gsave\n");
  416.   PSlinewidth(metawid/2);
  417.   xpen = -1;
  418. }
  419.  
  420.  
  421. /* Write out trailing information to the PostScript file and close it. */
  422.  
  423. void PSend()
  424. {
  425.   PSforcestroke();
  426.   if (epsfile)
  427.     fprintf(psdata, "%%%%EOF\n");
  428.   else {
  429.     fprintf(psdata, "showpage\n");
  430.     fprintf(psdata, "%%%%PageTrailer\n");
  431.     fprintf(psdata, "%%%%Trailer\n");
  432.     fprintf(psdata, "%%%%DocumentFonts: Times-Roman\n");
  433.     if (xfont) {
  434.       fprintf(psdata, "%%%%+ Courier\n");
  435.       fprintf(psdata, "%%%%+ Astro\n");
  436.     }
  437.   }
  438.   fclose(psdata);
  439. }
  440. #endif /* PS */
  441.  
  442.  
  443. /*
  444. ******************************************************************************
  445. ** Metafile Routines.
  446. ******************************************************************************
  447. */
  448.  
  449. #ifdef META
  450.  
  451. /* Global variables used by the metafile generator. */
  452.  
  453. colpal metalinedes, metalineact = -1,    /* Desired and actual line color. */
  454.   metafilldes,      metafillact = -1,    /* Desired and actual fill color. */
  455.   metafontdes = -1, metafontact = -1,    /* Desired and actual text font.  */
  456.   metatxtcdes = -1, metatxtcact = -1,    /* Desired and actual text color. */
  457.   metatxtades = -1, metatxtaact = -1;    /* Desired/actual text alignment. */
  458.  
  459. /* Macros to output the various metafile commands we use. */
  460.  
  461. #define MetaRecord(S, R) MetaLong((long)(S)); MetaWord(R)
  462. #define MetaSelectObject(O) MetaRecord(4, 0x12D); MetaWord(O)
  463. #define MetaDeleteObject(O) MetaRecord(4, 0x1F0); MetaWord(O)
  464. #define MetaSaveDc() MetaRecord(3, 0x01E)
  465. #define MetaRestoreDc() MetaRecord(4, 0x127); MetaWord(-1)
  466. #define MetaWindowOrg(X, Y) MetaRecord(5, 0x20B); MetaWord(Y); MetaWord(X)
  467. #define MetaWindowExt(X, Y) MetaRecord(5, 0x20C); MetaWord(Y); MetaWord(X)
  468. #define MetaCreatePen(S, W, C) MetaRecord(8, 0x2FA); MetaWord(S); \
  469.   MetaWord(W); MetaWord(W); MetaLong(C)
  470. #define MetaCreateBrush(S, C) MetaRecord(7, 0x2FC); \
  471.   MetaWord(S); MetaLong(C); MetaWord(0 /* Not used */);
  472. #define MetaCreateFont(S, X, Y, C) MetaRecord(12+(S), 0x2FB); MetaWord(Y); \
  473.   MetaWord(X); MetaWord(0 /* Angle */); MetaWord(0 /* Not used */); \
  474.   MetaWord(400 /* Normal Weight */); MetaWord(0 /* Italic, Underline */); \
  475.   MetaWord(MAKEWORD(0 /* Strikeout */, C)); \
  476.   MetaWord(MAKEWORD(4 /* TrueType */, 0 /* Clip */))
  477. #define MetaBkMode(M) MetaRecord(4, 0x102); MetaWord(M)
  478. #define MetaTextAlign(A) MetaRecord(4, 0x12E); MetaWord(A)
  479. #define MetaTextColor(C) MetaRecord(5, 0x209); MetaLong(C);
  480. #define MetaTextOut(X, Y, S) MetaRecord(7+((S)+1)/2, 0xA32); \
  481.   MetaWord(Y); MetaWord(X); MetaWord(S); MetaWord(0 /* ETO */)
  482. #define MetaRectangle(X1, Y1, X2, Y2) MetaRecord(7, 0x41B); \
  483.   MetaWord(Y2); MetaWord(X2); MetaWord(Y1); MetaWord(X1)
  484. #define MetaEllipse(X1, Y1, X2, Y2) MetaRecord(7, 0x418); \
  485.   MetaWord(Y2); MetaWord(X2); MetaWord(Y1); MetaWord(X1)
  486. #define MetaEscape(S) MetaRecord((S), 0x626); \
  487.   MetaWord(15 /* MFCOMMENT */); MetaWord(((S)-5)*2 /* Bytes in comment */);
  488.  
  489.  
  490. /* Output one 16 bit or 32 bit value into the metafile buffer stream. */
  491.  
  492. void MetaWord(w)
  493. word w;
  494. {
  495.   if ((byte PTR)metacur - bm >= MAXMETA) {
  496.     PrintError("Metafile would be more than %ld bytes.", MAXMETA);
  497.     Terminate(_FATAL);
  498.   }
  499.   *metacur = w;
  500.   metacur++;
  501. }
  502.  
  503. void MetaLong(l)
  504. long l;
  505. {
  506.   MetaWord(LOWORD(l));
  507.   MetaWord(HIWORD(l));
  508. }
  509.  
  510.  
  511. /* Output any necessary metafile records to make the current actual     */
  512. /* settings of line color, fill color, etc, be those that we know are   */
  513. /* desired. This is generally called by the primitives routines before  */
  514. /* any figure record is actually written into a metafile. We wait until */
  515. /* the last moment before changing any settings to ensure that we don't */
  516. /* output any unnecessary records, e.g. two select colors in a row.     */
  517.  
  518. void MetaSelect()
  519. {
  520.   if (metalinedes != metalineact) {
  521.     MetaSelectObject(metalinedes);
  522.     metalineact = metalinedes;
  523.   }
  524.   if (metafilldes != metafillact) {
  525.     MetaSelectObject(16*4 + metafilldes);
  526.     metafillact = metafilldes;
  527.   }
  528.   if (metafontdes != metafontact) {
  529.     MetaSelectObject(16*5 + metafontdes);
  530.     metafontact = metafontdes;
  531.   }
  532.   if (metatxtcdes != metatxtcact) {
  533.     MetaTextColor(rgbbmp[metatxtcdes]);
  534.     metatxtcact = metatxtcdes;
  535.   }
  536.   if (metatxtades != metatxtaact) {
  537.     MetaTextAlign(metatxtades);
  538.     metatxtaact = metatxtades;
  539.   }
  540.   xpen = -1;    /* Invalidate PolyLine cache */
  541. }
  542.  
  543.  
  544. /* Output initial metafile header information into our metafile buffer. */
  545. /* We also setup and create all pen, brush, and font objects that may   */
  546. /* possibly be used in the generation and playing of the picture.       */
  547.  
  548. void MetaInit()
  549. {
  550.   int i, j, k;
  551.  
  552.   metacur = (word PTR)bm;
  553.   /* Placable Metaheader */
  554.   MetaLong(0x9AC6CDD7L);
  555.   MetaWord(0);      /* Not used */
  556.   MetaWord(0); MetaWord(0);
  557.   MetaWord(chartx); MetaWord(charty);
  558.   MetaWord(chartx/6);  /* Units per inch */
  559.   MetaLong(0L);     /* Not used */
  560.   MetaWord(0x9AC6 ^ 0xCDD7 ^ chartx ^ charty ^ chartx/6);  /* Checksum */
  561.   /* Metaheader */
  562.   MetaWord(1);                   /* Metafile type */
  563.   MetaWord(9);                   /* Size of header in words */
  564.   MetaWord(0x300);               /* Windows version */
  565.   MetaLong(0L);                  /* Size of entire metafile in words */
  566.   MetaWord(16*5+1+(xfont>0)*4);  /* Number of objects in metafile */
  567.   MetaLong(17L);                 /* Size of largest record in words */
  568.   MetaWord(0);                   /* Not used */
  569.   /* Setup */
  570.   MetaEscape(17);
  571.   MetaLong(MAKEQUAD('A', 's', 't', 'r'));  /* "Astr" */
  572.   MetaWord(4);                             /* Creator */
  573.   MetaLong(14L);                           /* Bytes in string */
  574.   MetaLong(MAKEQUAD('A', 's', 't', 'r'));  /* "Astr" */
  575.   MetaLong(MAKEQUAD('o', 'l', 'o', 'g'));  /* "olog" */
  576.   MetaLong(MAKEQUAD(' ', '4', '.', '0'));  /* " 3.2" */
  577.   MetaWord(MAKEWORD('0', 0));              /* "0"    */
  578.   MetaSaveDc();
  579.   MetaWindowOrg(0, 0);
  580.   MetaWindowExt(chartx, charty);
  581.   MetaBkMode(1 /* Transparent */);
  582.   /* Colors */
  583.   for (j = 1; j <= 4; j++)
  584.     for (i = 0; i < 16; i++) {
  585.       k = j <= 1 ? metawid : 0;
  586.       MetaCreatePen(j <= 2 ? 0 : j-2 /* PS_SOLID; PS_DASH; PS_DOT */,
  587.         k, rgbbmp[i]);
  588.     }
  589.   for (i = 0; i < 16; i++) {
  590.     MetaCreateBrush(0 /* BS_SOLID */, rgbbmp[i]);
  591.   }
  592.   MetaCreateBrush(1 /* BS_NULL */, 0L);
  593.   /* Fonts */
  594.   if (xfont) {
  595.     MetaCreateFont(5, 0, -8*SCALE, 2 /* Symbol Charset */);
  596.     MetaWord(MAKEWORD(1 /* Draft */, 1 | 0x10 /* Fixed | Roman */));
  597.     MetaLong(MAKEQUAD('W', 'i', 'n', 'g'));
  598.     MetaLong(MAKEQUAD('d', 'i', 'n', 'g'));
  599.     MetaWord(MAKEWORD('s', 0));
  600.  
  601.     MetaCreateFont(8, 0, -6*SCALE, 0 /* Ansi Charset */);
  602.     MetaWord(MAKEWORD(0 /* Default */, 2 | 0x10 /* Variable | Roman */));
  603.     MetaLong(MAKEQUAD('T', 'i', 'm', 'e'));
  604.     MetaLong(MAKEQUAD('s', ' ', 'N', 'e'));
  605.     MetaLong(MAKEQUAD('w', ' ', 'R', 'o'));
  606.     MetaLong(MAKEQUAD('m', 'a', 'n', 0));
  607.  
  608.     MetaCreateFont(6, 6*METAMUL, 10*METAMUL, 0 /* Ansi Charset */);
  609.     MetaWord(MAKEWORD(1 /* Draft */, 1 | 0x30 /* Fixed | Modern */));
  610.     MetaLong(MAKEQUAD('C', 'o', 'u', 'r'));
  611.     MetaLong(MAKEQUAD('i', 'e', 'r', ' '));
  612.     MetaLong(MAKEQUAD('N', 'e', 'w', 0));
  613.  
  614.     MetaCreateFont(8, 0, -11*SCALE, 0 /* Ansi Charset */);
  615.     MetaWord(MAKEWORD(0 /* Default */, 2 | 0 /* Variable | Don't Care */));
  616.     MetaLong(MAKEQUAD('A', 's', 't', 'r'));
  617.     MetaLong(MAKEQUAD('o', '-', 'S', 'e'));
  618.     MetaLong(MAKEQUAD('m', 'i', 'B', 'o'));
  619.     MetaLong(MAKEQUAD('l', 'd', 0, 0));
  620.   }
  621. }
  622.  
  623.  
  624. /* Output trailing records to indicate the end of the metafile and then */
  625. /* actually write out the entire buffer to the specifed file.           */
  626.  
  627. void WriteMeta(data)
  628. FILE *data;
  629. {
  630.   word PTR w;
  631. #if FALSE
  632.   int i;
  633.  
  634.   for (i = 16*5+1+(xfont>0)*4; i >= 0; i--) {
  635.     MetaDeleteObject(i);
  636.   }
  637. #endif
  638.   MetaRestoreDc();
  639.   MetaRecord(3, NULL);    /* End record */
  640.   *(long PTR)(bm + 22 + 6) = ((long)((byte PTR)metacur - bm) - 22) / 2;
  641.   for (w = (word PTR)bm; w < metacur; w++) {
  642.     PutWord(*w);
  643.   }
  644. }
  645. #endif /* META */
  646.  
  647.  
  648. /*
  649. ******************************************************************************
  650. ** Core Graphic Procedures.
  651. ******************************************************************************
  652. */
  653.  
  654. /* Set the current color to use in drawing on the screen or bitmap array. */
  655.  
  656. void DrawColor(col)
  657. colpal col;
  658. {
  659. #ifdef PS
  660.   if (psfile) {
  661.     if (colcur != col) {
  662.       PSforcestroke();      /* Render existing path with current color */
  663.       fprintf(psdata, "%.2f %.2f %.2f c\n",
  664.         (real)RGBR(rgbbmp[col])/255.0, (real)RGBG(rgbbmp[col])/255.0,
  665.         (real)RGBB(rgbbmp[col])/255.0);
  666.     }
  667.     colcur = col;
  668.     return;
  669.   }
  670. #endif
  671. #ifdef META
  672.   if (metafile)
  673.     metalinedes = col;
  674. #endif
  675. #ifdef X11
  676.   else if (!xfile)
  677.     XSetForeground(disp, gc, rgbind[col]);
  678. #endif
  679. #ifdef MSG
  680.   else if (!xfile)
  681.     _setcolor(col);
  682. #endif
  683.   colcur = col;
  684. }
  685.  
  686.  
  687. /* Set a single point on the screen. This is the most basic graphic function */
  688. /* and is called by all the more complex routines. Based on what mode we are */
  689. /* in, we either set a cell in the bitmap array or a pixel on the window.    */
  690.  
  691. void DrawPoint(x, y)
  692. int x, y;
  693. {
  694.   if (xfile) {
  695.     if (xbitmap) {
  696.       /* Force the coordinates to be within the bounds of the bitmap array. */
  697.  
  698.       if (x < 0)
  699.         x = 0;
  700.       else if (x >= chartx)
  701.         x = chartx-1;
  702.       if (y < 0)
  703.         y = 0;
  704.       else if (y >= charty)
  705.         y = charty-1;
  706.       PSET(bm, x, y, colcur);
  707.     }
  708. #ifdef PS
  709.     else if (psfile) {
  710.       DrawColor(colcur);
  711.       PSlinecap(TRUE);
  712.       fprintf(psdata, "%d %d d\n", x, y);
  713.       PSstroke(2);
  714.     }
  715. #endif
  716. #ifdef META
  717.     else {
  718.       metafilldes = colcur;
  719.       MetaSelect();
  720.       MetaEllipse(x-metawid/2, y-metawid/2, x+metawid/2, y+metawid/2);
  721.     }
  722. #endif
  723.   }
  724. #ifdef X11
  725.   else
  726.     XDrawPoint(disp, pixmap, gc, x, y);
  727. #endif
  728. #ifdef MSG
  729.   else
  730.     _setpixel(offsetx + x, offsety + y);
  731. #endif
  732. }
  733.  
  734.  
  735. /* Draw dot a little larger than just a single pixel at specified location. */
  736.  
  737. void DrawSpot(x, y)
  738. int x, y;
  739. {
  740. #ifdef PS
  741.   if (psfile) {
  742.     PSlinewidth(currentlinewidth*3);
  743.     DrawPoint(x, y);
  744.     PSlinewidth(currentlinewidth/3);
  745.     return;
  746.   }
  747. #endif
  748. #ifdef META
  749.   if (metafile) {
  750.     metafilldes = colcur;
  751.     MetaSelect();
  752.     MetaEllipse(x-metawid, y-metawid, x+metawid, y+metawid);
  753.     return;
  754.   }
  755. #endif
  756.   DrawPoint(x, y);
  757.   DrawPoint(x, y-1);
  758.   DrawPoint(x-1, y);
  759.   DrawPoint(x+1, y);
  760.   DrawPoint(x, y+1);
  761. }
  762.  
  763.  
  764. /* Draw a filled in block, defined by the corners of its rectangle. */
  765.  
  766. void DrawBlock(x1, y1, x2, y2)
  767. int x1, y1, x2, y2;
  768. {
  769.   int x, y;
  770.  
  771.   if (xfile) {
  772.     if (xbitmap) {
  773.       for (y = y1; y <= y2; y++)         /* For bitmap, we have to  */
  774.         for (x = x1; x <= x2; x++)       /* just fill in the array. */
  775.           PSET(bm, x, y, colcur);
  776.     }
  777. #ifdef PS
  778.     else if (psfile) {
  779.       DrawColor(colcur);
  780.       fprintf(psdata, "%d %d %d %d rf\n",
  781.         x1-metawid/4, y1-metawid/4, x2-x1+metawid/4, y2-y1+metawid/4);
  782.     }
  783. #endif
  784. #ifdef META
  785.     else {
  786.       metafilldes = colcur;
  787.       MetaSelect();
  788.       MetaRectangle(x1-metawid/2, y1-metawid/2, x2+metawid/2, y2+metawid/2);
  789.     }
  790. #endif
  791.   }
  792. #ifdef X11
  793.   else
  794.     XFillRectangle(disp, pixmap, gc, x1, y1, x2, y2);
  795. #endif
  796. #ifdef MSG
  797.   else
  798.     _rectangle(_GFILLINTERIOR,
  799.       offsetx + x1, offsety + y1, offsetx + x2, offsety + y2);
  800. #endif
  801. }
  802.  
  803.  
  804. /* Draw a rectangle on the screen with specified thickness. This is just   */
  805. /* like DrawBlock() except that we are only drawing the edges of the area. */
  806.  
  807. void DrawBox(x1, y1, x2, y2, xsiz, ysiz)
  808. int x1, y1, x2, y2, xsiz, ysiz;
  809. {
  810. #ifdef META
  811.   if (metafile)
  812.     /* For thin boxes in metafiles, we can just output one rectangle record */
  813.     /* instead of drawing each side separately as we have to do otherwise.  */
  814.     if (xsiz <= 1 && ysiz <= 1) {
  815.       metafilldes = 16;              /* Specify a hollow fill brush. */
  816.       MetaSelect();
  817.       MetaRectangle(x1, y1, x2, y2);
  818.       return;
  819.     }
  820. #endif
  821.   DrawBlock(x1, y1, x2, y1 + ysiz - 1);
  822.   DrawBlock(x1, y1 + ysiz, x1 + xsiz - 1, y2 - ysiz);
  823.   DrawBlock(x2 - xsiz + 1, y1 + ysiz, x2, y2 - ysiz);
  824.   DrawBlock(x1, y2 - ysiz + 1, x2, y2);
  825. }
  826.  
  827.  
  828. /* Clear and erase the graphics screen or bitmap contents. */
  829.  
  830. void DrawClearScreen()
  831. {
  832. #ifdef PS
  833.   if (psfile) {
  834.     /* For PostScript charts first output page orientation information. */
  835.     if (!epsfile) {
  836.       if (modex == MODEL || modex == MODEW ||
  837.         (modex == MODEZ && (todisplay & DASHZ0) == 0)) {
  838.         /* Chartx and charty are reversed for Landscape mode. */
  839.         fprintf(psdata, "%d %d translate\n",
  840.           ((int)(8.5*72) + charty)/2, (chartx + 11*72)/2);
  841.         fprintf(psdata, "-90 rotate\n");
  842.       } else {
  843.         /* Most charts are in Portrait mode */
  844.         fprintf(psdata, "%d %d translate\n", (int)(8.5*72/2) - chartx/2,
  845.         charty/2 + 11*72/2);
  846.       }
  847.     } else
  848.       fprintf(psdata, "0 %d translate\n", charty);
  849.     fprintf(psdata, "1 -1 scale\n");
  850.     scale *= PSMUL; chartx *= PSMUL; charty *= PSMUL;
  851.     fprintf(psdata, "1 %d div dup scale\n", PSMUL);
  852.   }
  853. #endif
  854. #ifdef META
  855.   if (metafile)
  856.     MetaInit();    /* For metafiles first go write our header information. */
  857. #endif
  858.  
  859.   /* Hack: If a comparison relationship chart is set and we're in the -Z  */
  860.   /* horizon or -S space graphics chart modes (which normally is just the */
  861.   /* same as single chart graphics) don't actually clear the screen.      */
  862.  
  863.   if (relation <= DASHr0 && xnow > 0 && (modex == MODEZ || modex == MODES))
  864.     return;
  865. #ifdef MSG
  866.   if (!xfile)
  867.     _clearscreen(_GCLEARSCREEN);
  868. #endif
  869.   DrawColor(off);
  870.   DrawBlock(0, 0, chartx - 1, charty - 1);    /* Clear bitmap screen. */
  871. }
  872.  
  873.  
  874. /* Draw a line on the screen, specified by its endpoints. In addition, we */
  875. /* have specified a skip factor, which allows us to draw dashed lines.    */
  876.  
  877. void DrawDash(x1, y1, x2, y2, skip)
  878. int x1, y1, x2, y2, skip;
  879. {
  880.   static word PTR poly;
  881.   int x = x1, y = y1, xadd, yadd, yinc, xabs, yabs, i, j = 0;
  882.  
  883.   if (skip < 0)
  884.     skip = 0;
  885. #ifdef ISG
  886.   if (!xfile) {
  887.     if (!skip) {
  888. #ifdef X11
  889.       /* For non-dashed X window lines, let's have the Xlib do it for us. */
  890.  
  891.       XDrawLine(disp, pixmap, gc, x1, y1, x2, y2);
  892. #else
  893.       /* For non-dashed lines, let's have the graphics library do it for us. */
  894.  
  895.       _moveto(offsetx + x1, offsety + y1);
  896.       _lineto(offsetx + x2, offsety + y2);
  897. #endif
  898.       return;
  899.     }
  900.   }
  901. #endif /* ISG */
  902.  
  903. #ifdef PS
  904.   if (psfile) {
  905.  
  906.     /* For PostScript charts we can save file size if we output a LineTo  */
  907.     /* command when the start vertex is the same as the end vertex of the */
  908.     /* previous line drawn, instead of writing out both vertices.         */
  909.  
  910.     PSlinecap(TRUE);
  911.     PSdash(skip);
  912.     if (xpen != x1 || ypen != y1)
  913.       fprintf(psdata, "%d %d %d %d l\n", x1, y1, x2, y2);
  914.     else
  915.       fprintf(psdata, "%d %d t\n", x2, y2);
  916.     xpen = x2; ypen = y2;
  917.     PSstroke(2);
  918.     return;
  919.   }
  920. #endif
  921. #ifdef META
  922.   if (metafile) {
  923.  
  924.     /* For metafile charts we can really save file size for consecutive */
  925.     /* lines sharing endpoints by consolidating them into a PolyLine.   */
  926.  
  927.     if (xpen != x1 || ypen != y1) {
  928.       metalinedes = (metalinedes & 15) + 16*(skip > 3 ? 3 : skip);
  929.       MetaSelect();
  930.       poly = metacur;
  931.       MetaRecord(8, 0x325);    /* Polyline */
  932.       MetaWord(2); MetaWord(x1); MetaWord(y1);
  933.     } else {
  934.       *poly += 2;
  935.       (*(poly+3))++;
  936.       /* Note: We should technically update the max record size in the   */
  937.       /* file header if need be here too, but it doesn't seem necessary. */
  938.     }
  939.     MetaWord(x2); MetaWord(y2);
  940.     xpen = x2; ypen = y2;
  941.     return;
  942.   }
  943. #endif
  944.  
  945.   /* If none of the above cases hold, we have to draw the line dot by dot. */
  946.  
  947.   xadd = x2 - x1 >= 0 ? 1 : 3;
  948.   yadd = y2 - y1 >= 0 ? 2 : 4;
  949.   xabs = abs(x2 - x1);
  950.   yabs = abs(y2 - y1);
  951.  
  952.   /* Technically what we're doing here is drawing a line which is more    */
  953.   /* horizontal then vertical. We always increment x by 1, and increment  */
  954.   /* y whenever a fractional variable passes a certain amount. For lines  */
  955.   /* that are more vertical than horizontal, we just swap x and y coords. */
  956.  
  957.   if (xabs < yabs) {
  958.     SWAP(xadd, yadd);
  959.     SWAP(xabs, yabs);
  960.   }
  961.   yinc = (xabs >> 1) - ((xabs & 1 ^ 1) && xadd > 2);
  962.   for (i = xabs+1; i; i--) {
  963.     if (j < 1)
  964.       DrawPoint(x, y);
  965.     j = j < skip ? j+1 : 0;
  966.     switch (xadd) {
  967.     case 1: x++; break;
  968.     case 2: y++; break;
  969.     case 3: x--; break;
  970.     case 4: y--; break;
  971.     }
  972.     yinc += yabs;
  973.     if (yinc - xabs >= 0) {
  974.       yinc -= xabs;
  975.       switch (yadd) {
  976.       case 1: x++; break;
  977.       case 2: y++; break;
  978.       case 3: x--; break;
  979.       case 4: y--; break;
  980.       }
  981.     }
  982.   }
  983. }
  984.  
  985.  
  986. /* Draw a normal line on the screen; however, if the x coordinates are close */
  987. /* to either of the two given bounds, then we assume that the line runs off  */
  988. /* one side and reappears on the other, so draw the appropriate two lines    */
  989. /* instead. This is used by the Ley line and astro-graph routines, which     */
  990. /* draw lines running around the world and hence off the edges of the maps.  */
  991.  
  992. void DrawWrap(x1, y1, x2, y2, xmin, xmax)
  993. int x1, y1, x2, y2;
  994. {
  995.   int xmid, ymid, i;
  996.  
  997.   if (x1 < 0) {           /* Special case for drawing world map. */
  998.     DrawPoint(x2, y2);
  999.     return;
  1000.   }
  1001.   xmid = (xmax-xmin) / 2;
  1002.  
  1003.   /* If endpoints aren't near opposite edges, just draw the line and return. */
  1004.  
  1005.   if (abs(x2-x1) < xmid) {
  1006.     DrawLine(x1, y1, x2, y2);
  1007.     return;
  1008.   }
  1009.   i = (xmax-xmin+1) + (x1 < xmid ? x1-x2 : x2-x1);
  1010.  
  1011.   /* Determine vertical coordinate where our line runs off edges of screen. */
  1012.  
  1013.   ymid = y1+(int)((real)(y2-y1)*
  1014.     (x1 < xmid ? (real)(x1-xmin) : (real)(xmax-x1))/(real)i + ROUND);
  1015.   DrawLine(x1, y1, x1 < xmid ? xmin : xmax, ymid);
  1016.   DrawLine(x2 < xmid ? xmin : xmax, ymid, x2, y2);
  1017. }
  1018.  
  1019.  
  1020. /* This routine, and its companion below, clips a line defined by its  */
  1021. /* endpoints to either above some line y=c, or below some line y=c. By */
  1022. /* passing in parameters in different orders, we can clip to vertical  */
  1023. /* lines, too. These are used by the DrawClip() routine below.         */
  1024.  
  1025. void ClipLesser(x1, y1, x2, y2, s)
  1026. int *x1, *y1, *x2, *y2, s;
  1027. {
  1028.   *x1 -= (int)((long)(*y1-s)*(*x2-*x1)/(*y2-*y1));
  1029.   *y1 = s;
  1030. }
  1031.  
  1032. void ClipGreater(x1, y1, x2, y2, s)
  1033. int *x1, *y1, *x2, *y2, s;
  1034. {
  1035.   *x1 += (int)((long)(s-*y1)*(*x2-*x1)/(*y2-*y1));
  1036.   *y1 = s;
  1037. }
  1038.  
  1039.  
  1040. /* Draw a line on the screen. This is just like DrawLine() routine earlier; */
  1041. /* however, first clip the endpoints to the window viewport before drawing. */
  1042.  
  1043. void DrawClip(x1, y1, x2, y2, xl, yl, xh, yh, skip)
  1044. int x1, y1, x2, y2, xl, yl, xh, yh, skip;
  1045. {
  1046.   if (x1 < xl)
  1047.     ClipLesser (&y1, &x1, &y2, &x2, xl);    /* Check left side of window. */
  1048.   if (x2 < xl)
  1049.     ClipLesser (&y2, &x2, &y1, &x1, xl);
  1050.   if (y1 < yl)
  1051.     ClipLesser (&x1, &y1, &x2, &y2, yl);    /* Check top side of window.  */
  1052.   if (y2 < yl)
  1053.     ClipLesser (&x2, &y2, &x1, &y1, yl);
  1054.   if (x1 > xh)
  1055.     ClipGreater(&y1, &x1, &y2, &x2, xh);    /* Check right of window.  */
  1056.   if (x2 > xh)
  1057.     ClipGreater(&y2, &x2, &y1, &x1, xh);
  1058.   if (y1 > yh)
  1059.     ClipGreater(&x1, &y1, &x2, &y2, yh);    /* Check bottom of window. */
  1060.   if (y2 > yh)
  1061.     ClipGreater(&x2, &y2, &x1, &y1, yh);
  1062.   DrawDash(x1, y1, x2, y2, skip);           /* Go draw the line.       */
  1063. }
  1064.  
  1065.  
  1066. /* Draw a circle or ellipse inside the given bounding rectangle. */
  1067.  
  1068. void DrawEllipse(x1, y1, x2, y2)
  1069. int x1, y1, x2, y2;
  1070. {
  1071.   int x, y, rx, ry, m, n, u, v, i;
  1072.  
  1073.   if (xfile) {
  1074.     x = (x1+x2)/2; y = (y1+y2)/2; rx = (x2-x1)/2; ry = (y2-y1)/2;
  1075.     if (xbitmap) {
  1076.       InitCircle();
  1077.       m = x + rx; n = y;
  1078.       for (i = 0; i <= DEGR; i += DEGINC) {
  1079.         u = x + (int)((real)rx*circ->x[i]); v = y + (int)((real)ry*circ->y[i]);
  1080.         u = MIN(u, x + rx-1); v = MIN(v, y + ry-1);
  1081.         DrawLine(m, n, u, v);
  1082.         m = u; n = v;
  1083.       }
  1084.     }
  1085. #ifdef PS
  1086.     else if (psfile) {
  1087.       PSlinecap(FALSE);
  1088.       PSforcestroke();
  1089.       fprintf(psdata, "%d %d %d %d el\n", rx, ry, x, y);
  1090.     }
  1091. #endif
  1092. #ifdef META
  1093.     else {
  1094.       metafilldes = 16;    /* Specify a hollow fill brush. */
  1095.       MetaSelect();
  1096.       MetaEllipse(x1+metawid/3, y1+metawid/3, x2+metawid/3, y2+metawid/3);
  1097.     }
  1098. #endif
  1099.   }
  1100. #ifdef X11
  1101.   else
  1102.     XDrawArc(disp, pixmap, gc, x1, y1, x2-x1, y2-y1, 0, 360*64);
  1103. #endif
  1104. #ifdef MSG
  1105.   else
  1106.     _ellipse(_GBORDER, offsetx + x1, offsety + y1, offsetx + x2, offsety + y2);
  1107. #endif
  1108. }
  1109.  
  1110.  
  1111. /* Print a string of text on the graphic window at specified location. To  */
  1112. /* do this we either use Astrolog's own "font" (6x10) and draw each letter */
  1113. /* separately, or else specify system fonts for PostScript and metafiles.  */
  1114.  
  1115. void DrawText(string, x, y, base)
  1116. char *string;
  1117. int x, y, base;
  1118. {
  1119.   int s = scale, c = colcur, len;
  1120.  
  1121.   len = StringLen(string);
  1122.   scale = 100 * scalet;
  1123.   x += SCALE;
  1124.   if (base >= FALSE)
  1125.     x -= len*FONTX*SCALE/2;
  1126.   if (!base)
  1127.     y -= FONTY*SCALE/2;
  1128.   else
  1129.     y -= (FONTY-3)*SCALE;
  1130.   DrawColor(off);
  1131.   DrawBlock(x, y, x+FONTX*SCALE*len, y+(FONTY-1)*SCALE);
  1132.   DrawColor(c);
  1133. #ifdef PS
  1134.   if (psfile && xfont) {
  1135.     PSfont(4);
  1136.     fprintf(psdata, "%d %d(%s)center\n",
  1137.       x + FONTX*SCALE*len/2, y + FONTY*SCALE/2, string);
  1138.     scale = s;
  1139.     return;
  1140.   }
  1141. #endif
  1142.   while (*string) {
  1143. #ifdef META
  1144.     if (metafile && xfont) {
  1145.       metafontdes = 3;
  1146.       metatxtcdes = colcur;
  1147.       metatxtades = 0x6 | 0 /* Center | Top */;
  1148.       MetaSelect();
  1149.       MetaTextOut(x, y, 1);
  1150.       MetaWord(MAKEWORD(*string, 0));
  1151.     } else
  1152. #endif
  1153.       DrawTurtle(asciidraw[*string-' '], x, y);
  1154.     x += FONTX*SCALE;
  1155.     string++;
  1156.   }
  1157.   scale = s;
  1158. }
  1159.  
  1160.  
  1161. /* Draw the glyph of a sign at particular coordinates on the screen.    */
  1162. /* To do this we either use Astrolog's turtle vector representation or  */
  1163. /* we may specify a system font character for PostScript and metafiles. */
  1164.  
  1165. void DrawSign(i, x, y)
  1166. int i, x, y;
  1167. {
  1168. #ifdef PS
  1169.   if (psfile && xfont) {
  1170.     PSfont(1);
  1171.     fprintf(psdata, "%d %d(%c)center\n", x, y, 'A' + i - 1);
  1172.     return;
  1173.   }
  1174. #endif
  1175. #ifdef META
  1176.   if (metafile && xfont) {
  1177.     metafontdes = 1;
  1178.     metatxtcdes = colcur;
  1179.     metatxtades = 0x6 | 0x8 /* Center | Bottom */;
  1180.     MetaSelect();
  1181.     MetaTextOut(x, y+4*SCALE, 1);
  1182.     MetaWord(MAKEWORD('^' + i - 1, 0));
  1183.     return;
  1184.   }
  1185. #endif
  1186.   DrawTurtle(signdraw[i], x, y);
  1187. }
  1188.  
  1189.  
  1190. /* Draw the number of a house at particular coordinates on the screen. */
  1191. /* We either use a turtle vector or write a number in a system font.   */
  1192.  
  1193. void DrawHouse(i, x, y)
  1194. int i, x, y;
  1195. {
  1196. #ifdef PS
  1197.   if (psfile && xfont) {
  1198.     PSfont(3);
  1199.       fprintf(psdata, "%d %d(%d)center\n", x, y, i);
  1200.     return;
  1201.   }
  1202. #endif
  1203. #ifdef META
  1204.   if (metafile && xfont) {
  1205.     metafontdes = 2;
  1206.     metatxtcdes = colcur;
  1207.     metatxtades = 0x6 | 0x8 /* Center | Bottom */;
  1208.     MetaSelect();
  1209.     MetaTextOut(x, y+3*SCALE, 1 + (i>9));
  1210.     MetaWord(MAKEWORD(i > 9 ? '1' : '0'+i, i > 9 ? '0'+i-10 : 0));
  1211.     return;
  1212.   }
  1213. #endif
  1214.   DrawTurtle(housedraw[i], x, y);
  1215. }
  1216.  
  1217.  
  1218. /* Draw the glyph of an object at particular coordinates on the screen. */
  1219.  
  1220. void DrawObject(i, x, y)
  1221. int i, x, y;
  1222. {
  1223.   char glyph[4];
  1224. #ifdef PS
  1225.   static char objectchar[] = "dQRSTUVWXYZ     < ba ";
  1226. #endif
  1227. #ifdef META
  1228.   char c = 0;
  1229. #endif
  1230.  
  1231.   if (!xlabel)    /* If we are inhibiting labels, then do nothing. */
  1232.     return;
  1233.  
  1234.   /* For other planet centered charts, we have to remember that that     */
  1235.   /* particular planet's index now represents the Earth. If we are given */
  1236.   /* that index to draw, then change it so we draw the Earth instead.    */
  1237.  
  1238.   if (modex != MODES &&
  1239.     ((i == centerplanet && i > _MOO) || (centerplanet == 0 && i == _SUN)))
  1240.     i = 0;
  1241.   DrawColor(objectcolor[i]);
  1242.   if (i <= BASE) {
  1243. #ifdef PS
  1244.     if (psfile && xfont == 1 && objectchar[i] != ' ') {
  1245.       PSfont(2);
  1246.       fprintf(psdata, "%d %d(%c)center\n", x, y, objectchar[i]);
  1247.       return;
  1248.     }
  1249. #endif
  1250. #ifdef META
  1251.     if (metafile && xfont == 1) {
  1252.       if (i < _SUN)
  1253.         c = ';';
  1254.       else if (i <= _PLU) c = 'Q' + i - 1;
  1255.       else if (i == _NOD) c = '<';
  1256.       else if (i == _MC)  c = 'b';
  1257.       else if (i == _ASC) c = 'a';
  1258.     }
  1259.     if (c) {
  1260.       metafontdes = 4;
  1261.       metatxtcdes = colcur;
  1262.       metatxtades = 0x6 | 0x8 /* Center | Bottom */;
  1263.       MetaSelect();
  1264.       MetaTextOut(x, y+5*SCALE, 1);
  1265.       MetaWord(MAKEWORD(c, 0));
  1266.       return;
  1267.     }
  1268. #endif
  1269.     DrawTurtle(objectdraw[i], x, y);
  1270.  
  1271.   /* Normally we can just go draw the glyph; however, stars don't have */
  1272.   /* glyphs, so for these draw their three letter abbreviation.        */
  1273.  
  1274.   } else {
  1275.     sprintf(glyph, "%c%c%c", OBJNAM(i));
  1276.     DrawText(glyph, x, y, FALSE);
  1277.   }
  1278. }
  1279.  
  1280.  
  1281. /* Draw the glyph of an aspect at particular coordinates on the screen. */
  1282. /* Again we either use Astrolog's turtle vector or a system Astro font. */
  1283.  
  1284. void DrawAspect(i, x, y)
  1285. int i, x, y;
  1286. {
  1287. #ifdef PS
  1288.   static char aspectchar[] = "!\"#$'&%()+-       ";
  1289. #endif
  1290. #ifdef META
  1291.   char c = 0;
  1292. #endif
  1293.  
  1294. #ifdef PS
  1295.   if (psfile && xfont == 1 && aspectchar[i-1] != ' ') {
  1296.     PSfont(2);
  1297.     fprintf(psdata, "%d %d(%c)center\n", x, y, aspectchar[i-1]);
  1298.     return;
  1299.   }
  1300. #endif
  1301. #ifdef META
  1302.   if (metafile && xfont == 1) {
  1303.     if (i <= _TRI)
  1304.       c = '!' + i - 1;
  1305.     else if (i == _SEX) c = '\'';
  1306.     else if (i == _INC) c = '&';
  1307.     else if (i == _SSX) c = '%';
  1308.     else if (i == _SSQ) c = '(';
  1309.     else if (i == _SES) c = ')';
  1310.     else if (i == _QUI) c = '+';
  1311.     else if (i == _BQN) c = '-';
  1312.   }
  1313.   if (c) {
  1314.     metafontdes = 4;
  1315.     metatxtcdes = colcur;
  1316.     metatxtades = 0x6 | 0x8 /* Center | Bottom */;
  1317.     MetaSelect();
  1318.     MetaTextOut(x, y+5*SCALE, 1);
  1319.     MetaWord(MAKEWORD(c, 0));
  1320.     return;
  1321.   }
  1322. #endif
  1323.   DrawTurtle(aspectdraw[i], x, y);
  1324. }
  1325.  
  1326.  
  1327. /* Convert a string segment to a positive number, updating the string to  */
  1328. /* point beyond the number chars. Return 1 if the string doesn't point to */
  1329. /* a numeric value. This is used by the DrawTurtle() routine to extract   */
  1330. /* motion vector quantities from draw strings, e.g. the "12" in "U12".    */
  1331.  
  1332. int IntInString(str)
  1333. char **str;
  1334. {
  1335.   int num = 0, i = 0;
  1336.  
  1337.   loop {
  1338.     if (**str < '0' || **str > '9')
  1339.       return num > 0 ? num : (i < 1 ? 1 : 0);
  1340.     num = num*10+(**str)-'0';
  1341.     (*str)++;
  1342.     i++;
  1343.   }
  1344. }
  1345.  
  1346.  
  1347. /* This routine is used to draw complicated objects composed of lots of line */
  1348. /* segments on the screen, such as all the glyphs and coastline pieces. It   */
  1349. /* is passed in a string of commands defining what to draw in relative       */
  1350. /* coordinates. This is a copy of the format of the BASIC draw command found */
  1351. /* in PC's. For example, "U5R10D5L10" means go up 5 dots, right 10, down 5,  */
  1352. /* and left 10 - draw a box twice as wide as it is high.                     */
  1353.  
  1354. void DrawTurtle(lin, x0, y0)
  1355. char *lin;
  1356. int x0, y0;
  1357. {
  1358.   int i, j, x, y, deltax, deltay, blank, noupdate;
  1359.   char cmd;
  1360.  
  1361.   turtlex = x0; turtley = y0;
  1362.   while (cmd = CAP(*lin)) {
  1363.     lin++;
  1364.  
  1365.     /* 'B' prefixing a command means just move the cursor, and don't draw. */
  1366.  
  1367.     if (blank = cmd == 'B') {
  1368.       cmd = CAP(*lin);
  1369.       lin++;
  1370.     }
  1371.  
  1372.     /* 'N' prefixing a command means don't update cursor when done drawing. */
  1373.  
  1374.     if (noupdate = cmd == 'N') {
  1375.       cmd = CAP(*lin);
  1376.       lin++;
  1377.     }
  1378.  
  1379.     /* Here we process the eight directional commands. */
  1380.  
  1381.     switch (cmd) {
  1382.     case 'U': deltax =  0; deltay = -1; break;      /* Up    */
  1383.     case 'D': deltax =  0; deltay =  1; break;      /* Down  */
  1384.     case 'L': deltax = -1; deltay =  0; break;      /* Left  */
  1385.     case 'R': deltax =  1; deltay =  0; break;      /* Right */
  1386.     case 'E': deltax =  1; deltay = -1; break;      /* NorthEast */
  1387.     case 'F': deltax =  1; deltay =  1; break;      /* SouthEast */
  1388.     case 'G': deltax = -1; deltay =  1; break;      /* SouthWest */
  1389.     case 'H': deltax = -1; deltay = -1; break;      /* NorthWest */
  1390.     default: PrintError("Bad turtle subcommand.");  /* Shouldn't happen. */
  1391.     }
  1392.     x = turtlex;
  1393.     y = turtley;
  1394.     j = IntInString(&lin)*SCALE;    /* Figure out how far to draw. */
  1395.     if (blank) {
  1396.       turtlex += deltax*j;
  1397.       turtley += deltay*j;
  1398.     } else {
  1399.       if (psfile || metafile) {
  1400.         turtlex += deltax*j;
  1401.         turtley += deltay*j;
  1402.         DrawLine(x, y, turtlex, turtley);
  1403.       } else {
  1404.         DrawPoint(turtlex, turtley);
  1405.         for (i = 0; i < j; i++) {
  1406.           turtlex += deltax;
  1407.           turtley += deltay;
  1408.           DrawPoint(turtlex, turtley);
  1409.         }
  1410.       }
  1411.       if (noupdate) {
  1412.         turtlex = x;
  1413.         turtley = y;
  1414.       }
  1415.     }
  1416.   }
  1417. }
  1418. #endif /* GRAPH */
  1419.  
  1420. /* xgeneral.c */
  1421.