home *** CD-ROM | disk | FTP | other *** search
/ High Voltage Shareware / high1.zip / high1 / DIR23 / TOUCH2.ZIP / GRPH.C < prev    next >
C/C++ Source or Header  |  1993-08-14  |  11KB  |  501 lines

  1. /*
  2.  * grph.c - graph support
  3.  */
  4.  
  5. /*
  6.  * Copyright 1993 Victor A. Abell, Lafayette, Indiana  47906.  All rights
  7.  * reserved.
  8.  *
  9.  * Written by Victor A. Abell.
  10.  *
  11.  * Permission is granted to anyone to use this software for any purpose on
  12.  * any computer system, and to alter it and redistribute it freely, subject
  13.  * to the following restrictions:
  14.  *
  15.  * 1. Victor A. Abell is not responsible for any consequences of the use of
  16.  * this software.
  17.  *
  18.  * 2. The origin of this software must not be misrepresented, either by
  19.  *    explicit claim or by omission.  Credit to Victor A. Abell must
  20.  *    appear in documentation and sources.
  21.  *
  22.  * 3. Altered versions must be plainly marked as such, and must not be
  23.  *    misrepresented as being the original software.
  24.  *
  25.  * 4. This notice may not be removed or altered.
  26.  */
  27. #ifndef lint
  28. static char copyright[] =
  29. "@(#) Copyright 1993 Victor A. Abell.\nAll rights reserved.\n";
  30. #endif
  31.  
  32. #include "touch2.h"
  33. #include <ctype.h>
  34. #include <math.h>
  35.  
  36. #define    FIELDLN    16            /* dump line field length */
  37. #define GPFX    31            /* graph prefix column count */
  38.  
  39. char Date[FIELDLN];            /* dump line date */
  40. char Dow[FIELDLN];            /* dump line day of week */
  41. double Gmaxl;                /* graph maximum line */
  42. double Gminl;                /* graph minimum line */
  43. short Lpp = LPP;            /* lines per page */
  44. double Rval;                /* dump line reading value */
  45. char Time[FIELDLN];            /* dump line time value */
  46.  
  47. char *MeasName[] = { "Regular", "Check Solution (C)", "Check Strip (!)",
  48.              "Meter Error (*)" };
  49.  
  50.  
  51. /*
  52.  * DrawGraph() - draw a graph of meter memory values
  53.  */
  54.  
  55. void
  56. DrawGraph(ty)
  57.     int ty;                /* type: 0 = screen, 1 = file */
  58. {
  59.  
  60. #if    defined(UNIX)
  61.     int i;
  62. #else
  63.     short i;
  64. #endif
  65.  
  66.     short err, gmn, gmx, j, k, lpp, mmol, n[4], pc, row;
  67.     char ch, *cp1, *cp2, gttl[2][82], hdr[5][72], ln[82], pr[80];
  68.     double fn, dj, dk, iv, max[4], min[4], mn, mx, sumx[4], sumxx[4];
  69.     short prow, px, pxh, py, pyh;
  70.     char pca[PRTRCTLLN+1], pcb[PRTRCTLLN+1];
  71.     int pcal, pcbl;
  72.     struct videoconfig vc;
  73.  
  74. #if    defined(UNIX)
  75.     int g, gt, pcol;
  76. #else
  77.     short g, gt, pcol;
  78. #endif
  79.  
  80. /*
  81.  * If graphing to screen, enter VRES16COLOR video mode.
  82.  */
  83.     if ( !ty) {
  84.         vc = Vc;
  85.         if (_setvideomode(_VRES16COLOR) == 0) {
  86.             (void) WarnMsg(10, 30,
  87.                 "The graph function requires VRES16COLOR.",
  88.                 12, 30,
  89.                 "This display does not support that mode.", 0);
  90.             return;
  91.         }
  92.         _setbkcolor(Colors[BkClrx].v);
  93.         _settextcolor(TxtClrx);
  94.         _setcolor(TxtClrx);
  95.         _getvideoconfig(&Vc);
  96.         Vmode = 1;
  97.     }
  98. /*
  99.  * Miscellaneous setup.
  100.  */
  101.     for (j = 0; j < 4; j++) {
  102.         max[j] = 0.0;
  103.         min[j] = 9999.0;
  104.         n[j] = 0;
  105.         sumx[j] = sumxx[j] = 0.0;
  106.     }
  107.     px = Vc.numxpixels / ((Vc.numtextcols > 80 ? 80 : Vc.numtextcols) - 2);
  108.     py = Vc.numypixels / Vc.numtextrows;
  109.     pxh = px/2;
  110.     pyh = py/2;
  111. /*
  112.  * Accumulate statistics values.
  113.  */
  114.     for (err = mmol = 0, i = DumpHs; i < DumpLc; i++) {
  115.         if ((j = ParseDumpLn(i, 1)) == 0) {
  116.             err = 1;
  117.             if ((char)WarnMsg(10, 34, "Bad dump line:", 12,
  118.             (short)(((Vc.numtextcols - strlen(DumpLp[i]))/2)+1),
  119.             DumpLp[i], 1)
  120.             == ESC) {
  121. graph_exit:
  122.             if ( ! ty) {
  123.                 _setvideomode(vc.mode);
  124.                 _setbkcolor(BkClrx & 7);
  125.                 _settextcolor(TxtClrx);
  126.                 Vc = vc;
  127.                 Vmode = 0;
  128.             }
  129.                 return;
  130.             }
  131.             continue;
  132.         }
  133.         if (j == 2)
  134.             mmol = 1;
  135.         if (j > 3)
  136.             continue;
  137.         sumx[Rtype] += Rval;
  138.         sumxx[Rtype] += Rval * Rval;
  139.         n[Rtype]++;
  140.         if (max[Rtype] < Rval)
  141.             max[Rtype] = Rval;
  142.         if (min[Rtype] > Rval)
  143.             min[Rtype] = Rval;
  144.     }
  145.     if (err)
  146.         goto graph_exit;
  147. /*
  148.  * Form statistics lines.
  149.  */
  150.     (void) sprintf(&hdr[0][0], "          %-18s %7s %6s %8s %6s %6s",
  151.         "", "Number", "Mean", "Std Dev", "Min", "Max");
  152.     for (j = 0; j < 4; j++) {
  153.         if ( ! n[j]) {
  154.             hdr[j+1][0] = '\0';
  155.             continue;
  156.         }
  157.         fn = (float)n[j];
  158.         (void) sprintf(&hdr[j+1][0],
  159.             "          %-18s %7d %6.1f %8.2f %6.1f %6.1f",
  160.             MeasName[j], n[j], sumx[j]/fn,
  161.             sqrt(sumxx[j]/fn - (sumx[j]/fn * sumx[j]/fn)),
  162.             min[j], max[j]);
  163.     }
  164. /*
  165.  * Establish graph parameters.
  166.  */
  167.     if ( ! Lineval) {
  168.         if (mmol) {
  169.             Gmaxl = DEFMMMAX;
  170.             Gminl = DEFMMMIN;
  171.         } else {
  172.             Gmaxl = DEFMGMAX;
  173.             Gminl = DEFMGMIN;
  174.         }
  175.     }
  176.     mn = (Gminl < min[0]) ? Gminl : min[0];
  177.     mx = (Gmaxl > max[0]) ? Gmaxl : max[0];
  178.     dk = (double)(((Vc.numtextcols > 80) ? 80 : Vc.numtextcols) - GPFX - 2);
  179.     if ((iv = (mx - mn) / dk) < 0.1)
  180.         iv = 0.1;
  181.     gmn = (int)((Gminl - mn) / iv) + GPFX;
  182.     gmx = (int)((Gmaxl - mn) / iv) + GPFX;
  183.     (void) sprintf(>tl[0][0], "%.3f %s per column", iv,
  184.         mmol ? "mmol/l" : "mg/dl");
  185.     for (j = strlen(>tl[0][0]); j < GPFX; j++)
  186.         gttl[0][j] = ' ';
  187.      for (j = 0; j < GPFX; j++)
  188.         gttl[1][j] = ' ';
  189.     cp1 = >tl[0][GPFX-4];
  190.     cp2 = >tl[1][GPFX];
  191.     for (dj = mn; dj < mx; ) {
  192.         (void) sprintf(cp1, "%5.1f", dj);
  193.         cp1 += 5;
  194.         *cp2++ = '+';
  195.         *cp2 = '\0';
  196.         dj += iv;
  197.         for (k = 0; k < 5 && dj <= mx; k++) {
  198.             if (k < 1) {
  199.                 *cp1++ = ' ';
  200.                 *cp1 = '\0';
  201.             }
  202.             *cp2++ = '-';
  203.             *cp2 = '\0';
  204.             dj += iv;
  205.         }
  206.     }
  207. /*
  208.  * If drawing graph to file, create printer control strings.
  209.  */
  210.     if (ty) {
  211.         if (AftGraph)
  212.             pcal = CvtPrtrStr(AftGraph, pca, sizeof(pca));
  213.         if (BefGraph) {
  214.             if ((pcbl = CvtPrtrStr(BefGraph, pcb, sizeof(pcb))) > 0)
  215.             (void) fwrite((void *)pcb, (size_t)pcbl, 1, Graphfs);
  216.         }
  217.         lpp = Lpp;
  218.         pc = 0;
  219.     }
  220. /*
  221.  * Refill screen.
  222.  */
  223.     for (j = pcol = 0;;) {
  224.         if ( ! ty) {
  225.             pcol = 0;
  226.             _clearscreen(_GCLEARSCREEN);
  227.             (void) sprintf(pr,
  228.                 "(%d of %d) Press ESC or X to exit; Page Up/Down; Arrow Up/Down.",
  229.                 (j < 9) ? 1 : j - 9 + 1, DumpLc - DumpHs);
  230.             PromptMsg(pr);
  231.         }
  232.         for (row = 1, k = j;
  233.             row < Vc.numtextrows && k < DumpLc+9-DumpHs;
  234.             k++, row++)
  235.         {
  236.             if ( ! ty)
  237.                 _settextposition(row, 1);
  238.             switch (k) {
  239.             case 0:
  240.                 if ( ! ty)
  241.                     _outtext(Gttl);
  242.                 break;
  243.  
  244.             case 1:
  245.             case 2:
  246.             case 3:
  247.             case 4:
  248.             case 5:
  249.                 if ( ! ty)
  250.                     _outtext(&hdr[k-1][0]);
  251.                 break;
  252.             case 6:
  253.                 break;
  254.             case 7:
  255.             case 8:
  256.                 if ( ! ty)
  257.                     _outtext(>tl[k-7][0]);
  258.                 break;
  259.             default:
  260.                 (void) ParseDumpLn(k-9+DumpHs, 1);
  261.                 if (Rtype == RDREG)
  262.                     g = (int)((Rval - mn) / iv) + GPFX;
  263.                 if (Rtype == RDHIGH) {
  264.                     (void) sprintf(ln,
  265.                     "%-3.3s %-8.8s %-8.8s    HIGH",
  266.                     Dow, Date, Time);
  267.                 } else {
  268.                     switch (Rtype) {
  269.                     case RDSOL:
  270.                         ch = 'C'; break;
  271.                     case RDSTRIP:
  272.                         ch = '!'; break;
  273.                     case RDMTRERR:
  274.                         ch = '*'; break;
  275.                     default:
  276.                         ch = ' ';
  277.                     }
  278.                     (void) sprintf(ln,
  279.                     "%-3.3s %-8.8s %-8.8s %c %5.1f",
  280.                     Dow, Date, Time, ch, Rval);
  281.                 }
  282.                 if (ty) {
  283.                     if (lpp >= Lpp) {
  284.                     pc++;
  285.                     if (PcDisp) {
  286.                         (void) fprintf(Graphfs,
  287.                         "%s\nPage %2d:  %s\n",
  288.                         pc > 1 ? "\f" : "",
  289.                         pc, Gttl);
  290.                     } else {
  291.                         (void) fprintf(Graphfs,
  292.                         "%s\n          %s\n",
  293.                         pc > 1 ? "\f" : "",
  294.                         Gttl);
  295.                     }
  296.                     (void) fprintf(Graphfs,
  297.                         "\n%s\n%s\n%s\n%s\n%s\n\n%s\n%s\n",
  298.                         &hdr[0][0],
  299.                         &hdr[1][0],
  300.                         &hdr[2][0],
  301.                         &hdr[3][0],
  302.                         &hdr[4][0],
  303.                         >tl[0][0],
  304.                         >tl[1][0]);
  305.                     lpp = HDRLPP;
  306.                     }
  307.                     if (Rtype != RDREG) {
  308.                     gt = gmx;
  309.                     g = GPFX-2;
  310.                     } else
  311.                         gt = (g > gmx) ? g : gmx;
  312.                     ln[gt+1] = '\0';
  313.                     for (gt; gt >= GPFX-2; gt--) {
  314.                     if (gt == gmn || gt == gmx) {
  315.                         ln[gt] = (gt <= g) ? IntCh[0]
  316.                                    : LineCh[0];
  317.                     } else if (gt >= GPFX && gt <= g)
  318.                         ln[gt] = BarCh[0];
  319.                     else
  320.                         ln[gt] = ' ';
  321.                     }
  322.                     (void) fprintf(Graphfs, "%s\n", ln);
  323.                     lpp++;
  324.                 } else {
  325.                     _outtext(ln);
  326.                     if (gmn) {
  327.                         _settextposition(row, gmn + 1);
  328.                         _outtext(LineCh);
  329.                     }
  330.                     if (gmx) {
  331.                         _settextposition(row, gmx + 1);
  332.                         _outtext(LineCh);
  333.                     }
  334.                     if (Rtype != RDREG)
  335.                         break;
  336.                     if (pcol) {
  337.                         _moveto((pcol * px) + pxh,
  338.                             ((prow-1) * py) + pyh);
  339.                         _lineto((g * px) + pxh,
  340.                             ((row-1) * py) + pyh);
  341.                     }
  342.                     pcol = g;
  343.                     prow = row;
  344.                 }
  345.             }
  346.         }
  347.     /*
  348.      * See if done graphing to file.
  349.      */
  350.         if (ty) {
  351.             if (k >= DumpLc+9-DumpHs) {
  352.                 if (pcal > 0) {
  353.                     (void) fwrite((void *)pca,
  354.                         (size_t)pcal, 1, Graphfs);
  355.                 }
  356.                 (void) fclose(Graphfs);
  357.                 Graphfs = NULL;
  358.                 return;
  359.             }
  360.             j = k;
  361.             continue;
  362.         }
  363.     /*
  364.      * Wait for keyboard input.
  365.      */
  366.         for (k = 1; k;) {
  367.             switch ((char)WaitAnyKey()) {
  368.             case ESC:
  369.             case 'x':
  370.             case 'X':
  371.                 goto graph_exit;
  372.             case PGDN:
  373.                 if ((j+Vc.numtextrows-1) < (DumpLc+9-DumpHs)) {
  374.                     j = j + Vc.numtextrows - 1;
  375.                     k = 0;
  376.                 } else
  377.                     putch(BELL);
  378.                 break;
  379.             case PGUP:
  380.                 if (j < (Vc.numtextrows - 1))
  381.                     j = 0;
  382.                 else
  383.                     j = j - (Vc.numtextrows - 1);
  384.                 k = 0;
  385.                 break;
  386.             case UARW:
  387.                 if (j) {
  388.                     j--;
  389.                     k = 0;
  390.                 } else
  391.                     putch(BELL);
  392.                 break;
  393.             case DARW:
  394.                 if (j < (DumpLc+9-DumpHs-1)) {
  395.                     j++;
  396.                     k = 0;
  397.                 } else
  398.                     putch(BELL);
  399.                 break;
  400.             default:
  401.                 putch(BELL);
  402.             }
  403.         }
  404.     }
  405. }
  406.  
  407.  
  408. /*
  409.  * ParseDumpLn() - parse dump line
  410.  */
  411.  
  412. int
  413. ParseDumpLn(i, s)
  414.  
  415. #if    defined(UNIX)
  416.     int i;                /* line index */
  417.     int s;                /* seconds flag */
  418. #else
  419.     short i;            /* line index */
  420.     short s;            /* seconds flag */
  421. #endif
  422.  
  423. {
  424.     char *cp, r[FIELDLN];
  425.     short rv;
  426.  
  427.     if ( i < DumpHs || i > DumpLc)
  428.         return(0);
  429. /*
  430.  * Parse day of week, date, time and reading.
  431.  */
  432.     if ((cp = ParseField(DumpLp[i], Dow, sizeof(Dow))) == NULL)
  433.         return(0);
  434.     if ((cp = ParseField(cp, Date, sizeof(Date))) == NULL)
  435.         return(0);
  436.     if ((cp = ParseField(cp, Time, sizeof(Time))) == NULL)
  437.         return(0);
  438.     if ((cp = ParseField(cp, r, sizeof(r))) == NULL)
  439.         return(0);
  440. /*
  441.  * Convert last two characters of day of week to lower case.
  442.  */
  443.     if (Dow[1] && isascii(Dow[1]) && isupper(Dow[1]))
  444.         Dow[1] = tolower(Dow[1]);
  445.     if (Dow[2] && isascii(Dow[2]) && isupper(Dow[2]))
  446.         Dow[2] = tolower(Dow[2]);
  447. /*
  448.  * Shorten the time by eliminating the :00 seconds.
  449.  */
  450.     if (s) {
  451.         if (strncmp(&Time[5], ":00", 3) == 0) {
  452.             for (cp = &Time[5];; cp++) {
  453.                 if ((*cp = *(cp+3)) == '\0')
  454.                     break;
  455.             }
  456.         }
  457.     }
  458. /*
  459.  * Get reading type and convert the value.
  460.  */
  461.     cp = r;
  462.     rv = 1;
  463.     switch (*cp) {
  464.         case ' ':
  465.         case 'M':
  466.             if (strcmpi(cp, " HIGH ") == 0) {
  467.                 Rtype = RDHIGH;
  468.                 return(4);
  469.             }
  470.             Rtype = RDREG;
  471.             break;
  472.         case '!':
  473.             Rtype = RDSTRIP;
  474.             break;
  475.         case 'C':
  476.         case 'K':            /* SVENS || DEUTS */
  477.             Rtype = RDSOL;
  478.             break;
  479.         default:
  480.             return(0);
  481.     }
  482. /*
  483.  * Parse value.
  484.  */
  485.     cp++;
  486.     if (*cp == 'M') {
  487.         rv = 2;
  488.         cp++;
  489.     } else
  490.         rv = 1;
  491.     if ( ! Atof(cp, &Rval, NULL, cp)) {
  492.         if (*cp == '?') {
  493.             Rtype = RDMTRERR;
  494.             return(3);
  495.         }
  496.         Rval = 0.0;
  497.         return(0);
  498.     }
  499.     return(rv);
  500. }
  501.