home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume31 / jgraph / part05 / process.c < prev    next >
C/C++ Source or Header  |  1992-07-14  |  23KB  |  835 lines

  1. /* 
  2.  * $Source: /n/fs/vd/jsp/src/jgraph/RCS/process.c,v $
  3.  * $Revision: 8.0 $
  4.  * $Date: 92/07/03 14:16:11 $
  5.  * $Author: jsp $
  6.  */
  7.  
  8. #include <stdio.h>
  9. #include <math.h>
  10.  
  11. #include "jgraph.h"
  12.  
  13. #define ABS(a) ((a > 0.0) ? (a) : (-a))
  14. #define MAX(a, b) ((a > b) ? (a) : (b))
  15. #define MIN(a, b) ((a < b) ? (a) : (b))
  16. #define AXIS_CHAR(a) ((a->is_x) ? 'x' : 'y')
  17. #define HASH_DIR(a) ((a->hash_scale > 0.0) ? 1 : -1)
  18.  
  19. static double Pi;
  20.  
  21. process_title(g)
  22. Graph g;
  23. {
  24.  
  25.   float ytitleloc;
  26.  
  27.   if (g->title->x == FSIG) g->title->x = g->x_axis->psize / 2.0;
  28.     else g->title->x = ctop(g->title->x, g->x_axis);
  29.   if (g->title->y != FSIG) g->title->y = ctop(g->title->y, g->y_axis);
  30.   else {
  31.     ytitleloc = 0.0;
  32.     if (g->x_axis->draw_axis_label && g->x_axis->label->label != CNULL) 
  33.       ytitleloc = MIN(ytitleloc, g->x_axis->label->ymin); 
  34.     if (g->x_axis->draw_hash_labels)
  35.       ytitleloc = MIN(ytitleloc, g->x_axis->hl->ymin);
  36.     if (g->x_axis->draw_hash_marks)
  37.       ytitleloc = MIN(ytitleloc, g->x_axis->draw_hash_marks_at - HASH_SIZE);
  38.     if (g->legend->type == 'u')
  39.       ytitleloc = MIN(ytitleloc, g->legend->l->ymin);
  40.     
  41.     g->title->y = ytitleloc - 10.0;
  42.   }
  43.   process_label(g->title, g, 0);
  44. }
  45.  
  46. process_legend(g)
  47. Graph g;
  48. {
  49.   Legend l;
  50.   int anything;
  51.   float height, hdist, y, x, width, maxmark, maxmarky;
  52.   Curve c;
  53.   char *s;
  54.  
  55.   l = g->legend;
  56.   if (l->type == 'n') return;
  57.   if (l->l->linesep == FSIG) l->l->linesep = l->l->fontsize;
  58.   l->anylines = 0;
  59.   maxmark = 0.0;
  60.   maxmarky = 0.0;
  61.   anything = 0;
  62.   for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
  63.     if (c->l->label != CNULL) {
  64.       anything = 1;
  65.       if (c->marktype == 'l') {
  66.          maxmark = MAX(maxmark, c->lmark->xmax - c->lmark->xmin); 
  67.          maxmarky = MAX(maxmarky, c->lmark->ymax - c->lmark->ymin); 
  68.       } else if (c->marktype != 'n') {
  69.         maxmark = MAX(maxmark, ABS(c->marksize[0]));
  70.         maxmarky = MAX(maxmarky, ABS(c->marksize[1]));
  71.       }
  72.       if (c->linetype != '0') l->anylines = 1;
  73.     }
  74.   }
  75.   if (l->linelength == FSIG)
  76.     l->linelength = (l->anylines) ? (MAX(maxmark + 6.0, 12.0)) : 0.0;
  77.     else l->linelength = disttop(l->linelength, g->x_axis);
  78.   if (l->midspace == FSIG)
  79.     l->midspace = (l->anylines) ? 4.0 : (maxmark / 2.0) + 4.0;
  80.     else l->midspace = disttop(l->midspace, g->x_axis);
  81.   if (l->linebreak == FSIG)
  82.     l->linebreak = MAX(l->l->linesep * FCPI / FPPI, maxmarky);
  83.     else l->linebreak = disttop(l->linebreak, g->y_axis);
  84.  
  85.   if (l->type == 'c') {
  86.     for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
  87.       if (c->l->label != CNULL) process_label(c->l, g, 1);
  88.     }
  89.     return;
  90.   }
  91.  
  92.   if (!anything) {
  93.     l->anylines = -1; 
  94.     return;
  95.   }
  96.  
  97.   width = 0.0;
  98.   height = -l->linebreak;
  99.   for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
  100.     if (c->l->label != CNULL) {
  101.       s = c->l->label;
  102.       copy_label(c->l, l->l);
  103.       c->l->x = 0.0;
  104.       c->l->y = 0.0;
  105.       c->l->rotate = 0.0;
  106.       c->l->hj = 'l';
  107.       c->l->vj = 'b';
  108.       c->l->label = s;
  109.       process_label(c->l, g, 0);
  110.       height += c->l->ymax + l->linebreak;
  111.       width = MAX(width, c->l->xmax);
  112.     }
  113.   }
  114.   hdist = (l->anylines) ? l->midspace + l->linelength : l->midspace;
  115.   width += hdist;
  116.  
  117.   if (l->l->x == FSIG) {
  118.     if (l->l->hj == 'c') {
  119.       l->l->x = g->x_axis->psize / 2;
  120.     } else if (l->l->hj == 'l') {
  121.       if (l->l->vj == 'c') {
  122.         l->l->x = g->x_axis->psize;
  123.         if (g->y_axis->draw_axis_label) 
  124.           l->l->x = MAX(l->l->x, g->y_axis->label->xmax);
  125.         if (g->y_axis->draw_hash_labels) 
  126.           l->l->x = MAX(l->l->x, g->y_axis->hl->xmax);
  127.         if (g->y_axis->draw_hash_marks) {
  128.           l->l->x = MAX(l->l->x, g->y_axis->draw_hash_marks_at);
  129.           l->l->x = MAX(l->l->x, g->y_axis->draw_hash_marks_at + 
  130.                                  HASH_DIR(g->y_axis) * HASH_SIZE);
  131.         }
  132.         l->l->x += 15.0;
  133.       } else {
  134.         l->l->x = 0.0;
  135.       }
  136.     } else {
  137.       if (l->l->vj == 'c') {
  138.         l->l->x = 0.0;
  139.         if (g->y_axis->draw_axis_label) 
  140.           l->l->x = MIN(l->l->x, g->y_axis->label->xmin);
  141.         if (g->y_axis->draw_hash_labels) 
  142.           l->l->x = MIN(l->l->x, g->y_axis->hl->xmin);
  143.         if (g->y_axis->draw_hash_marks) {
  144.           l->l->x = MIN(l->l->x, g->y_axis->draw_hash_marks_at);
  145.           l->l->x = MIN(l->l->x, g->y_axis->draw_hash_marks_at + 
  146.                                  HASH_DIR(g->y_axis) * HASH_SIZE);
  147.         }
  148.         l->l->x = l->l->x - 15.0;
  149.       } else {
  150.         l->l->x = g->x_axis->psize;
  151.       }
  152.     }
  153.   } else {
  154.     l->l->x = ctop(l->l->x, g->x_axis);
  155.   }
  156.   if (l->l->y == FSIG) {
  157.     if (l->l->vj == 'c') {
  158.       l->l->y = g->y_axis->psize / 2.0;
  159.     } else if (l->l->vj == 'b') {
  160.       l->l->y = g->y_axis->psize;
  161.       if (g->x_axis->draw_axis_label) 
  162.         l->l->y = MAX(l->l->y, g->x_axis->label->ymax);
  163.       if (g->x_axis->draw_hash_labels) 
  164.         l->l->y = MAX(l->l->y, g->x_axis->hl->ymax);
  165.       if (g->x_axis->draw_hash_marks) {
  166.         l->l->y = MAX(l->l->y, g->x_axis->draw_hash_marks_at);
  167.         l->l->y = MAX(l->l->y, g->x_axis->draw_hash_marks_at + 
  168.                                HASH_DIR(g->x_axis) * HASH_SIZE);
  169.       }
  170.       l->l->y += 15.0;
  171.     } else {
  172.       l->l->y = 0.0;
  173.       if (g->x_axis->draw_axis_label) 
  174.         l->l->y = MIN(l->l->y, g->x_axis->label->ymin);
  175.       if (g->x_axis->draw_hash_labels) 
  176.         l->l->y = MIN(l->l->y, g->x_axis->hl->ymin);
  177.       if (g->x_axis->draw_hash_marks) {
  178.         l->l->y = MIN(l->l->y, g->x_axis->draw_hash_marks_at);
  179.         l->l->y = MIN(l->l->y, g->x_axis->draw_hash_marks_at + 
  180.                                HASH_DIR(g->x_axis) * HASH_SIZE);
  181.       }
  182.       l->l->y -= 15.0;
  183.     }
  184.   } else {
  185.     l->l->y = ctop(l->l->y, g->y_axis);
  186.   }
  187.  
  188.   if (l->l->hj == 'l') x = 0.0;
  189.   else if (l->l->hj == 'c') x = - width/2.0;
  190.   else x = -width;
  191.  
  192.   if (l->l->vj == 't') y = 0.0;
  193.   else if (l->l->vj == 'c') y = height / 2.0;
  194.   else y = height;
  195.  
  196.   for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
  197.     if (c->l->label != CNULL) {
  198.       c->l->x = hdist + x;
  199.       c->l->y = y;
  200.       c->l->vj = 't';
  201.       c->l->hj = 'l';
  202.       c->l->rotate = 0.0;
  203.       process_label(c->l, g, 0);
  204.       y = c->l->ymin - l->linebreak;
  205.     }
  206.   }
  207.   
  208.   process_label_max_n_mins(l->l, width, height);
  209. }
  210.  
  211. float find_reasonable_hash_interval(a) 
  212. Axis a;
  213. {
  214.   float s, d;
  215.  
  216.   if (a->is_lg) return 0.0;
  217.   s = a->max - a->min;
  218.   d = 1.0;
  219.   if (s > 5.0) {
  220.     while(1) {
  221.       if (s / d < 6.0) return d;
  222.       d *= 2.0;
  223.       if (s / d < 6.0) return d;
  224.       d *= 2.5;
  225.       if (s / d < 6.0) return d;
  226.       d *= 2.0;
  227.     }
  228.   } else {
  229.     while(1) {
  230.       if (s / d > 2.0) return d;
  231.       d /= 2.0;
  232.       if (s / d > 2.0) return d;
  233.       d /= 2.5;
  234.       if (s / d > 2.0) return d;
  235.       d /= 2.0;
  236.     }
  237.   }
  238. }
  239.  
  240. float find_reasonable_hash_start(a)
  241. Axis a;
  242. {
  243.   int i;
  244.   
  245.   if (a->is_lg) return 0.0;
  246.   if (a->max > 0.0 && a->min < 0.0) return 0.0;
  247.   i = ((int) (a->min / a->hash_interval));
  248.   return ((float) i) * a->hash_interval;
  249. }
  250.  
  251. int find_reasonable_precision(a)
  252. Axis a;
  253. {
  254.   int i, b, b2, done;
  255.   float x, x2, tolerance;
  256.  
  257.   tolerance = 0.000001;
  258.   b = 0;
  259.   x = a->hash_interval;
  260.  
  261.   done = 0;
  262.   while(b < 6 && !done) {
  263.     i = (int) (x + 0.4);
  264.     x2 = i;
  265.     if (x2 - x < tolerance && x - x2 < tolerance) done = 1;
  266.     else {
  267.       b++;
  268.       x *= 10.0;
  269.       tolerance *= 10.0;
  270.     }
  271.   }
  272.  
  273.   tolerance = 0.000001;
  274.   b2 = 0;
  275.   x = a->hash_start;
  276.  
  277.   done = 0;
  278.   while(b2 < 6 && !done) {
  279.     i = (int) (x + 0.4);
  280.     x2 = i;
  281.     if (x2 - x < tolerance && x - x2 < tolerance) done = 1;
  282.     else {
  283.       b2++;
  284.       x *= 10.0;
  285.       tolerance *= 10.0;
  286.     }
  287.   }
  288.   return MAX(b, b2);
  289. }
  290.  
  291. int find_reasonable_minor_hashes(a)
  292. Axis a;
  293. {
  294.   float d;  
  295.   int i;
  296.   
  297.   if (a->is_lg) {
  298.     d = a->log_base;
  299.     while(d > 10.0) d /= 10.0;
  300.     while(d <= 1.0) d *= 10.0;
  301.     i = (int) d;
  302.     return MAX((i - 2), 0);
  303.   } else {
  304.     d = a->hash_interval;
  305.     if (d == 0.0) return 0;
  306.     while(d > 10.0) d /= 10.0;
  307.     while(d <= 1.0) d *= 10.0;
  308.     i = (int) d;
  309.     if (((float) i) != d) return 0;
  310.     return i-1;
  311.   }
  312. }
  313.  
  314. process_axis1(a, g)
  315. Axis a;
  316. Graph g;
  317. {
  318.   float tmp;
  319.   int i;
  320.  
  321.   if (a->min == FSIG) {
  322.     if (a->pmin == FSIG) {
  323.       error_header();
  324.       fprintf(stderr, 
  325.               "Graph %d: %c axis has no minimum, and cannot derive one\n",
  326.               g->num, AXIS_CHAR(a));
  327.       fprintf(stderr, "  Use %caxis min\n", AXIS_CHAR(a));
  328.       exit(1);
  329.     } else if (a->pmin <= 0.0 && a->is_lg) {
  330.       error_header();
  331.       fprintf(stderr, "Trying to derive %c axis\n", AXIS_CHAR(a));
  332.       fprintf(stderr, 
  333.         "        Minimum value %f will be -infinity with log axes\n", a->pmin);
  334.       exit(1);
  335.     } else a->min = a->pmin;
  336.   }
  337.   if (a->max == FSIG) {
  338.     if (a->pmax == FSIG) {
  339.       error_header();
  340.       fprintf(stderr, 
  341.               "Graph %d: %c axis has no maximum, and cannot derive one\n",
  342.               g->num, AXIS_CHAR(a));
  343.       fprintf(stderr, "  Use %caxis max\n", AXIS_CHAR(a));
  344.       exit(1);
  345.     } else if (a->pmax <= 0.0 && a->is_lg) {
  346.       error_header();
  347.       fprintf(stderr, "Trying to derive %c axis\n", AXIS_CHAR(a));
  348.       fprintf(stderr, 
  349.         "        Maximum value %f will be -infinity with log axes\n", a->pmax);
  350.       exit(1);
  351.     } else a->max = a->pmax;
  352.   }
  353.   if (a->max < a->min) {
  354.     tmp = a->max;  a->max = a->min;  a->min = tmp;
  355.   } else if (a->max == a->min) {
  356.     if (!a->is_lg) a->min -= 1;
  357.     a->max += 1;
  358.   }
  359.   a->psize = intop(a->size);
  360.   if (a->is_lg) {
  361.     if (a->min <= 0.0) {
  362.       error_header();
  363.       fprintf(stderr, 
  364.         "Graph %d, %c axis: Min value = %f.  This is -infinity with logrhythmic axes\n", 
  365.         g->num, (a->is_x) ? 'x' : 'y', a->min);
  366.       exit(1);
  367.     }
  368.     a->logfactor = log(a->log_base);
  369.     a->logmin = log(a->min) / a->logfactor;
  370.     a->factor = a->psize / (log(a->max) / a->logfactor - a->logmin);
  371.   } else {
  372.     a->factor = a->psize / (a->max - a->min);
  373.   }
  374.   if (a->gr_graytype == '0') {
  375.     a->gr_graytype = a->graytype;
  376.     for (i = 0; i < 3; i++) a->gr_gray[i] = a->gray[i];
  377.   }
  378.   if (a->mgr_graytype == '0') {
  379.     a->mgr_graytype = a->gr_graytype;
  380.     for (i = 0; i < 3; i++) a->mgr_gray[i] = a->gr_gray[i];
  381.   }
  382. }
  383.  
  384. process_axis2(a, g)
  385. Axis a;
  386. Graph g;
  387. {
  388.   float t1, t2, t3, minor_hashes, hloc, tmp;
  389.   float ymin, ymax, xmin, xmax;
  390.   int prec, i1;
  391.   Hash h;
  392.   String s;
  393.   Axis other;
  394.  
  395.   other = (a->is_x) ? g->y_axis : g->x_axis;
  396.   if (a->draw_at == FSIG) 
  397.     a->draw_at = (HASH_DIR(a) == -1) ? 0.0 : other->psize;
  398.   else a->draw_at = ctop(a->draw_at, other);
  399.  
  400.   if (a->hash_interval < 0.0) {
  401.     a->hash_interval = find_reasonable_hash_interval(a);
  402.     if (!a->start_given)
  403.       a->hash_start = find_reasonable_hash_start(a);
  404.   } else if (!a->start_given) a->hash_start = a->min;
  405.   if (a->minor_hashes < 0) {
  406.     a->minor_hashes = find_reasonable_minor_hashes(a);
  407.   }
  408.   if (a->precision < 0 && !a->is_lg)
  409.     a->precision = find_reasonable_precision(a);
  410.  
  411.   for (h = first(a->hash_lines) ; h != nil(a->hash_lines); h = next(h)) {
  412.     h->loc = ctop(h->loc, a);
  413.   }
  414.   
  415.   for (s = first(a->hash_labels); s != nil(a->hash_labels); s = next(s)) {
  416.     s->s->x = ctop(s->s->x, a);
  417.     s->s->y = ctop(s->s->y, a);
  418.   }
  419.  
  420.   if (((a->hash_interval != 0.0 && !a->is_lg) || a->is_lg) && a->auto_hash_marks) {
  421.     if (a->is_lg) {
  422.       for (t1 = 1.0; t1 > a->min; t1 /= a->log_base) ;
  423.       t2 = t1 * a->log_base - t1;
  424.     } else {
  425.       for (t1 = a->hash_start; t1 > a->min; t1 -= a->hash_interval) ;
  426.       t2 = a->hash_interval;
  427.     }
  428.     while (t1 <= a->max) {
  429.       hloc = ctop(t1, a);
  430.       if (hloc > -.05 && hloc < a->psize + .05) {
  431.         h = (Hash) get_node(a->hash_lines);
  432.         h->loc = hloc;
  433.         h->size = HASH_SIZE;
  434.         h->major = 1;
  435.         insert(h, a->hash_lines);
  436.         if (a->auto_hash_labels) {
  437.           s = (String) get_node (a->hash_labels);
  438.           s->s = new_label();
  439.           s->s->x = hloc;
  440.           s->s->y = hloc;
  441.           s->s->label = (char *) malloc (80);
  442.           if (a->precision >= 0) {
  443.             prec = a->precision;
  444.           } else {
  445.             if (ABS(t1) >= 1.0 || t1 == 0.0) prec = 0;
  446.             else {
  447.               tmp = ABS(t1);
  448.               prec = -1;
  449.               while(tmp < 1.0) {tmp *= 10.0; prec++;}
  450.             }
  451.           }
  452.           sprintf(s->s->label, "%.*f", prec, t1);
  453.           insert(s, a->hash_labels);
  454.         }
  455.       }
  456.       minor_hashes = t2 / ((float) (a->minor_hashes + 1));
  457.       t3 = t1;
  458.       for (i1 = 1; i1 <= a->minor_hashes; i1++) {
  459.         t3 += minor_hashes;
  460.         hloc = ctop(t3, a);
  461.         if (hloc > -.05 && hloc < a->psize + .05) {
  462.           h = (Hash) get_node(a->hash_lines);
  463.           h->loc = hloc;
  464.           h->size = MHASH_SIZE;
  465.           h->major = 0;
  466.           insert(h, a->hash_lines);
  467.         }
  468.       }
  469.       if (a->is_lg) {
  470.         t1 *= a->log_base;
  471.         t2 = t1 * a->log_base - t1;
  472.       } else t1 += t2;
  473.     }
  474.   }
  475.  
  476.   if (a->draw_hash_marks_at == FSIG)
  477.     a->draw_hash_marks_at = a->draw_at;
  478.   else a->draw_hash_marks_at = ctop(a->draw_hash_marks_at, other);
  479.   if (a->draw_hash_labels_at == FSIG)
  480.     a->draw_hash_labels_at = a->draw_hash_marks_at +
  481.       a->hash_scale * HASH_SIZE + HASH_DIR(a) * 3.0;
  482.   else a->draw_hash_labels_at = ctop(a->draw_hash_labels_at, other);
  483.  
  484.   if (a->is_x) {
  485.     a->hl->y = a->draw_hash_labels_at; 
  486.     if (a->hl->hj == '0')
  487.       a->hl->hj = 'c';
  488.     if (a->hl->vj == '0')
  489.       a->hl->vj = (HASH_DIR(a) == -1) ? 't' : 'b';
  490.   } else {
  491.     a->hl->x = a->draw_hash_labels_at;
  492.     if (a->hl->vj == '0') a->hl->vj = 'c';
  493.     if (a->hl->hj == '0')
  494.       a->hl->hj = (HASH_DIR(a) == -1) ? 'r' : 'l';
  495.   }
  496.  
  497.   ymin = (a->is_x) ? a->hl->y : 0;
  498.   ymax = (a->is_x) ? a->hl->y : a->psize;
  499.   xmin = (!a->is_x) ? a->hl->x : 0;
  500.   xmax = (!a->is_x) ? a->hl->x : a->psize;
  501.  
  502.   for (s = first(a->hash_labels); s != nil(a->hash_labels); s = next(s)) {
  503.     if (a->is_x) a->hl->x = s->s->x; else a->hl->y = s->s->y;
  504.     a->hl->label = s->s->label;
  505.     process_label(a->hl, g, 0);
  506.     xmin = MIN(a->hl->xmin, xmin);
  507.     ymin = MIN(a->hl->ymin, ymin);
  508.     xmax = MAX(a->hl->xmax, xmax);
  509.     ymax = MAX(a->hl->ymax, ymax);
  510.   }
  511.   a->hl->xmin = xmin;
  512.   a->hl->ymin = ymin;
  513.   a->hl->xmax = xmax;
  514.   a->hl->ymax = ymax;
  515.  
  516.   /* HERE -- now either test or continue */
  517.  
  518.   if (a->is_x) {
  519.     if (a->label->x == FSIG) 
  520.       a->label->x = a->psize / 2.0;
  521.       else a->label->x = ctop(a->label->x, g->x_axis);
  522.     if (a->label->y == FSIG) {
  523.       ymin = 0.0;
  524.       ymax = other->psize;
  525.       if (a->draw_hash_labels) {
  526.         ymin = MIN(ymin, a->hl->ymin); 
  527.         ymax = MAX(ymax, a->hl->ymax); 
  528.       } 
  529.       if (a->draw_hash_marks) {
  530.         ymin = MIN(ymin, a->draw_hash_marks_at);
  531.         ymin = MIN(ymin, a->draw_hash_marks_at + a->hash_scale * HASH_SIZE);
  532.         ymax = MAX(ymax, a->draw_hash_marks_at);
  533.         ymax = MAX(ymax, a->draw_hash_marks_at + a->hash_scale * HASH_SIZE);
  534.       } 
  535.       a->label->y = (HASH_DIR(a) == -1) ? ymin - 8.0 : ymax + 8.0 ;
  536.     } else a->label->y = ctop(a->label->y, g->y_axis);
  537.     if (a->label->hj == '0') a->label->hj = 'c';
  538.     if (a->label->vj == '0') a->label->vj = (HASH_DIR(a) == -1) ? 't' : 'b' ;
  539.     if (a->label->rotate == FSIG) a->label->rotate = 0.0;
  540.   } else {
  541.     if (a->label->y == FSIG) 
  542.       a->label->y = a->psize / 2.0;
  543.       else a->label->y = ctop(a->label->y, g->y_axis);
  544.     if (a->label->x == FSIG) {
  545.       xmin = 0.0;
  546.       xmax = other->psize;
  547.       if (a->draw_hash_labels) {
  548.         xmin = MIN(xmin, a->hl->xmin); 
  549.         xmax = MAX(xmax, a->hl->xmax); 
  550.       } 
  551.       if (a->draw_hash_marks) {
  552.         xmin = MIN(xmin, a->draw_hash_marks_at);
  553.         xmin = MIN(xmin, a->draw_hash_marks_at + a->hash_scale * HASH_SIZE);
  554.         xmax = MAX(xmax, a->draw_hash_marks_at);
  555.         xmax = MAX(xmax, a->draw_hash_marks_at + a->hash_scale * HASH_SIZE);
  556.       } 
  557.       a->label->x = (HASH_DIR(a) == -1) ? xmin - 8.0 : xmax + 8.0 ;
  558.     } else a->label->x = ctop(a->label->x, g->x_axis);
  559.     if (a->label->hj == '0') a->label->hj = 'c';
  560.     if (a->label->vj == '0') a->label->vj = 'b';
  561.     if (a->label->rotate == FSIG) 
  562.       a->label->rotate = (HASH_DIR(a) == -1) ? 90.0 : -90.0;
  563.   }
  564.   process_label (a->label, g, 0);
  565. }
  566.  
  567. process_label(l, g, adjust)
  568. Label l;
  569. Graph g;
  570. int adjust;
  571. {
  572.   float len, height;
  573.   int f, i;
  574.   float fnl, tmp;
  575.   char *s;
  576.  
  577.   if (l->label == CNULL) return;
  578.  
  579.   if (adjust) {
  580.     l->x = ctop(l->x, g->x_axis);
  581.     l->y = ctop(l->y, g->y_axis);
  582.   }
  583.   if (l->linesep == FSIG) l->linesep = l->fontsize;
  584.  
  585.   l->nlines = 0;
  586.   for (i = 0; l->label[i] != '\0'; i++) {
  587.     if (l->label[i] == '\n') {
  588.       l->label[i] = '\0';
  589.       l->nlines++;
  590.     }
  591.   }
  592.   fnl = (float) l->nlines;
  593.  
  594.   len = 0.0;
  595.   s = l->label;
  596.   for (i = 0; i <= l->nlines; i++) {
  597.     tmp = l->fontsize * FCPI / FPPI * strlen(s) * 0.8;
  598.     len = MAX(len, tmp);
  599.     if (i != l->nlines) {
  600.       f = strlen(s);
  601.       s[f] = '\n';
  602.       s = &(s[f+1]);
  603.     }
  604.   }
  605.   height = (l->fontsize * (fnl+1) + l->linesep * fnl) * FCPI / FPPI;
  606.   process_label_max_n_mins(l, len, height);
  607. }
  608.    
  609. process_label_max_n_mins(l, len, height)
  610. Label l;
  611. float len;
  612. float height;
  613. {
  614.   float xlen, ylen, xheight, yheight;
  615.   float x, y;
  616.  
  617.   xlen = len * cos(l->rotate * Pi / 180.00);
  618.   ylen = height * cos((l->rotate + 90.0) * Pi / 180.00);
  619.   xheight = len * sin(l->rotate * Pi / 180.00);
  620.   yheight = height * sin((l->rotate + 90.0) * Pi / 180.00);
  621.   
  622.   x = l->x;
  623.   y = l->y;
  624.  
  625.   if (l->hj == 'c') {
  626.     x -= xlen / 2.0;
  627.     y -= xheight / 2.0;
  628.   } else if (l->hj == 'r') {
  629.     x -= xlen;
  630.     y -= xheight;
  631.   }
  632.   if (l->vj == 'c') {
  633.     x -= ylen / 2.0;
  634.     y -= yheight / 2.0;
  635.   } else if (l->vj == 't') {
  636.     x -= ylen;
  637.     y -= yheight;
  638.   }
  639.  
  640.   l->xmin = MIN(x, x + xlen);
  641.   l->xmin = MIN(l->xmin, x + xlen + ylen);
  642.   l->xmin = MIN(l->xmin, x + ylen);
  643.  
  644.   l->ymin = MIN(y, y + xheight);
  645.   l->ymin = MIN(l->ymin, y + yheight);
  646.   l->ymin = MIN(l->ymin, y + xheight + yheight);
  647.  
  648.   l->xmax = MAX(x, x + xlen);
  649.   l->xmax = MAX(l->xmax, x + xlen + ylen);
  650.   l->xmax = MAX(l->xmax, x + ylen);
  651.  
  652.   l->ymax = MAX(y, y + xheight);
  653.   l->ymax = MAX(l->ymax, y + yheight);
  654.   l->ymax = MAX(l->ymax, y + xheight + yheight);
  655.  
  656. }
  657.  
  658. process_strings(g)
  659. Graph g;
  660. {
  661.   String s;
  662.  
  663.   for(s = first(g->strings); s != nil(g->strings); s = next(s)) {
  664.     process_label(s->s, g, 1);
  665.   }
  666. }
  667.  
  668. process_curve(c, g)
  669. Curve c;
  670. Graph g;
  671. {
  672.   if (c->bezier && (c->npts < 4 || (c->npts % 3 != 1))) {
  673.     error_header();
  674.     fprintf(stderr, "  Graph %d Curve %d:\n", g->num, c->num);
  675.     fprintf(stderr, "  Curve has %d points\n", c->npts);
  676.     fprintf(stderr, "  Bezier must have 3n + 1 points (n > 0)\n");
  677.     exit(1);
  678.   }
  679.   c->marksize[0] = (c->marksize[0] == FSIG) ? 
  680.                    4.0 : disttop(c->marksize[0], g->x_axis);
  681.   c->marksize[1] = (c->marksize[1] == FSIG) ? 
  682.                    4.0 : disttop(c->marksize[1], g->y_axis);
  683.   if (c->marktype == 'o') c->marksize[1] = c->marksize[0];
  684.   c->asize[0] = (c->asize[0] == FSIG) ? 
  685.                    6.0 : disttop(c->asize[0], g->x_axis);
  686.   c->asize[1] = (c->asize[1] == FSIG) ? 
  687.                    2.0 : disttop(c->asize[1], g->y_axis) / 2.0;
  688.   c->lmark->x = disttop(c->lmark->x, g->x_axis);
  689.   c->lmark->y = disttop(c->lmark->y, g->y_axis);
  690.   process_label(c->lmark, g, 0);
  691. }
  692.  
  693. process_curves(g)
  694. Graph g;
  695. {
  696.   Curve c;
  697.   for(c = first(g->curves); c != nil(g->curves); c = next(c)) {
  698.     process_curve(c, g);
  699.   }
  700. }
  701.  
  702. process_extrema(g)  /* This finds all the minval/maxvals for bbox calc */
  703. Graph g;
  704. {
  705.   Curve c;
  706.   String s;
  707.   Axis xa, ya;
  708.  
  709.   xa = g->x_axis;
  710.   ya = g->y_axis;
  711.  
  712.   g->xminval = 0.0;
  713.   g->yminval = 0.0;
  714.   g->xmaxval = xa->psize;
  715.   g->ymaxval = ya->psize;
  716.   
  717.   if (xa->draw_axis_label) process_label_extrema(xa->label, g);
  718.   if (ya->draw_axis_label) process_label_extrema(ya->label, g);
  719.   if (xa->draw_hash_labels) process_label_extrema(xa->hl, g);
  720.   if (ya->draw_hash_labels) process_label_extrema(ya->hl, g);
  721.  
  722.   if (xa->draw_hash_marks) {
  723.       g->yminval = MIN(g->yminval, xa->draw_hash_marks_at);
  724.       g->yminval = MIN(g->yminval, 
  725.                        xa->draw_hash_marks_at + HASH_DIR(xa) * HASH_SIZE);
  726.       g->ymaxval = MAX(g->ymaxval, xa->draw_hash_marks_at);
  727.       g->ymaxval = MAX(g->ymaxval, 
  728.                        xa->draw_hash_marks_at + HASH_DIR(xa) * HASH_SIZE);
  729.   }
  730.   if (ya->draw_hash_marks) {
  731.       g->xminval = MIN(g->xminval, ya->draw_hash_marks_at);
  732.       g->xminval = MIN(g->xminval, 
  733.                        ya->draw_hash_marks_at + HASH_DIR(ya) * HASH_SIZE);
  734.       g->xmaxval = MAX(g->xmaxval, ya->draw_hash_marks_at);
  735.       g->xmaxval = MAX(g->xmaxval, 
  736.                        ya->draw_hash_marks_at + HASH_DIR(ya) * HASH_SIZE);
  737.   }
  738.   process_label_extrema(g->title, g);  
  739.  
  740.   if (g->legend->type == 'c') {
  741.     for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
  742.       process_label_extrema(c->l, g);
  743.     }
  744.   } else if (g->legend->type == 'u' && g->legend->anylines >= 0) {
  745.     process_label_extrema(g->legend->l, g);
  746.   }
  747.   for(s = first(g->strings); s != nil(g->strings); s = next(s)) {
  748.     process_label_extrema(s->s, g);
  749.   }
  750. }
  751.  
  752. process_label_extrema(l, g)
  753. Label l;
  754. Graph g;
  755. {
  756.   if (l->label == CNULL) return;
  757.   g->yminval = MIN(g->yminval, l->ymin);
  758.   g->ymaxval = MAX(g->ymaxval, l->ymax);
  759.   g->xminval = MIN(g->xminval, l->xmin);
  760.   g->xmaxval = MAX(g->xmaxval, l->xmax);
  761. }
  762.  
  763. process_graph(g)
  764. Graph g;
  765. {
  766.   g->x_translate = intop(g->x_translate);
  767.   g->y_translate = intop(g->y_translate);
  768.   process_axis1(g->x_axis, g);
  769.   process_axis1(g->y_axis, g);
  770.   process_axis2(g->x_axis, g);
  771.   process_axis2(g->y_axis, g);
  772.   process_curves(g);
  773.   process_legend(g);
  774.   process_strings(g);
  775.   process_title(g);
  776.   process_extrema(g);
  777. }
  778.  
  779. process_graphs(gs)
  780. Graphs gs;
  781. {
  782.   Graphs the_g;
  783.   Graph g;
  784.   float diff, max_y, min_y, max_x, min_x;
  785.   int do_bb, i;
  786.  
  787.   Pi = acos(-1.0);
  788.   for (the_g = first(gs); the_g != nil(gs); the_g = next(the_g)) {
  789.     for (g = first(the_g->g); g != nil(the_g->g); g = next(g)) process_graph(g);
  790.     max_x = 0.0;
  791.     min_x = 0.0;
  792.     max_y = 0.0;
  793.     min_y = 0.0;
  794.     for (g = first(the_g->g); g != nil(the_g->g); g = next(g)) {
  795.       max_y = MAX(max_y, g->y_translate + g->ymaxval);
  796.       min_y = MIN(min_y, g->y_translate + g->yminval);
  797.       max_x = MAX(max_x, g->x_translate + g->xmaxval);
  798.       min_x = MIN(min_x, g->x_translate + g->xminval);
  799.     }
  800.     if (the_g->height >= 0.00) {
  801.       the_g->height *= FCPI;
  802.       if (the_g->height > max_y - min_y) {
  803.         diff = (the_g->height - max_y + min_y) / 2.0;
  804.         max_y += diff;
  805.         min_y -= diff;
  806.       } else {
  807.         the_g->height = max_y - min_y;
  808.       }
  809.     } else {
  810.       the_g->height = max_y - min_y;
  811.     }
  812.     if (the_g->width >= 0.00) {
  813.       the_g->width *= FCPI;
  814.       if (the_g->width > max_x - min_x) {
  815.         diff = (the_g->width - max_x + min_x) / 2.0;
  816.         max_x += diff;
  817.         min_x -= diff;
  818.       } else {
  819.         the_g->width = max_x - min_x;
  820.       }
  821.     } else {
  822.       the_g->width = max_x - min_x;
  823.     }
  824.  
  825.     do_bb = 1;
  826.     for (i = 0; i < 4; i++) do_bb = (do_bb && the_g->bb[i] == FSIG);
  827.     if (do_bb) {
  828.       the_g->bb[0] = min_x;
  829.       the_g->bb[1] = min_y;
  830.       the_g->bb[2] = max_x;
  831.       the_g->bb[3] = max_y;
  832.     } 
  833.   }
  834. }
  835.