home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / d / dots151.zip / GRAPHSRC.ZIP / SCALE.C < prev    next >
C/C++ Source or Header  |  1990-04-19  |  13KB  |  444 lines

  1. /*    scale - calculate scaling parameters for plotting so that axes
  2.             have convenient labels
  3. */
  4.  
  5. #include <stdio.h>
  6. #include <math.h>
  7. #include "g.h"
  8. #include "g3.h"
  9. #include "graph.h"
  10.  
  11. /*
  12. #define xxxx
  13. #define xxx
  14. #define xx
  15. */
  16.  
  17. #define NTIC 30.
  18. #define minimum(x, y) (((x) < (y))?(x):(y))
  19. #define maximum(x, y) (((x) > (y))?(x):(y))
  20. #define power(x, y) (exp(log(x)*(y)))
  21.  
  22.                     /* local functions */
  23. static          MODEL exptext( int flag, char *buf );
  24. static double   MODEL adjust( char *fmt, double x1, double x2, int nlx );
  25. static          MODEL scale_one ( double amin, double amax, double *bmin, 
  26.                        double *bmax, int lab_requested, int tic_requested,
  27.                        int *nlab, int *ntic, int kind );
  28.  
  29. #ifdef xxx
  30.  
  31. static int used[4][4] =     {    {0, 0, 0, 0}, 
  32.                                 {0, 0, 0, 0}, 
  33.                                 {0, 0, 0, 0}, 
  34.                                 {0, 0, 0, 0}
  35.                             };
  36. #endif
  37.  
  38. static double decide[4][3] ={    {1.414,    3.162,    7.071    },
  39.                                 {1.414,    1.414,    1.414    },
  40.                                 {2.236,    2.236,    2.236    },
  41.                                 {1.414,    3.162,    7.071    }
  42.                             };
  43. static int mtic[4][4] =     {    {1,  2,  5, 10},
  44.                                 {1,  2,  2,  2},
  45.                                 {1,  5,  5,  5},
  46.                                 {1,  2,  5, 10}
  47.                             };
  48. static double    x1;        /* minimum x value */
  49. static double    x2;        /* maximum x value */
  50. static int        kx;        /* kind of axis...0 for linear, 1 for log */
  51. static int        nlx;    /* number of long tic marks */
  52. static int        ntx;    /* number of short tic marks */
  53. static double    y1, y2;    /* (similar for y's) */
  54. static int        ky, nly, nty;
  55.  
  56. scale (amin, amax, rlx, rtx, ka, bmin, bmax, rly, rty, kb)
  57.     double amin, amax, bmin, bmax;
  58.     int ka, kb, rlx, rly;
  59. {
  60. #ifdef xxx
  61.     printf("scale: amin = %f  amax = %f  ka = %d \n", amin, amax, ka);
  62. #endif
  63.     scale_one(amin, amax, &x1, &x2, rlx, rtx, &nlx, &ntx, ka);
  64. #ifdef xxx
  65.     printf("scale: x1 = %f x2 = %f nlx = %d ntx = %d \n", x1, x2, nlx, ntx);
  66.     printf("scale: bmin = %f  bmax = %f  kb = %d \n", bmin, bmax, kb);
  67. #endif
  68.     scale_one(bmin, bmax, &y1, &y2, rly, rty, &nly, &nty, kb);
  69. #ifdef xxx
  70.     printf("scale: y1 = %f y2 = %f nly = %d nty = %d \n", y1, y2, nly, nty);
  71. #endif
  72.     kx = ka; ky = kb;
  73.     window(x1, x2, y1, y2);
  74. }
  75.  
  76. static scale_one (amin, amax, bmin, bmax, lab_requested, tic_requested, nlab,
  77. ntic, kind)
  78.  
  79.     double amin, amax, *bmin, *bmax; int lab_requested, tic_requested,
  80.     *nlab, *ntic, kind;
  81.  
  82. {    double tens, top, bottom, fraction, d, interval;
  83.     int i, j;
  84.  
  85.     if(!kind)    /* linear scale */
  86.         {if(amax <= amin) amax = amin + 1.;
  87.         fraction = (amax - amin)/maximum(lab_requested - 1, 1);
  88. #ifdef xxx
  89.         printf("\nscale_one: fraction = %f", fraction);
  90. #endif
  91.         tens = power(10., floor(log10(fraction)));
  92.         fraction /= tens;
  93.         for (j = 0; j <= 2; j++) if(fraction < decide[0][j]) break;
  94.         d = mtic[0][j]*tens;                /* data increment between labels */
  95.         bottom = floor(amin/d + .002);    *bmin = bottom*d;
  96.         top = ceil(amax/d - .002);        *bmax = top*d;
  97.         *nlab = (int)(top - bottom + .25);                    /* # labels */
  98.         interval = tic_requested/ *nlab;
  99.         for (i = 0; i <= 2; i++) if(interval < decide[j][i]) break;
  100.         *ntic = mtic[j][i]* *nlab;                            /* # tic marks */
  101. #ifdef xxx
  102.         used[j][i]++;
  103.         printf("(-->%f) ?= d = %f, tens = %f \n", fraction, d, tens);
  104.         printf("       bottom = %f, top = %f, interval = %f \n", 
  105.                                                         bottom, top, interval);
  106.         printf("i = %d  j = %d  bmin = %f  bmax = %f  \n", i, j, *bmin, *bmax);
  107. #endif
  108.         }
  109.     else    /* log scale */
  110.         {*bmin = floor(amin + .001); *bmax = ceil(amax - .001);
  111.         *nlab = *bmax - *bmin + .1;
  112.         if ((*nlab * 3) > tic_requested) *ntic = *nlab;
  113.         else *ntic = *nlab*9;
  114.         }
  115. #ifdef xx
  116.     printf("\n scale_one: *bmin=%f  *bmax=%f  *nlab=%d  *ntic=%d  kind=%d \n",
  117.                                             *bmin, *bmax, *nlab, *ntic, kind);
  118. #endif
  119. }
  120.  
  121. /*    return scale factor and format for printing nlx labels from x1 to x2 */
  122. static double adjust(fmt, x1, x2, nlx) char *fmt; double x1, x2; int nlx;
  123. {    double large, a1, a2, adj = 1.;
  124.     int exponent = 0, after;    /* "after" is # digits needed after decimal */
  125.     a1 = fabs(x1);
  126.     a2 = fabs(x2);
  127.     large = (a1 > a2)?a1:a2;
  128.     if(large < .01)
  129.         while(large*adj < 1.) {adj *= 1000.; exponent -= 3;}
  130.     if(large*adj > 10000.)
  131.         while(large*adj > 1000.) {adj /= 1000.; exponent += 3;}
  132.     after = ceil(-log10((x2*adj - x1*adj)/nlx) - .01);
  133.     if(after < 0) after = 0;
  134.     if(exponent)
  135.         {sprintf(fmt, "%%%d.%dfe%d", after, after, exponent);
  136.         }
  137.     else
  138.         {sprintf(fmt, "%%%d.%df", after, after);
  139.         }
  140.     return (adj);
  141. }
  142.  
  143. static double segl[9] = {.301, .176, .125, .097, .079, .067, .058, .051, .046};
  144. static double ch;        /* height of a character (world coordinates) */
  145. static double cw;        /* width of a character (world coordinates) */
  146.  
  147. axis(numbers, grid_style, grid_width, width_used, height_used)
  148. int numbers, grid_style, grid_width;
  149. double width_used, height_used;
  150. {    int i, j, after;
  151.     double adj = 1., tic, t1, t11, e1, t2, t22, e2, s, x, y, y0, yval, dely,
  152.         offset;
  153.     static double wx1, wx2, wy1, wy2;    /* window limits (world coordinates) */
  154.     static double vx1, vx2, vy1, vy2;    /* viewport limits */
  155.     char buf[80], format[80];
  156.  
  157.     if(grid_style == 0) return;
  158.     clip_window(0);
  159.     if(grid_width < 1) grid_width = 1;
  160.     else if(grid_width > 9) grid_width = 9;
  161.     set_linewidth(grid_width);
  162.     inquire_window(&wx1, &wx2, &wy1, &wy2);
  163.     inquire_viewport_2(&vx1, &vx2, &vy1, &vy2);
  164.                 /*
  165.                     W1 = pixels_wide*(vx2-vx1)/best_width is the width of
  166.                     the viewport in pixels.  W2 = char_width/W1 is the
  167.                     width of a character as a fraction of the viewport
  168.                     width.  cw = W2*(wx2-wx1) is the width of a
  169.                     character in user units.
  170.                 */
  171.     cw = (wx2 - wx1)*best_width/(vx2 - vx1)*char_width/(double)pixels_wide;
  172.     ch = (wy2 - wy1)*best_height/(vy2 - vy1)*char_height/(double)pixels_high;
  173.     tic = .01*sqrt(width_used*width_used + height_used*height_used);
  174.     t1 = tic/width_used*(x2 - x1);    /* length of small horizontal tic mark */
  175.     e1 = t1*.0000001;                /* invisibly small horizontal distance */
  176.     x1 += e1; x2 -= e1;
  177.     t2 = tic/height_used*(y2 - y1);
  178.     e2 = t2*.0000001;                /* invisibly small vertical distance */
  179.     y1 += e2; y2 -= e2;
  180.     if(grid_style < 0 && grid_style != -2)                 /* tics on outside */
  181.         {t1 = -t1; t2 = -t2;
  182.         }
  183.     t11 = t1*2.; t22 = t2*2.;                    /* length of long tic mark */
  184.     if(abs(grid_style) == 2) {t11 = x2 - x1; t22 = 0.;}          /* full grid */
  185.     y_axis(y1, y2, ky, nly, nty, x1, t1, t11, grid_style);         /* left */
  186.     if(abs(grid_style) < 3)
  187.         x_axis(x1, x2, kx, nlx, ntx, y2, -t2, -t22, grid_style); /* top */
  188.     if(abs(grid_style) == 2) {t11 = 0.; t22 = y2 - y1;}
  189.     x_axis(x1, x2, kx, nlx, ntx, y1, t2, t22, grid_style);          /* bottom */
  190.     if(abs(grid_style) < 3)
  191.         y_axis(y1, y2, ky, nly, nty, x2, -t1, -t11, grid_style); /* right */
  192.     if(numbers)
  193.         {if(!ky) adj = adjust(format, y1, y2, nly);
  194.         x = x1;
  195.         if(grid_style < 0 && grid_style != -2) x += t11; 
  196.         if(grid_style == 4) x -= 3.*t1;
  197.         else if(grid_style == -4) x += t1;
  198.         yval = y2; 
  199.         dely = (y2 - y1)/nly; 
  200.         y = y0 = y2 - .4*ch;
  201.         if(char_v_adjusted && !plotting_device && grid_style > 0) 
  202.             {y -= .6*ch;                        /* stay within screen */
  203.             if(ky) y -= .4*ch;                     /* allow for superscripts */
  204.             }
  205.         for(i = 0; i <= nly; i++)                        /* label y axis */
  206.             {if(ky) sprintf(buf, "1e%1.0f", yval);
  207.             else sprintf(buf, format, yval*adj);
  208.             move_abs_2(x - cw*(1. + strlen(buf)), y);
  209.             exptext(ky, buf);
  210.             y = y0 - dely*(i + 1); yval -= (y2 - y1)/nly;
  211.             }
  212.  
  213.         if(!kx) adj = adjust(format, x1, x2, nlx);
  214.         x = x1; y = y1 - (kx?1.6:1.3)*ch;
  215.         if(grid_style < 0 && grid_style != -2) y += t22;
  216.         if(grid_style == 4) y -= 3.*t2;
  217.         else if(grid_style == -4) y += t2;
  218.         offset = .5;
  219.         for(i = 0; i <= nlx; i++)                        /* label x axis */
  220.             {if(kx) sprintf(buf, "1e%1.0f", x);
  221.             else sprintf(buf, format, x*adj); 
  222.             if(i == nlx && !plotting_device) 
  223.                 offset = 1.;        /* on screen, offset label for clearance */
  224.             move_abs_2(x - cw*offset*strlen(buf), y);
  225.             exptext(kx, buf);
  226.             x += (x2 - x1)/nlx;
  227.             }
  228.         }
  229.     clip_window(1);
  230. }
  231.  
  232. static exptext(flag, buf) int flag; char *buf;
  233. {    if(flag && char_v_adjusted) 
  234.         {text("10"); 
  235.         move_rel_2(cw*2.,ch*.4); 
  236.         buf += 2;
  237.         }
  238.     text(buf);
  239. }
  240.  
  241. static x_axis(x, x2, kx, nlx, ntx, y, t, tlarge, grid_style)
  242. double x, x2,     /* beginning and ending x locations */
  243. y,                 /* y location of axis */
  244. t,                 /* y displacement for small tic marks */
  245. tlarge;            /* y displacement for large tic marks */
  246. int kx,         /* nonzero for log axis */
  247. nlx,             /* # large tic marks */
  248. ntx,             /* # small tic marks */
  249. grid_style;        /* 1 = frame with tic marks inside (default)
  250.                   -1 = frame with tic marks outside the graph area
  251.                    2 = full grid
  252.                    3 = bottom and left axes only
  253.                   -3 = bottom and left axes, tic marks on outside
  254.                    4 = separated bottom and left axes only
  255.                   -4 = separated bottom and left axes, tic marks on outside
  256.                 */
  257. {    int i, j; double s;
  258.  
  259.     if(grid_style == 4) y -= 3.*t;
  260.     else if(grid_style == -4) y += t;
  261.  
  262.                                 /* display 1st large tic mark */
  263.     if(grid_style < 0 || grid_style > 3) 
  264.         {move_abs_2(x, y + tlarge); 
  265.         line_abs_2(x, y);
  266.         }
  267.     else move_abs_2(x, y);
  268.     if(kx)                        /* log axis */
  269.         {s = (x2 - x)/nlx;
  270.         for ( i = nlx ; i ; i-- )
  271.             {if(ntx > nlx)
  272.                 {for ( j = 0 ; j < 9 ; j++ )
  273.                     {if(plotting_device)
  274.                         line_abs_2(x, y);
  275.                     else
  276.                         move_abs_2(x, y);
  277.                     line_abs_2(x += s*segl[j], y);
  278.                     line_abs_2(x, y + t);
  279.                     }
  280.                 line_abs_2(x, y + tlarge);
  281.                 }
  282.             else
  283.                 {if(plotting_device)
  284.                     line_abs_2(x, y);
  285.                 else
  286.                     move_abs_2(x, y);
  287.                 line_abs_2(x += s, y);
  288.                 line_abs_2(x, y + tlarge);
  289.                 }
  290.             }
  291.         }
  292.     else                        /* linear axis */
  293.         {s = (x2 - x)/ntx;
  294.         for( i = nlx ; i ; i-- )
  295.             {for ( j = ntx/nlx ; j > 0 ; j-- )
  296.                 {if(plotting_device)
  297.                     line_abs_2(x, y);
  298.                 else
  299.                     move_abs_2(x, y);
  300.                 line_abs_2(x += s, y);
  301.                 line_abs_2(x, y + t);
  302.                 }
  303.             line_abs_2(x, y + tlarge);
  304.             }
  305.         }
  306. }
  307.  
  308. static y_axis(y, y2, ky, nly, nty, x, t, tlarge, grid_style)
  309. double y, y2,     /* beginning and ending y locations */
  310. x,                 /* x location of axis */
  311. t,                 /* x displacement for small tic marks */
  312. tlarge;            /* x displacement for large tic marks */
  313. int ky,         /* nonzero for log axis */
  314. nly,             /* # large tic marks */
  315. nty,             /* # small tic marks */
  316. grid_style;        /* 1 = frame with tic marks inside (default), 
  317.                   -1 = frame with tic marks outside the graph area, 
  318.                    2 = full grid
  319.                    3 = bottom and left axes only
  320.                   -3 = bottom and left axes, tic marks on outside.
  321.                    4 = separated bottom and left axes only
  322.                   -4 = separated bottom and left axes, tic marks on outside.
  323.                 */
  324. {    int i,j; double s;
  325.  
  326.     if(grid_style == 4) x -= 3.*t;
  327.     else if(grid_style == -4) x += t;
  328.  
  329.     if(grid_style < 0 || grid_style > 3)
  330.         {move_abs_2(x + tlarge, y); 
  331.         line_abs_2(x, y);
  332.         }
  333.     else move_abs_2(x, y);
  334.     move_abs_2(x, y);
  335.     if(ky)                /* log axis */
  336.         {s = (y2 - y)/nly;
  337.         for ( i = nly ; i ; i-- )
  338.             {if(nty > nly)
  339.                 {for ( j = 0 ; j < 9 ; j++ )
  340.                     {if(plotting_device)
  341.                         line_abs_2(x, y);
  342.                     else
  343.                         move_abs_2(x, y);
  344.                     line_abs_2(x, y += s*segl[j]);
  345.                     line_abs_2(x + t, y);
  346.                     }
  347.                 line_abs_2(x + tlarge, y);
  348.                 }
  349.             else
  350.                 {if(plotting_device)
  351.                     line_abs_2(x, y);
  352.                 else
  353.                     move_abs_2(x, y);
  354.                 line_abs_2(x, y += s);
  355.                 line_abs_2(x + tlarge, y);
  356.                 }
  357.             }
  358.         }
  359.     else                /* linear axis */
  360.         {s = (y2 - y)/nty;
  361.         for( i = nly ; i ; i-- )
  362.             {for ( j = nty/nly ; j > 0 ; j-- )
  363.                 {if(plotting_device)
  364.                     line_abs_2(x, y);
  365.                 else
  366.                     move_abs_2(x, y);
  367.                 line_abs_2(x, y  += s);
  368.                 line_abs_2(x + t, y);
  369.                 }
  370.             line_abs_2(x + tlarge, y);
  371.             }
  372.         }
  373. }
  374.  
  375. #ifdef xxxx
  376.  
  377. /*        illustrate a lot of labeled axes  */
  378. main()
  379. {    double lower, upper, delt, span;
  380.     int nlab, ntic, i, j;
  381.  
  382.     initialize_core(1);
  383.     initialize_view_surface(1);
  384.     ndc_space_2(1., .8);
  385. /*    viewport2(.1, 1., .1, .8); */
  386.     clip_window(1);
  387.     delt = power(10., 0.1);
  388.     lower = -5.;
  389.     for (i = 4; i; i--)
  390.         {span = 1.;
  391.         for (j = 11; j; j--)
  392.             {new_frame();
  393.             /* generate the figure */
  394.             upper = lower + span;
  395.                                     /**** old calling sequence *****/
  396.             scale(lower, upper, 2, lower, upper, 2); 
  397.             create_temporary_segment();
  398.             axis();
  399.             printf("\n lower = %10.4f...upper = %10.4f \n",
  400.                 lower, upper);
  401.             close_temporary_segment();    
  402.             span *= delt;
  403.             getchar();
  404.             }
  405.         lower += 3.;
  406.         }
  407.     printf("mtic[][]...\n");
  408.     for(j = 0; j < 4; j++)
  409.         {for(i = 0; i < 4; i++) printf("%4d", mtic[j][i]);
  410.         printf("\n");
  411.         }
  412.     printf("usage of cells of mtic[][]...\n");
  413.     for(j = 0; j < 4; j++)
  414.         {for(i = 0; i < 4; i++) printf("%4d", used[j][i]);
  415.         printf("\n");
  416.         }
  417. }
  418.  
  419. #endif
  420.  
  421.  
  422. #ifdef FORMATS
  423.  
  424. /*    illustrate the formats generated by adjust() for numeric axis labels */
  425. main()
  426. {    char format[80], s1[30], s2[30], s3[30], s4[30];
  427.     double x, x0 = .000001, adj;
  428.     int i;
  429.  
  430.     for (i = 0; i < 2; i++)
  431.         {for (x = x0; x < 1.e6; x *=  10.)
  432.             {adj = adjust(format, x/5, x, 5);
  433.             sprintf(s1, format, x/5*adj); 
  434.             sprintf(s2, format, x*adj); 
  435.             adj = adjust(format, x/10, x, 10);
  436.             sprintf(s3, format, x/10*adj); 
  437.             sprintf(s4, format, x*adj); 
  438.             printf("%8s ...%8s   %8s ...%8s\n", s1, s2, s3, s4);
  439.             }
  440.         x0 *= 3.;
  441.         }
  442. }
  443. #endif
  444.