home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume26 / psgraph / part02 / grid.c next >
Encoding:
C/C++ Source or Header  |  1992-09-06  |  18.4 KB  |  733 lines

  1. /* $Header: grid.c,v 1.12 92/08/04 17:55:02 mogul Exp $ */
  2.  
  3. /*
  4.  *               Copyright 1989, 1992 Digital Equipment Corporation
  5.  *                          All Rights Reserved
  6.  * 
  7.  * 
  8.  * Permission to use, copy, and modify this software and its documentation
  9.  * is hereby granted only under the following terms and conditions.  Both
  10.  * the above copyright notice and this permission notice must appear in
  11.  * all copies of the software, derivative works or modified versions, and
  12.  * any portions threof, and both notices must appear in supporting
  13.  * documentation.
  14.  * 
  15.  * Users of this software agree to the terms and conditions set forth
  16.  * herein, and hereby grant back to Digital a non-exclusive, unrestricted,
  17.  * royalty-free right and license under any changes, enhancements or
  18.  * extensions made to the core functions of the software, including but
  19.  * not limited to those affording compatibility with other hardware or
  20.  * software environments, but excluding applications which incorporate
  21.  * this software.  Users further agree to use their best efforts to return
  22.  * to Digital any such changes, enhancements or extensions that they make
  23.  * and inform Digital of noteworthy uses of this software.  Correspondence
  24.  * should be provided to Digital at:
  25.  * 
  26.  *                       Director of Licensing
  27.  *                       Western Research Laboratory
  28.  *                       Digital Equipment Corporation
  29.  *                       250 University Avenue
  30.  *                       Palo Alto, California  94301  
  31.  * 
  32.  * This software may be distributed (but not offered for sale or
  33.  * transferred for compensation) to third parties, provided such third
  34.  * parties agree to abide by the terms and conditions of this notice.
  35.  * 
  36.  * THE SOFTWARE IS PROVIDED "AS IS" AND DIGITAL EQUIPMENT CORP. DISCLAIMS
  37.  * ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING ALL IMPLIED
  38.  * WARRANTIES OF MERCHANTABILITY AND FITNESS.   IN NO EVENT SHALL DIGITAL
  39.  * EQUIPMENT CORPORATION BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR
  40.  * CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF
  41.  * USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
  42.  * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
  43.  * PERFORMANCE OF THIS SOFTWARE.
  44.  */
  45.  
  46. /* 
  47.  * grid.c - Compute and generate grids and axes
  48.  * 
  49.  * Author:    Christopher A. Kent
  50.  *         Western Research Laboratory
  51.  *         Digital Equipment Corporation
  52.  * Date:    Wed Jan  4 1989
  53.  */
  54.  
  55. /*
  56.  * $Log:    grid.c,v $
  57.  * Revision 1.12  92/08/04  17:55:02  mogul
  58.  * undo RCS botch
  59.  * 
  60.  * Revision 1.11  1992/06/17  22:14:41  kent
  61.  * Make axis specs with max < min work, fix some bugs with centering
  62.  * and multiple args.
  63.  *
  64.  * Revision 1.10  1992/06/16  01:48:11  kent
  65.  * Make y positioning and centering and such work right.
  66.  *
  67.  * Revision 1.9  1992/06/16  00:41:35  kent
  68.  * Hokey fix for a bug where min and max of a scale end up the same.
  69.  *
  70.  * Revision 1.8  1992/04/15  22:24:34  kent
  71.  * log Y label was being placed incorrectly
  72.  *
  73.  * Revision 1.7  1992/04/07  18:11:09  kent
  74.  * Made log scales support datalabels.
  75.  *
  76.  * Revision 1.6  1992/04/07  18:01:19  kent
  77.  * Can't draw the title until after the ticks are labelled, or the
  78.  * placement isn't right.
  79.  *
  80.  * Revision 1.5  1992/04/02  00:45:01  kent
  81.  * Changes to handle lots of points; when using dataticks, the axis
  82.  * routines could get too big and overflow the operand stack. As
  83.  * a result, the output PostScript code is even uglier.
  84.  *
  85.  * Revision 1.4  1992/04/01  23:27:34  kent
  86.  * Added datalabel verb, fixed a bug in handling blank input lines.
  87.  *
  88.  * Revision 1.3  1992/03/31  23:13:12  kent
  89.  * Added "dataticks" verb.
  90.  *
  91.  * Revision 1.2  1992/03/30  23:33:47  kent
  92.  * Added halfopen, halfticks grid styles, range frames, and gray.
  93.  *
  94.  * Revision 1.1  1992/03/20  21:25:43  kent
  95.  * Initial revision
  96.  *
  97.  * Revision 1.9  92/02/21  17:13:20  mogul
  98.  * Added Digital license info
  99.  * 
  100.  * Revision 1.8  91/02/04  16:46:25  mogul
  101.  * set variable "font" before using it, even when not labelling axes.
  102.  * 
  103.  * Revision 1.7  90/11/05  11:09:51  reid
  104.  * Checking in Chris Kent's changes before I start making some.
  105.  * 
  106.  * Revision 1.6  89/01/27  15:54:19  kent
  107.  * lint.
  108.  * 
  109.  * Revision 1.5  89/01/11  09:22:56  kent
  110.  * Use floor() to properly handle axis limit computations.
  111.  * 
  112.  * Revision 1.4  89/01/09  22:18:24  kent
  113.  * Added log scales.
  114.  * 
  115.  * Revision 1.3  89/01/04  17:30:24  kent
  116.  * Made command line arguments override compiled-in defaults for
  117.  * all plots in a run, not just the first one. 
  118.  * 
  119.  * Revision 1.2  89/01/04  15:21:52  kent
  120.  * Massive renaming. No functional change.
  121.  * 
  122.  * Revision 1.1  89/01/04  13:57:40  kent
  123.  * Initial revision
  124.  * 
  125.  */
  126.  
  127. static char rcs_ident[] = "$Header: grid.c,v 1.12 92/08/04 17:55:02 mogul Exp $";
  128.  
  129. #include <stdio.h>
  130.  
  131. #include "psgraph.h"
  132.  
  133. grid_t
  134. gridval(cp)
  135. char *cp;
  136. {
  137.     if ( isdigit(*cp)) {
  138.         switch(atoi(cp)) {
  139.         case 0: return NONE;
  140.         case 1:    return OPEN;
  141.         case 2: return TICKS;
  142.         case 3: return FULL;
  143.         case 4: return HALFOPEN;
  144.         case 5: return HALFTICKS;
  145.         default: return FULL;
  146.         }
  147.     } else if ( strcmp(cp,"none")==0 )
  148.         return NONE;
  149.     else if ( strcmp(cp,"open")==0 )
  150.         return OPEN;
  151.     else if ( strncmp(cp,"tick",4)==0 )
  152.         return TICKS;
  153.     else if ( strcmp(cp,"full")==0 )
  154.         return FULL;
  155.     else if ( strcmp(cp,"halfopen")==0 )
  156.         return HALFOPEN;
  157.     else if ( strncmp(cp,"halftick",8)==0 )
  158.         return HALFTICKS;
  159.     return FULL;
  160. }
  161.  
  162. limargs(p,argc,argv,arg)
  163. limit_t    *p;
  164. int    argc, arg;
  165. char    **argv;
  166. {
  167.     if ( arg < argc ** argv[arg] == 'l' ) {
  168.         p->tform = LOG10;
  169.         arg++;
  170.     }
  171.     if ( isfloat(argv[arg]) ) {
  172.         p->minflag = TRUE;
  173.         p->min = atof(argv[arg++]);
  174.         if ( isfloat(argv[arg]) ) {
  175.             p->maxflag = TRUE;
  176.             p->max = atof(argv[arg++]);
  177.             if ( isfloat(argv[arg]) ) {
  178.                 p->distf = TRUE;
  179.                 p->dist = atof(argv[arg++]);
  180.             }
  181.         }
  182.     }
  183.     return arg;
  184. }
  185.  
  186. /*
  187.  * draw the axes - define routines to draw the plot axes based on the
  188.  * parameters.  Because we may want to do a translate (to center the graph)
  189.  * based on the max and min, we can't just emit the commands here; because this
  190.  * could get arbitrarily large and overflow the operand stack, we use a hack to
  191.  * collapse that stack, at the cost of more obscure code.
  192.  */
  193.  
  194. setupAxes()
  195. {
  196.     minX = 0;
  197.     minY = 0;
  198.     maxX = MAX(maxX, sx(Xaxis.gmax));
  199.     maxY = MAX(maxY, sy(Yaxis.gmax));
  200. }
  201.  
  202. doXaxis()
  203. {
  204.         int i, startTemp = CurrentTemp;
  205.     
  206.     startGridTemp();
  207.     
  208.     if (Xaxis.tform == IDENT)
  209.         linearX();
  210.     else
  211.         logX();
  212.  
  213.     endGridTemp();
  214.     printf("/drawXaxis {\n");    /* hack hack */
  215.     for (i = startTemp; i < CurrentTemp; i++)
  216.         printf("\tgt%03d\n", i);
  217.     printf("}def\n");
  218. }
  219.  
  220. doYaxis()
  221. {
  222.         int i, startTemp = CurrentTemp;
  223.     
  224.     startGridTemp();
  225.     
  226.     if (Yaxis.tform == IDENT)
  227.         linearY();
  228.     else
  229.         logY();
  230.  
  231.     endGridTemp();
  232.     printf("/drawYaxis {\n");    /* hack hack */
  233.     for (i = startTemp; i < CurrentTemp; i++)
  234.         printf("\tgt%03d\n", i);
  235.     printf("}def\n");
  236. }
  237.  
  238. doTitle()
  239. {
  240.     if (Title.title != NULL)
  241.         axisText(Title.title, NORTH, 
  242.             Title.font ? Title.font : TextFont);
  243. }
  244.  
  245. #define    GT(a,b)        (argp->distg>0 ? ((a)-(b))>0 : ((a)-(b))<0)
  246. #define LT(a,b)        (argp->distg>0 ? ((a)-(b))<0 : ((a)-(b))>0)
  247.  
  248. linearX()
  249. {
  250.     register axis_t *argp;
  251.     char *font;
  252.     float x;
  253.     float amin, amax;
  254.     float agray, tgray;
  255.     int i;
  256.  
  257.     argp = &Xaxis;
  258.     agray = argp->axisgray;
  259.     tgray = argp->tickgray;
  260.     font = argp->font ? argp->font : TextFont;
  261.     amin = argp->gmin; amax = argp->gmax;
  262.  
  263.     /*
  264.      * Determine how much of the frame to draw
  265.      */
  266.     if (argp->rangeframe) {
  267.         amin = argp->min; amax = argp->max;
  268.     }
  269.     
  270.     /*
  271.      * Draw the frame 
  272.      */
  273.     if ( argp->gridtype != NONE ) {
  274.         gridLine(amin, Yaxis.gmin, amax, Yaxis.gmin, agray);
  275.         if (!argp->halfgrid)
  276.             gridLine(amin, Yaxis.gmax, amax, Yaxis.gmax, agray);
  277.     }
  278.  
  279.     /*
  280.      * Label the endpoints
  281.      */
  282.     if (DoAxisLabels) {
  283.         tickText(Xaxis.gmin, Yaxis.gmin, Xaxis.gmin, SOUTH, font);
  284.         tickText(Xaxis.gmax, Yaxis.gmin, Xaxis.gmax, SOUTH, font);
  285.     }
  286.  
  287.     /*
  288.      * Do data-only ticks
  289.      */
  290.     if (argp->datatick) {
  291.         for (i = 0; i < NumTokens; i++) {
  292.         if (Token[i].type != POINT)
  293.             continue;
  294.         x = Token[i].val[0];
  295.         if (argp->gridtype == FULL)
  296.             gridLine(x, Yaxis.gmin, x, Yaxis.gmax, tgray);
  297.         else {
  298.             tick(x, Yaxis.gmin, NORTH, TRUE, tgray);
  299.             if (!argp->halfgrid)
  300.             tick(x, Yaxis.gmax, SOUTH, TRUE, tgray);
  301.         }
  302.         if (argp->datalabel)
  303.             tickText(x, Yaxis.gmin, x, SOUTH, font);
  304.         }
  305.     }
  306.  
  307.     /*
  308.      * Draw the ticks that will have labels on them (or just the labels
  309.      * in the case of dataticks, ugh)
  310.      */
  311.     x = argp->gmin;
  312.  
  313.     while ( LT(x, argp->gmax) ) {
  314.         if ( GT(x, argp->gmin) ) {
  315.         if (!argp->datatick)
  316.             if ( argp->gridtype==FULL )
  317.             gridLine(x, Yaxis.gmin, x, Yaxis.gmax, tgray);
  318.             else if ( argp->gridtype==TICKS ) {
  319.             tick(x, Yaxis.gmin, NORTH, TRUE, tgray);
  320.             if (!argp->halfgrid)
  321.                 tick(x, Yaxis.gmax, SOUTH, TRUE, tgray);
  322.             }
  323.         if ( DoAxisLabels )
  324.             tickText(x, Yaxis.gmin, x, SOUTH, font);
  325.         }
  326.         x += argp->distg;
  327.     }
  328.  
  329.     /*
  330.      * Draw the "title" of the axis
  331.      */
  332.     if ( argp->label != NULL )
  333.         axisText(argp->label, SOUTH, font);
  334.  
  335.     if (argp->datatick)
  336.         return;
  337.  
  338.     /*
  339.      * Draw the ticks for the endpoints
  340.      */
  341.     if ( argp->gridtype == FULL ) {
  342.         gridLine(Xaxis.gmin, Yaxis.gmin, Xaxis.gmin, Yaxis.gmax, agray);
  343.         gridLine(Xaxis.gmax, Yaxis.gmin, Xaxis.gmax, Yaxis.gmax, agray);
  344.     } else if ( argp->gridtype==TICKS ) {
  345.         tick(Xaxis.gmin, Yaxis.gmin, NORTH, TRUE, tgray);
  346.         tick(Xaxis.gmax, Yaxis.gmin, NORTH, TRUE, tgray);
  347.         if (!argp->halfgrid) {
  348.         tick(Xaxis.gmin, Yaxis.gmax, SOUTH, TRUE, tgray);
  349.         tick(Xaxis.gmax, Yaxis.gmax, SOUTH, TRUE, tgray);
  350.         }
  351.     }
  352.  
  353.     /*
  354.      * Draw the secondary ticks
  355.      */
  356.     if ( argp->tickflag ) {
  357.         if (argp->minflag && argp->distf)
  358.             x = argp->gmin;
  359.         else
  360.             x = argp->pmin;
  361.         while ( LT(x, argp->gmax) ) {
  362.             if ( GT(x, argp->gmin) ) {
  363.                 tick(x, Yaxis.gmin, NORTH, FALSE, tgray);
  364.                 if (!argp->halfgrid)
  365.                     tick(x, Yaxis.gmax, SOUTH, FALSE, tgray);
  366.             }
  367.             x += argp->tick;
  368.         }
  369.     }
  370. }
  371.  
  372. logX()
  373. {
  374.     register axis_t *argp;
  375.     char    *font;
  376.     float    x, d1, d2, dist;
  377.     float    amin, amax;
  378.     float agray, tgray;
  379.     int i;
  380.  
  381.     argp = &Xaxis;
  382.     agray = argp->axisgray;
  383.     tgray = argp->tickgray;
  384.     font = argp->font ? argp->font : TextFont;
  385.     amin = argp->gmin; amax = argp->gmax;
  386.  
  387.     if (argp->rangeframe) {
  388.         amin = argp->min; amax = argp->max;
  389.     }
  390.  
  391.     if ( argp->gridtype != NONE ) {
  392.         gridLine(amin, Yaxis.gmin, amax, Yaxis.gmin, agray);
  393.         if (!argp->halfgrid)
  394.             gridLine(amin, Yaxis.gmax, amax, Yaxis.gmax, agray);
  395.     }
  396.     if (DoAxisLabels) {
  397.         tickText(argp->gmin, Yaxis.gmin, argp->gmin, SOUTH, font);
  398.         tickText(argp->gmax, Yaxis.gmin, argp->gmax, SOUTH, font);
  399.     }
  400.  
  401.     if ( argp->gridtype == FULL ) {
  402.         gridLine(Xaxis.gmin, Yaxis.gmin, Xaxis.gmin, Yaxis.gmax, agray);
  403.         gridLine(Xaxis.gmax, Yaxis.gmin, Xaxis.gmax, Yaxis.gmax, agray);
  404.     } else if ( argp->gridtype==TICKS ) {
  405.         tick(Xaxis.gmin, Yaxis.gmin, NORTH, TRUE, tgray);
  406.         tick(Xaxis.gmax, Yaxis.gmin, NORTH, TRUE, tgray);
  407.         if (!argp->halfgrid) {
  408.         tick(Xaxis.gmin, Yaxis.gmax, SOUTH, TRUE, tgray);
  409.         tick(Xaxis.gmax, Yaxis.gmax, SOUTH, TRUE, tgray);
  410.         }
  411.     }
  412.  
  413.     if (argp->datatick) {
  414.         for (i = 0; i < NumTokens; i++) {
  415.         if (Token[i].type != POINT)
  416.             continue;
  417.         x = Token[i].val[0];
  418.         if (argp->gridtype == FULL)
  419.             gridLine(x, Yaxis.gmin, x, Yaxis.gmax, tgray);
  420.         else {
  421.             tick(x, Yaxis.gmin, NORTH, TRUE, tgray);
  422.             if (!argp->halfgrid)
  423.             tick(x, Yaxis.gmax, SOUTH, TRUE, tgray);
  424.         }
  425.         if (argp->datalabel)
  426.             tickText(x, Yaxis.gmin, x, SOUTH, font);
  427.         }
  428.     }
  429.  
  430.     if ( argp->label != NULL )
  431.         axisText(argp->label, SOUTH, font);
  432.  
  433.     x = argp->gmin;
  434.  
  435.     d1 = ipow(10.0, (int)floor(log10(x)));
  436.     while ( LT(d1, argp->gmax) ) {
  437.         d2 = (argp->distg > 0) ? 10.0 * d1 : d1 / 10.0;
  438.         if ( GT(d1, argp->gmin) ) {
  439.         if (!argp->datatick)
  440.             if ( argp->gridtype==FULL )
  441.             gridLine(d1, Yaxis.gmin, d1, Yaxis.gmax, tgray);
  442.             else if ( argp->gridtype==TICKS ) {
  443.             tick(d1, Yaxis.gmin, NORTH, TRUE, tgray);
  444.             if (!argp->halfgrid)
  445.                 tick(d1, Yaxis.gmax, SOUTH, TRUE, tgray);
  446.             }
  447.         if ( DoAxisLabels )
  448.             tickText(d1, Yaxis.gmin, d1, SOUTH, font);
  449.         }
  450.         if ( argp->intervals && !argp->datatick ) {
  451.         dist = copysign(d2 / argp->intervals, argp->distg);
  452.         x = d1;
  453.         while (LT(x, d2) && LT(x, argp->gmax)) {
  454.             if ( GT(x, argp->gmin) ) {
  455.             tick(x, Yaxis.gmin, NORTH, FALSE, tgray);
  456.             if (!argp->halfgrid)
  457.                 tick(x, Yaxis.gmax, SOUTH, FALSE, tgray);
  458.             }
  459.             x += dist;
  460.         }
  461.         }
  462.         d1 = d2;
  463.     }
  464. }
  465.  
  466. linearY()
  467. {
  468.     register axis_t *argp;
  469.     char *font;
  470.     float y;
  471.     float amin, amax;
  472.     float agray, tgray;
  473.     int i;
  474.  
  475.     argp = &Yaxis;
  476.     font = argp->font ? argp->font : TextFont;
  477.     agray = argp->axisgray;
  478.     tgray = argp->tickgray;
  479.     amin = argp->gmin; amax = argp->gmax;
  480.  
  481.     if (argp->rangeframe) {
  482.         amin = argp->min; amax = argp->max;
  483.     }
  484.  
  485.     if ( argp->gridtype != NONE ) {
  486.         gridLine(Xaxis.gmin, amin, Xaxis.gmin, amax, agray);
  487.         if (!argp->halfgrid)
  488.             gridLine(Xaxis.gmax, amin, Xaxis.gmax, amax, agray);
  489.     }
  490.  
  491.     if (DoAxisLabels) {
  492.         tickText(Xaxis.gmin, Yaxis.gmin, Yaxis.gmin, WEST, font);
  493.         tickText(Xaxis.gmin, Yaxis.gmax, Yaxis.gmax, WEST, font);
  494.     }
  495.  
  496.     if (argp->datatick) {
  497.         for (i = 0; i < NumTokens; i++) {
  498.         if (Token[i].type != POINT)
  499.             continue;
  500.         y = Token[i].val[1];
  501.         if (argp->gridtype == FULL)
  502.             gridLine(Xaxis.gmin, y, Xaxis.gmax, y, tgray);
  503.         else {
  504.             tick(Xaxis.gmin, y, EAST, TRUE, tgray);
  505.             if (!argp->halfgrid)
  506.             tick(Xaxis.gmax, y, WEST, TRUE, tgray);
  507.         }
  508.         if (argp->datalabel)
  509.             tickText(Xaxis.gmin, y, y, WEST, font);
  510.         }
  511.     }
  512.  
  513.     y = argp->gmin;
  514.     
  515.     while ( LT(y, argp->gmax) ) {
  516.         if ( GT(y, argp->gmin) ) {
  517.         if (!argp->datatick)
  518.             if ( argp->gridtype==FULL )
  519.             gridLine(Xaxis.gmin, y, Xaxis.gmax, y, tgray);
  520.             else if ( argp->gridtype==TICKS ) {
  521.             tick(Xaxis.gmin, y, EAST, TRUE, tgray);
  522.             if (!argp->halfgrid)
  523.                 tick(Xaxis.gmax, y, WEST, TRUE, tgray);
  524.             }
  525.         if ( DoAxisLabels )
  526.             tickText(Xaxis.gmin, y, y, WEST, font);
  527.         }
  528.         y += argp->distg;
  529.     }
  530.  
  531.     if (argp->label != NULL)
  532.         axisText(argp->label, WEST, font);
  533.     
  534.     if (argp->datatick)
  535.         return;
  536.  
  537.     if ( argp->gridtype == FULL ) {
  538.         gridLine(Xaxis.gmin, Yaxis.gmin, Xaxis.gmax, Yaxis.gmin, agray);
  539.         gridLine(Xaxis.gmin, Yaxis.gmax, Xaxis.gmax, Yaxis.gmax, agray);
  540.     } else if ( argp->gridtype==TICKS ) {
  541.         tick(Xaxis.gmin, Yaxis.gmin, EAST, TRUE, tgray);
  542.         tick(Xaxis.gmin, Yaxis.gmax, EAST, TRUE, tgray);
  543.         if (!argp->halfgrid) {
  544.         tick(Xaxis.gmax, Yaxis.gmin, WEST, TRUE, tgray);
  545.         tick(Xaxis.gmax, Yaxis.gmax, WEST, TRUE, tgray);
  546.         }
  547.     }
  548.         
  549.     if ( argp->tickflag ) {
  550.         if ( argp->minflag && argp->distf )
  551.             y = argp->gmin;
  552.         else
  553.             y = argp->pmin;
  554.         while ( LT(y, argp->gmax) ) {
  555.             if ( GT(y, argp->gmin) ) {
  556.                 tick(Xaxis.gmin, y, EAST, FALSE, tgray);
  557.                 if (!argp->halfgrid)
  558.                     tick(Xaxis.gmax, y, WEST, FALSE, tgray);
  559.             }
  560.             y += argp->tick;
  561.         }
  562.     }
  563. }
  564.  
  565. logY()
  566. {
  567.     register axis_t *argp;
  568.     char *font;
  569.     float y, d1, d2, dist;
  570.     float    amin, amax;
  571.     float agray, tgray;
  572.     int i;
  573.  
  574.     argp = &Yaxis;
  575.     agray = argp->axisgray;
  576.     tgray = argp->tickgray;
  577.     font = argp->font ? argp->font : TextFont;
  578.     amin = argp->gmin; amax = argp->gmax;
  579.  
  580.     if (argp->rangeframe) {
  581.         amin = argp->min; amax = argp->max;
  582.     }
  583.  
  584.     if ( argp->gridtype != NONE ) {
  585.         gridLine(Xaxis.gmin, amin, Xaxis.gmin, amax, agray);
  586.         if (!argp->halfgrid)
  587.             gridLine(Xaxis.gmax, amin, Xaxis.gmax, amax, agray);
  588.     }
  589.     if (DoAxisLabels) {
  590.         tickText(Xaxis.gmin, Yaxis.gmin, Yaxis.gmin, WEST, font);
  591.         tickText(Xaxis.gmin, Yaxis.gmax, Yaxis.gmax, WEST, font);
  592.     }
  593.  
  594.     if ( argp->gridtype == FULL ) {
  595.         gridLine(Xaxis.gmin, Yaxis.gmin, Xaxis.gmax, Yaxis.gmin, agray);
  596.         gridLine(Xaxis.gmin, Yaxis.gmax, Xaxis.gmax, Yaxis.gmax, agray);
  597.     } else if ( argp->gridtype==TICKS ) {
  598.         tick(Xaxis.gmin, Yaxis.gmin, EAST, TRUE, tgray);
  599.         tick(Xaxis.gmin, Yaxis.gmax, EAST, TRUE, tgray);
  600.         if (!argp->halfgrid) {
  601.         tick(Xaxis.gmax, Yaxis.gmin, WEST, TRUE, tgray);
  602.         tick(Xaxis.gmax, Yaxis.gmax, WEST, TRUE, tgray);
  603.         }
  604.     }
  605.  
  606.     if (argp->datatick) {
  607.         for (i = 0; i < NumTokens; i++) {
  608.         if (Token[i].type != POINT)
  609.             continue;
  610.         y = Token[i].val[1];
  611.         if (argp->gridtype == FULL)
  612.              gridLine(Xaxis.gmin, y, Xaxis.gmax, y, tgray);
  613.         else {
  614.             tick(Xaxis.gmin, y, EAST, TRUE, tgray);
  615.             if (!argp->halfgrid)
  616.             tick(Xaxis.gmax, y, WEST, TRUE, tgray);
  617.         }
  618.         if (argp->datalabel)
  619.             tickText(Xaxis.gmin, y, y, WEST, font);
  620.         }
  621.     }
  622.  
  623.     if ( argp->label != NULL )
  624.         axisText(argp->label, WEST, font);
  625.  
  626.     y = argp->gmin;
  627.         
  628.     d1 = ipow(10.0, (int)floor(log10(y)));
  629.     while (LT(d1, argp->gmax)) {
  630.         d2 = (argp->distg > 0) ? 10.0 * d1 : d1 / 10.0;
  631.         if ( GT(d1, argp->gmin) ) {
  632.         if (!argp->datatick)
  633.             if ( argp->gridtype==FULL )
  634.             gridLine(Xaxis.gmin, d1, Xaxis.gmax, d1, tgray);
  635.             else if ( argp->gridtype==TICKS ) {
  636.             tick(Xaxis.gmin, d1, EAST, TRUE, tgray);
  637.             if (!argp->halfgrid)
  638.                 tick(Xaxis.gmax, d1, WEST, TRUE, tgray);
  639.             }
  640.         if ( DoAxisLabels )
  641.             tickText(Xaxis.gmin, d1, d1, WEST, font);
  642.         }
  643.         if ( argp->intervals && !argp->datatick ) {
  644.         dist = copysign(d2 / argp->intervals, argp->distg);
  645.         y = d1;
  646.         while ( LT(y, d2) && LT(y, argp->gmax)) {
  647.             if ( GT(y, argp->gmin) ) {
  648.             tick(Xaxis.gmin, y, EAST, FALSE, tgray);
  649.             if (!argp->halfgrid)
  650.                 tick(Xaxis.gmax, y, WEST, FALSE, tgray);
  651.             }
  652.             y += dist;
  653.         }
  654.         }
  655.         d1 = d2;
  656.     }
  657. }
  658.  
  659. /*
  660.  *----------------------------------------------------------------------
  661.  *
  662.  * GRID COMPUTATION ROUTINES
  663.  *
  664.  * These routines are from ACM Collected Algorithms, Number 463.
  665.  *
  666.  * Author: C.R.Lewart
  667.  */
  668.  
  669. float ipow(x,i)
  670. float x;
  671. int i;
  672. {
  673.     float    res;
  674.     
  675.     res = 1.0;
  676.     if ( i > 0 )
  677.         while ( i-- > 0 )
  678.             res *= x;
  679.     else
  680.         while ( i++ < 0 )
  681.             res /= x;
  682.     return res;
  683. }            
  684.  
  685. /*
  686.  * scale1
  687.  *
  688.  * Given data extremes xmin and xmax, and number of desired grid lines n
  689.  * (advisory only), compute plot minimum and maximum xpmin and xpmax with
  690.  * distance between grid lines dist.
  691.  *
  692.  * Translated from FORTRAN to C by Bob Brown.
  693.  */
  694.  
  695. scale1(xmin, xmax, n, xpmin, xpmax, dist)
  696. float    xmin, xmax;
  697. int    n;
  698. float    *xpmin, *xpmax, *dist;
  699. {
  700.     static float vint[] = { 1.0, 2.0, 5.0, 10.0 };
  701.     static float sqr[] = { 1.414213562373, 3.162277660168, 7.071067811865 };
  702.     static float del = 0.000001;
  703.     float a, al, b, fm;
  704.     int nal, m, i;
  705.  
  706.     if (xmax == xmin)
  707.         xmax += 1.0;
  708.     a = fabs((xmax-xmin)/(float)n);
  709.     al = log10(a);
  710.     nal = (int)al;
  711.     if ( a < 1.0 )
  712.         nal -= 1;
  713.     b = a/ipow(10.0, nal);
  714.     for ( i=0 ; i<3 ; i++ )
  715.         if ( b < sqr[i] )
  716.             break;
  717.     *dist = copysign(vint[i] * ipow(10.0, nal), (xmax - xmin));
  718.     fm = xmin / *dist;
  719.     m = fm < 0.0 ? (int)fm - 1 : (int)fm;
  720.     if ( fabs((float)m+1.0-fm) < del )
  721.         m += 1;
  722.     *xpmin = *dist * (float)m;
  723.     fm = xmax / *dist;
  724.     m = fm < -1.0 ? (int)fm : (int)fm + 1;
  725.     if ( fabs(fm+1.0-(float)m) < del )
  726.         m -= 1;
  727.     *xpmax = *dist * (float)m;
  728.     if ( *xpmin > xmin )
  729.         *xpmin = xmin;
  730.     if ( *xpmax < xmax )
  731.         *xpmax = xmax;
  732. }
  733.