home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / listings / v_10_08 / qcdemod.cpp < prev    next >
C/C++ Source or Header  |  1992-07-14  |  9KB  |  363 lines

  1. ///////////////////////////////////////////////////////
  2. //  QCDEMOD.CPP: Quadcode demo program for DOS
  3. //  Written by:
  4. //    Kenneth Van Camp
  5. //    RR #1 Box 1255
  6. //    East Stroudsburg, PA  18301
  7. //    (717)223-8620
  8. //
  9. //  Functions -
  10. //    main                      main pgm entry point
  11. //    init_graphics             initialize graphics
  12. //    Cursor::Cursor            default constructor
  13. //    Cursor::Move              move cursor
  14. //    RegionDisplay::Display    display region
  15. //    RegionDisplay::Interact   user interaction
  16. //    dos_yieldfunc             yield function for build
  17. //
  18. ///////////////////////////////////////////////////////
  19. #include <stdio.h>
  20. #include <stdlib.h>
  21. #include <ctype.h>
  22. #include <string.h>
  23. #include <time.h>
  24. #include <graphics.h>
  25. #include <conio.h>
  26. #include <iostream.h>
  27. #include "qc.h"
  28.  
  29. void init_graphics (void);
  30. int dos_yieldfunc (int pct_complete);
  31.  
  32. const char  CR = '\015',    // carriage return code
  33.             ESC = '\033';   // escape code
  34.  
  35. int xres,           // horiz screen resolution
  36.     yres,           // vert screen resolution
  37.     shrink = TRUE,  // shrink all qc's for plotting?
  38.     qccolor = 1,    // color to paint quadcodes
  39.     xsize,          // size of a single-division qc
  40.     ysize,
  41.     xoffs;          // offset to center picture on scrn
  42.  
  43. // class RegionDisplay: A Region class with graphical
  44. // display and interaction capabilities.
  45. class RegionDisplay: public Region
  46. {
  47.   public:
  48.     RegionDisplay         // constructor from outline
  49.         (PointListHeader &vertex_list):
  50.         Region (vertex_list) { }  // calls base constr.
  51.     void Display (void);  // display on graphics screen
  52.     void Interact (void); // graphic interact function
  53. };  // class RegionDisplay
  54.  
  55. // struct Cursor: Controls display of crosshair cursor.
  56. struct Cursor
  57. {
  58.     int xlen,
  59.         ylen,
  60.         xpos,
  61.         ypos;
  62.     Cursor (void);
  63.     void Move (int xdist, int ydist);
  64. };
  65.  
  66. ///////////////////////////////////////////////////////
  67. // main: Main program entry point
  68.  
  69. int main (int argc, char **argv)
  70. {
  71.   if (argc != 1)
  72.   {
  73.     if (argc != 2 || strcmp (argv[1], "-n") != 0)
  74.     {
  75.       cerr << "usage: QCdemo [-n]\n";
  76.       cerr << "  where -n specifies no shrinkage\n";
  77.       return 1;
  78.     }
  79.     shrink = FALSE;
  80.   }
  81.  
  82.   const int npts = 37;
  83.   const int ndiv = 128;
  84.   const int reduce = 1;
  85.   Point plist[npts] =
  86.   {
  87.     {  5, 68}, { 28, 68}, { 32, 88}, { 33, 94},
  88.     { 31,110}, { 30,113}, { 35,124}, { 51,125},
  89.     { 63,127}, { 63,119}, { 67,116}, { 59,109},
  90.     { 63,119}, { 63,127}, { 74,126}, { 80,125},
  91.     { 88,112}, { 99,101}, {107, 98}, {113, 96},
  92.     {124, 98}, {122, 94}, {123, 91}, {121, 85},
  93.     {118, 78}, {108, 73}, { 96, 64}, { 85, 58},
  94.     { 81, 50}, { 82, 46}, { 90, 38}, { 83, 25},
  95.     { 72, 21}, { 58,  8}, { 55,  8}, { 54, 40},
  96.     {  5, 40}, 
  97.   };
  98.   PointListHeader phdr =
  99.   {
  100.     npts, ndiv, plist
  101.   };
  102.  
  103.   // Reduce to proper size
  104.   phdr.ndiv /= reduce;
  105.   int i;
  106.   for (i = 0; i < npts; i++)
  107.   {
  108.     phdr.pointptr[i].i /= reduce;
  109.     phdr.pointptr[i].j /= reduce;
  110.   }
  111.  
  112.   // Set the yield function so user can interrupt.
  113.   SetRegionYieldFunc (dos_yieldfunc);
  114.  
  115.   time_t tstart;
  116.   time (&tstart);
  117.   cout << "Building quadcode region (press Escape to Abort)\n";
  118.  
  119.   // Build the region from a perimeter list
  120.   RegionDisplay reg (phdr);
  121.  
  122.   time_t tend;
  123.   time (&tend);
  124.  
  125.   if (reg.NumQC() == 0)
  126.   {
  127.     cout << "\nREGION BUILD ABORTED!\n";
  128.     return 0;
  129.   }
  130.  
  131.   init_graphics();
  132.  
  133.   // Display the region, then allow user interaction.
  134.   reg.Display();
  135.   reg.Interact();
  136.  
  137.   restorecrtmode();
  138.   cout << "There are " << reg.NumQC() <<
  139.       " quadcodes in the region.\n";
  140.   cout << "Region was built in " <<
  141.       (long)difftime (tend, tstart) << " secs.\n";
  142.  
  143.   return 0;
  144. } // main
  145.  
  146. ///////////////////////////////////////////////////////
  147. // init_graphics: Initialize graphics under TC++.
  148.  
  149. void init_graphics (void)
  150. {
  151.   // Initialize graphics
  152.   int driver = DETECT,
  153.       mode,
  154.       errc;
  155.  
  156.   initgraph (&driver, &mode, getenv ("BGIDIR"));
  157.   if ((errc = graphresult()) != grOk)
  158.   {
  159.     cerr << "Graph Error: " << grapherrormsg (errc);
  160.     exit (1);
  161.   }
  162.   xres = getmaxx () + 1;
  163.   yres = getmaxy () + 1;
  164.   int maxcol = getmaxcolor ();
  165.   if (maxcol >= WHITE)
  166.     qccolor = WHITE;
  167.   else if (maxcol >= GREEN)
  168.     qccolor = GREEN;
  169. } // init_graphics
  170.  
  171. ///////////////////////////////////////////////////////
  172. // Cursor::Cursor: Default constructor
  173.  
  174. Cursor::Cursor (void)
  175. {
  176.   xpos = xres / 2;
  177.   ypos = yres / 2;
  178.   xlen = xres / 75;
  179.   ylen = yres / 50;
  180.  
  181.   setwritemode (XOR_PUT);
  182.   setcolor (qccolor);
  183.   line (xpos - xlen, ypos, xpos + xlen, ypos);
  184.   line (xpos, ypos - ylen, xpos, ypos + ylen);
  185. } // Cursor::Cursor
  186.  
  187. ///////////////////////////////////////////////////////
  188. // Cursor::Move: Move the cursor a specified distance.
  189.  
  190. void Cursor::Move (int xdist, int ydist)
  191. // xdist   is the dist to move right (left if negative)
  192. // ydist   is the dist to move down (up if negative)
  193. {
  194.   // Erase the old cursor
  195.   setwritemode (XOR_PUT);
  196.   line (xpos - xlen, ypos, xpos + xlen, ypos);
  197.   line (xpos, ypos - ylen, xpos, ypos + ylen);
  198.   
  199.   // Update in new position
  200.   xpos += xdist;
  201.   ypos += ydist;
  202.   xpos = max (0, xpos);
  203.   xpos = min (xres - 1, xpos);
  204.   ypos = max (0, ypos);
  205.   ypos = min (yres - 1, ypos);
  206.  
  207.   line (xpos - xlen, ypos, xpos + xlen, ypos);
  208.   line (xpos, ypos - ylen, xpos, ypos + ylen);
  209. } // Cursor::Move
  210.  
  211. ///////////////////////////////////////////////////////
  212. // RegionDisplay::Display: Display region graphically.
  213.  
  214. void RegionDisplay::Display (void)
  215. // ndiv is the # of divisions to use on the screen
  216. {
  217.   setcolor (qccolor);
  218.   setfillstyle (SOLID_FILL, qccolor);
  219.  
  220.   // Find usable display area:
  221.   int ux = (float)xres / 1.5;
  222.   // Calculate size of a single-division quadcode:
  223.   xsize = ux / ndiv;
  224.   ysize = yres / ndiv;
  225.   xoffs = (xres - ux) * 0.5;
  226.  
  227.   QCNode *qcn;
  228.   for (qcn = first_qcnode; qcn; qcn = qcn->next)
  229.   {
  230.     COORD i, j;
  231.     int   nq;
  232.     qcn->ToIJ (i, j, nq);
  233.     COORD nqc_div = 1L << nq;
  234.     float qcfact = ndiv / nqc_div;
  235.     int xlen = xsize * qcfact;
  236.     int ylen = ysize * qcfact;
  237.     int x = xoffs + j * xsize * qcfact;
  238.     int y = i * ysize * qcfact;
  239.     if (shrink)
  240.     {
  241.       x++;
  242.       y++;
  243.       xlen -= 2;
  244.       ylen -= 2;
  245.     }
  246.     bar (x, y, x + xlen, y + ylen);
  247.   } // for qcn
  248.  
  249. } // RegionDisplay::Display
  250.  
  251. ///////////////////////////////////////////////////////
  252. // RegionDisplay::Interact: User interact with region.
  253.  
  254. void RegionDisplay::Interact (void)
  255. {
  256.   Cursor  csr;
  257.  
  258.   setcolor (qccolor);
  259.   setfillstyle (SOLID_FILL, qccolor);
  260.   int nquits = MaxQuits();
  261.   int xbox = xres / 75;
  262.   int ybox = yres / 50;
  263.   int hispeed = yres / 50;
  264.   int speed = hispeed;
  265.  
  266.   while(1)
  267.   {
  268.     // Update status box
  269.     int i = csr.ypos / ysize;
  270.     int j = (csr.xpos - xoffs) / xsize;
  271.     // Only check if within region limits
  272.     if (i >= 0 && i < ndiv && j >= 0 && j < ndiv)
  273.     {
  274.       QuadCode qc (i, j, nquits);
  275.       setwritemode (COPY_PUT);
  276.       if (InRegion (qc))
  277.       {
  278.         // In region - draw solid status box
  279.         bar (0, 0, xbox, ybox);
  280.       }
  281.       else
  282.       {
  283.         // Out of region - draw empty status box
  284.         setfillstyle (EMPTY_FILL, qccolor);
  285.         bar (0, 0, xbox, ybox);
  286.         setfillstyle (SOLID_FILL, qccolor);
  287.         rectangle (0, 0, xbox, ybox);
  288.       }
  289.     }
  290.     else
  291.     {
  292.       // Outside region limits - draw empty status box
  293.       setfillstyle (EMPTY_FILL, qccolor);
  294.       bar (0, 0, xbox, ybox);
  295.       setfillstyle (SOLID_FILL, qccolor);
  296.       rectangle (0, 0, xbox, ybox);
  297.     }
  298.  
  299.     // Get last key in kybd buffer (no type-ahead)
  300.     int ch;
  301.     do
  302.     {
  303.       ch = getch();
  304.       if (ch == 0)
  305.         // Extended key codes (arrow keys)
  306.         ch = getch();
  307.     } while (kbhit());
  308.  
  309.     switch (ch)
  310.     {
  311.       case 's':     // toggle speed
  312.       case 'S':
  313.         if (speed == hispeed)
  314.           speed = 1;
  315.         else
  316.           speed = hispeed;
  317.         break;
  318.  
  319.       case 'H':     // up arrow
  320.         csr.Move (0, -speed);
  321.         break;
  322.  
  323.       case 'P':     // down arrow
  324.         csr.Move (0, speed);
  325.         break;
  326.  
  327.       case 'K':     // left arrow
  328.         csr.Move (-speed, 0);
  329.         break;
  330.  
  331.       case 'M':     // right arrow
  332.         csr.Move (speed, 0);
  333.         break;
  334.  
  335.       case '\033':  // escape
  336.         return;
  337.  
  338.       default:
  339.         putchar ('\a');
  340.     } // switch
  341.  
  342.   } // while
  343. } // RegionDisplay::Interact
  344.  
  345. ///////////////////////////////////////////////////////
  346. // dos_yieldfunc: A function that is called periodically
  347. // during region building to yield control to the user
  348. // or another application.  Under DOS, it just lets the
  349. // user abort the build with an Escape.  It returns TRUE
  350. // if the user aborts, or FALSE otherwise.
  351.  
  352. int dos_yieldfunc (int pct_complete)
  353. // pct_complete     is the percent of region built
  354. {
  355.   printf ("%c%3d%% Complete", CR, pct_complete);
  356.   if (kbhit())
  357.   {
  358.     if (getch() == ESC)
  359.       return (TRUE);
  360.   }
  361.   return (FALSE);
  362. } // dos_yieldfunc
  363.