/* 
 * $Source: /tmp_mnt/n/fs/grad1/jsp/src/jgraph/RCS/process.c,v $
 * $Revision: 8.3 $
 * $Date: 92/11/30 11:42:35 $
 * $Author: jsp $
 */

#include <stdio.h>
#include <math.h>

#include "jgraph.h"

#define ABS(a) ((a > 0.0) ? (a) : (-a))
#define MAX(a, b) ((a > b) ? (a) : (b))
#define MIN(a, b) ((a < b) ? (a) : (b))
#define AXIS_CHAR(a) ((a->is_x) ? 'x' : 'y')
#define HASH_DIR(a) ((a->hash_scale > 0.0) ? 1 : -1)

static double Pi;

process_title(g)
Graph g;
{

  float ytitleloc;

  if (g->title->x == FSIG) g->title->x = g->x_axis->psize / 2.0;
    else g->title->x = ctop(g->title->x, g->x_axis);
  if (g->title->y != FSIG) g->title->y = ctop(g->title->y, g->y_axis);
  else {
    ytitleloc = 0.0;
    if (g->x_axis->draw_axis_label && g->x_axis->label->label != CNULL) 
      ytitleloc = MIN(ytitleloc, g->x_axis->label->ymin); 
    if (g->x_axis->draw_hash_labels)
      ytitleloc = MIN(ytitleloc, g->x_axis->hl->ymin);
    if (g->x_axis->draw_hash_marks)
      ytitleloc = MIN(ytitleloc, g->x_axis->draw_hash_marks_at - HASH_SIZE);
    if (g->legend->type == 'u')
      ytitleloc = MIN(ytitleloc, g->legend->l->ymin);
    
    g->title->y = ytitleloc - 10.0;
  }
  process_label(g->title, g, 0);
}

process_legend(g)
Graph g;
{
  Legend l;
  int anything;
  float height, hdist, y, x, width, maxmark, maxmarky;
  Curve c;
  char *s;

  l = g->legend;
  if (l->type == 'n') return;
  if (l->l->linesep == FSIG) l->l->linesep = l->l->fontsize;
  l->anylines = 0;
  maxmark = 0.0;
  maxmarky = 0.0;
  anything = 0;
  for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
    if (c->l->label != CNULL) {
      anything = 1;
      if (c->marktype == 'l') {
         maxmark = MAX(maxmark, c->lmark->xmax - c->lmark->xmin); 
         maxmarky = MAX(maxmarky, c->lmark->ymax - c->lmark->ymin); 
      } else if (c->marktype != 'n') {
        maxmark = MAX(maxmark, ABS(c->marksize[0]));
        maxmarky = MAX(maxmarky, ABS(c->marksize[1]));
      }
      if (c->linetype != '0') l->anylines = 1;
    }
  }
  if (l->linelength == FSIG)
    l->linelength = (l->anylines) ? (MAX(maxmark + 6.0, 24.0)) : 0.0;
    else l->linelength = disttop(l->linelength, g->x_axis);
  if (l->midspace == FSIG)
    l->midspace = (l->anylines) ? 4.0 : (maxmark / 2.0) + 4.0;
    else l->midspace = disttop(l->midspace, g->x_axis);
  if (l->linebreak == FSIG)
    l->linebreak = MAX(l->l->linesep * FCPI / FPPI, maxmarky);
    else l->linebreak = disttop(l->linebreak, g->y_axis);

  if (l->type == 'c') {
    for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
      if (c->l->label != CNULL) process_label(c->l, g, 1);
    }
    return;
  }

  if (!anything) {
    l->anylines = -1; 
    return;
  }

  width = 0.0;
  height = -l->linebreak;
  for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
    if (c->l->label != CNULL) {
      s = c->l->label;
      copy_label(c->l, l->l);
      c->l->x = 0.0;
      c->l->y = 0.0;
      c->l->rotate = 0.0;
      c->l->hj = 'l';
      c->l->vj = 'b';
      c->l->label = s;
      process_label(c->l, g, 0);
      height += c->l->ymax + l->linebreak;
      width = MAX(width, c->l->xmax);
    }
  }
  hdist = (l->anylines) ? l->midspace + l->linelength : l->midspace;
  width += hdist;

  if (l->l->x == FSIG) {
    if (l->l->hj == 'c') {
      l->l->x = g->x_axis->psize / 2;
    } else if (l->l->hj == 'l') {
      if (l->l->vj == 'c') {
        l->l->x = g->x_axis->psize;
        if (g->y_axis->draw_axis_label) 
          l->l->x = MAX(l->l->x, g->y_axis->label->xmax);
        if (g->y_axis->draw_hash_labels) 
          l->l->x = MAX(l->l->x, g->y_axis->hl->xmax);
        if (g->y_axis->draw_hash_marks) {
          l->l->x = MAX(l->l->x, g->y_axis->draw_hash_marks_at);
          l->l->x = MAX(l->l->x, g->y_axis->draw_hash_marks_at + 
                                 HASH_DIR(g->y_axis) * HASH_SIZE);
        }
        l->l->x += 15.0;
      } else {
        l->l->x = 0.0;
      }
    } else {
      if (l->l->vj == 'c') {
        l->l->x = 0.0;
        if (g->y_axis->draw_axis_label) 
          l->l->x = MIN(l->l->x, g->y_axis->label->xmin);
        if (g->y_axis->draw_hash_labels) 
          l->l->x = MIN(l->l->x, g->y_axis->hl->xmin);
        if (g->y_axis->draw_hash_marks) {
          l->l->x = MIN(l->l->x, g->y_axis->draw_hash_marks_at);
          l->l->x = MIN(l->l->x, g->y_axis->draw_hash_marks_at + 
                                 HASH_DIR(g->y_axis) * HASH_SIZE);
        }
        l->l->x = l->l->x - 15.0;
      } else {
        l->l->x = g->x_axis->psize;
      }
    }
  } else {
    l->l->x = ctop(l->l->x, g->x_axis);
  }
  if (l->l->y == FSIG) {
    if (l->l->vj == 'c') {
      l->l->y = g->y_axis->psize / 2.0;
    } else if (l->l->vj == 'b') {
      l->l->y = g->y_axis->psize;
      if (g->x_axis->draw_axis_label) 
        l->l->y = MAX(l->l->y, g->x_axis->label->ymax);
      if (g->x_axis->draw_hash_labels) 
        l->l->y = MAX(l->l->y, g->x_axis->hl->ymax);
      if (g->x_axis->draw_hash_marks) {
        l->l->y = MAX(l->l->y, g->x_axis->draw_hash_marks_at);
        l->l->y = MAX(l->l->y, g->x_axis->draw_hash_marks_at + 
                               HASH_DIR(g->x_axis) * HASH_SIZE);
      }
      l->l->y += 15.0;
    } else {
      l->l->y = 0.0;
      if (g->x_axis->draw_axis_label) 
        l->l->y = MIN(l->l->y, g->x_axis->label->ymin);
      if (g->x_axis->draw_hash_labels) 
        l->l->y = MIN(l->l->y, g->x_axis->hl->ymin);
      if (g->x_axis->draw_hash_marks) {
        l->l->y = MIN(l->l->y, g->x_axis->draw_hash_marks_at);
        l->l->y = MIN(l->l->y, g->x_axis->draw_hash_marks_at + 
                               HASH_DIR(g->x_axis) * HASH_SIZE);
      }
      l->l->y -= 15.0;
    }
  } else {
    l->l->y = ctop(l->l->y, g->y_axis);
  }

  if (l->l->hj == 'l') x = 0.0;
  else if (l->l->hj == 'c') x = - width/2.0;
  else x = -width;

  if (l->l->vj == 't') y = 0.0;
  else if (l->l->vj == 'c') y = height / 2.0;
  else y = height;

  for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
    if (c->l->label != CNULL) {
      c->l->x = hdist + x;
      c->l->y = y;
      c->l->vj = 't';
      c->l->hj = 'l';
      c->l->rotate = 0.0;
      process_label(c->l, g, 0);
      y = c->l->ymin - l->linebreak;
    }
  }
  
  process_label_max_n_mins(l->l, width, height);
}

float find_reasonable_hash_interval(a) 
Axis a;
{
  float s, d;

  if (a->is_lg) return 0.0;
  s = a->max - a->min;
  d = 1.0;
  if (s > 5.0) {
    while(1) {
      if (s / d < 6.0) return d;
      d *= 2.0;
      if (s / d < 6.0) return d;
      d *= 2.5;
      if (s / d < 6.0) return d;
      d *= 2.0;
    }
  } else {
    while(1) {
      if (s / d > 2.0) return d;
      d /= 2.0;
      if (s / d > 2.0) return d;
      d /= 2.5;
      if (s / d > 2.0) return d;
      d /= 2.0;
    }
  }
}

float find_reasonable_hash_start(a)
Axis a;
{
  int i;
  
  if (a->is_lg) return 0.0;
  if (a->max > 0.0 && a->min < 0.0) return 0.0;
  i = ((int) (a->min / a->hash_interval));
  return ((float) i) * a->hash_interval;
}

int find_reasonable_precision(a)
Axis a;
{
  int i, b, b2, done;
  float x, x2, tolerance;

  if (a->hash_format == 'g' || a->hash_format == 'G') return 6;
  if (a->hash_format == 'e' || a->hash_format == 'E') return 0;
  if (a->is_lg) return 0;

  tolerance = 0.000001;
  b = 0;
  x = a->hash_interval;

  done = 0;
  while(b < 6 && !done) {
    i = (int) (x + 0.4);
    x2 = i;
    if (x2 - x < tolerance && x - x2 < tolerance) done = 1;
    else {
      b++;
      x *= 10.0;
      tolerance *= 10.0;
    }
  }

  tolerance = 0.000001;
  b2 = 0;
  x = a->hash_start;

  done = 0;
  while(b2 < 6 && !done) {
    i = (int) (x + 0.4);
    x2 = i;
    if (x2 - x < tolerance && x - x2 < tolerance) done = 1;
    else {
      b2++;
      x *= 10.0;
      tolerance *= 10.0;
    }
  }
  return MAX(b, b2);
}

int find_reasonable_minor_hashes(a)
Axis a;
{
  float d;  
  int i;
  
  if (a->is_lg) {
    d = a->log_base;
    while(d > 10.0) d /= 10.0;
    while(d <= 1.0) d *= 10.0;
    i = (int) d;
    return MAX((i - 2), 0);
  } else {
    d = a->hash_interval;
    if (d == 0.0) return 0;
    while(d > 10.0) d /= 10.0;
    while(d <= 1.0) d *= 10.0;
    i = (int) d;
    if (((float) i) != d) return 0;
    return i-1;
  }
}

process_axis1(a, g)
Axis a;
Graph g;
{
  float tmp;
  int i;

  if (a->min == FSIG) {
    if (a->pmin == FSIG) {
      error_header();
      fprintf(stderr, 
              "Graph %d: %c axis has no minimum, and cannot derive one\n",
              g->num, AXIS_CHAR(a));
      fprintf(stderr, "  Use %caxis min\n", AXIS_CHAR(a));
      exit(1);
    } else if (a->pmin <= 0.0 && a->is_lg) {
      error_header();
      fprintf(stderr, "Trying to derive %c axis\n", AXIS_CHAR(a));
      fprintf(stderr, 
        "        Minimum value %f will be -infinity with log axes\n", a->pmin);
      exit(1);
    } else a->min = a->pmin;
  }
  if (a->max == FSIG) {
    if (a->pmax == FSIG) {
      error_header();
      fprintf(stderr, 
              "Graph %d: %c axis has no maximum, and cannot derive one\n",
              g->num, AXIS_CHAR(a));
      fprintf(stderr, "  Use %caxis max\n", AXIS_CHAR(a));
      exit(1);
    } else if (a->pmax <= 0.0 && a->is_lg) {
      error_header();
      fprintf(stderr, "Trying to derive %c axis\n", AXIS_CHAR(a));
      fprintf(stderr, 
        "        Maximum value %f will be -infinity with log axes\n", a->pmax);
      exit(1);
    } else a->max = a->pmax;
  }
  if (a->max < a->min) {
    tmp = a->max;  a->max = a->min;  a->min = tmp;
  } else if (a->max == a->min) {
    if (!a->is_lg) a->min -= 1;
    a->max += 1;
  }
  a->psize = intop(a->size);
  if (a->is_lg) {
    if (a->min <= 0.0) {
      error_header();
      fprintf(stderr, 
        "Graph %d, %c axis: Min value = %f.  This is -infinity with logrhythmic axes\n", 
        g->num, (a->is_x) ? 'x' : 'y', a->min);
      exit(1);
    }
    a->logfactor = log(a->log_base);
    a->logmin = log(a->min) / a->logfactor;
    a->factor = a->psize / (log(a->max) / a->logfactor - a->logmin);
  } else {
    a->factor = a->psize / (a->max - a->min);
  }
  if (a->gr_graytype == '0') {
    a->gr_graytype = a->graytype;
    for (i = 0; i < 3; i++) a->gr_gray[i] = a->gray[i];
  }
  if (a->mgr_graytype == '0') {
    a->mgr_graytype = a->gr_graytype;
    for (i = 0; i < 3; i++) a->mgr_gray[i] = a->gr_gray[i];
  }
}

process_axis2(a, g)
Axis a;
Graph g;
{
  float t1, t2, t3, minor_hashes, hloc, tmp;
  float ymin, ymax, xmin, xmax;
  int prec, i1;
  Hash h;
  String s;
  Axis other;

  other = (a->is_x) ? g->y_axis : g->x_axis;
  if (a->draw_at == FSIG) 
    a->draw_at = (HASH_DIR(a) == -1) ? 0.0 : other->psize;
  else a->draw_at = ctop(a->draw_at, other);

  if (a->hash_interval < 0.0) {
    a->hash_interval = find_reasonable_hash_interval(a);
    if (!a->start_given)
      a->hash_start = find_reasonable_hash_start(a);
  } else if (!a->start_given) a->hash_start = a->min;
  if (a->minor_hashes < 0) {
    a->minor_hashes = find_reasonable_minor_hashes(a);
  }
  if (a->precision < 0) a->precision = find_reasonable_precision(a);

  for (h = first(a->hash_lines) ; h != nil(a->hash_lines); h = next(h)) {
    h->loc = ctop(h->loc, a);
  }
  
  for (s = first(a->hash_labels); s != nil(a->hash_labels); s = next(s)) {
    s->s->x = ctop(s->s->x, a);
    s->s->y = ctop(s->s->y, a);
  }

  if (((a->hash_interval != 0.0 && !a->is_lg) || a->is_lg) && a->auto_hash_marks) {
    if (a->is_lg) {
      for (t1 = 1.0; t1 > a->min; t1 /= a->log_base) ;
      t2 = t1 * a->log_base - t1;
    } else {
      for (t1 = a->hash_start; t1 > a->min; t1 -= a->hash_interval) ;
      t2 = a->hash_interval;
    }
    while (t1 <= a->max) {
      hloc = ctop(t1, a);
      if (hloc > -.05 && hloc < a->psize + .05) {
        h = (Hash) get_node(a->hash_lines);
        h->loc = hloc;
        h->size = HASH_SIZE;
        h->major = 1;
        insert(h, a->hash_lines);
        if (a->auto_hash_labels) {
          s = (String) get_node (a->hash_labels);
          s->s = new_label();
          s->s->x = hloc;
          s->s->y = hloc;
          s->s->label = (char *) malloc (80);
          if (a->precision >= 0) {
            prec = a->precision;
          } else {
            if (ABS(t1) >= 1.0 || t1 == 0.0) prec = 0;
            else {
              tmp = ABS(t1);
              prec = -1;
              while(tmp < 1.0) {tmp *= 10.0; prec++;}
            }
          }
	  switch(a->hash_format) {
            case 'G': sprintf(s->s->label, "%.*G", prec, t1); break;
            case 'g': sprintf(s->s->label, "%.*g", prec, t1); break;
            case 'E': sprintf(s->s->label, "%.*E", prec, t1); break;
            case 'e': sprintf(s->s->label, "%.*e", prec, t1); break;
            case 'f': sprintf(s->s->label, "%.*f", prec, t1); break;
            default: fprintf(stderr, "Internal jgraph error: hl_st\n");
		     exit(1);
          }
          insert(s, a->hash_labels);
        }
      }
      minor_hashes = t2 / ((float) (a->minor_hashes + 1));
      t3 = t1;
      for (i1 = 1; i1 <= a->minor_hashes; i1++) {
        t3 += minor_hashes;
        hloc = ctop(t3, a);
        if (hloc > -.05 && hloc < a->psize + .05) {
          h = (Hash) get_node(a->hash_lines);
          h->loc = hloc;
          h->size = MHASH_SIZE;
          h->major = 0;
          insert(h, a->hash_lines);
        }
      }
      if (a->is_lg) {
        t1 *= a->log_base;
        t2 = t1 * a->log_base - t1;
      } else t1 += t2;
    }
  }

  if (a->draw_hash_marks_at == FSIG)
    a->draw_hash_marks_at = a->draw_at;
  else a->draw_hash_marks_at = ctop(a->draw_hash_marks_at, other);
  if (a->draw_hash_labels_at == FSIG)
    a->draw_hash_labels_at = a->draw_hash_marks_at +
      a->hash_scale * HASH_SIZE + HASH_DIR(a) * 3.0;
  else a->draw_hash_labels_at = ctop(a->draw_hash_labels_at, other);

  if (a->is_x) {
    a->hl->y = a->draw_hash_labels_at; 
    if (a->hl->hj == '0')
      a->hl->hj = 'c';
    if (a->hl->vj == '0')
      a->hl->vj = (HASH_DIR(a) == -1) ? 't' : 'b';
  } else {
    a->hl->x = a->draw_hash_labels_at;
    if (a->hl->vj == '0') a->hl->vj = 'c';
    if (a->hl->hj == '0')
      a->hl->hj = (HASH_DIR(a) == -1) ? 'r' : 'l';
  }

  ymin = (a->is_x) ? a->hl->y : 0;
  ymax = (a->is_x) ? a->hl->y : a->psize;
  xmin = (!a->is_x) ? a->hl->x : 0;
  xmax = (!a->is_x) ? a->hl->x : a->psize;

  for (s = first(a->hash_labels); s != nil(a->hash_labels); s = next(s)) {
    if (a->is_x) a->hl->x = s->s->x; else a->hl->y = s->s->y;
    a->hl->label = s->s->label;
    process_label(a->hl, g, 0);
    xmin = MIN(a->hl->xmin, xmin);
    ymin = MIN(a->hl->ymin, ymin);
    xmax = MAX(a->hl->xmax, xmax);
    ymax = MAX(a->hl->ymax, ymax);
  }
  a->hl->xmin = xmin;
  a->hl->ymin = ymin;
  a->hl->xmax = xmax;
  a->hl->ymax = ymax;

  /* HERE -- now either test or continue */

  if (a->is_x) {
    if (a->label->x == FSIG) 
      a->label->x = a->psize / 2.0;
      else a->label->x = ctop(a->label->x, g->x_axis);
    if (a->label->y == FSIG) {
      ymin = 0.0;
      ymax = other->psize;
      if (a->draw_hash_labels) {
        ymin = MIN(ymin, a->hl->ymin); 
        ymax = MAX(ymax, a->hl->ymax); 
      } 
      if (a->draw_hash_marks) {
        ymin = MIN(ymin, a->draw_hash_marks_at);
        ymin = MIN(ymin, a->draw_hash_marks_at + a->hash_scale * HASH_SIZE);
        ymax = MAX(ymax, a->draw_hash_marks_at);
        ymax = MAX(ymax, a->draw_hash_marks_at + a->hash_scale * HASH_SIZE);
      } 
      a->label->y = (HASH_DIR(a) == -1) ? ymin - 8.0 : ymax + 8.0 ;
    } else a->label->y = ctop(a->label->y, g->y_axis);
    if (a->label->hj == '0') a->label->hj = 'c';
    if (a->label->vj == '0') a->label->vj = (HASH_DIR(a) == -1) ? 't' : 'b' ;
    if (a->label->rotate == FSIG) a->label->rotate = 0.0;
  } else {
    if (a->label->y == FSIG) 
      a->label->y = a->psize / 2.0;
      else a->label->y = ctop(a->label->y, g->y_axis);
    if (a->label->x == FSIG) {
      xmin = 0.0;
      xmax = other->psize;
      if (a->draw_hash_labels) {
        xmin = MIN(xmin, a->hl->xmin); 
        xmax = MAX(xmax, a->hl->xmax); 
      } 
      if (a->draw_hash_marks) {
        xmin = MIN(xmin, a->draw_hash_marks_at);
        xmin = MIN(xmin, a->draw_hash_marks_at + a->hash_scale * HASH_SIZE);
        xmax = MAX(xmax, a->draw_hash_marks_at);
        xmax = MAX(xmax, a->draw_hash_marks_at + a->hash_scale * HASH_SIZE);
      } 
      a->label->x = (HASH_DIR(a) == -1) ? xmin - 8.0 : xmax + 8.0 ;
    } else a->label->x = ctop(a->label->x, g->x_axis);
    if (a->label->hj == '0') a->label->hj = 'c';
    if (a->label->vj == '0') a->label->vj = 'b';
    if (a->label->rotate == FSIG) 
      a->label->rotate = (HASH_DIR(a) == -1) ? 90.0 : -90.0;
  }
  process_label (a->label, g, 0);
}

process_label(l, g, adjust)
Label l;
Graph g;
int adjust;
{
  float len, height;
  int f, i;
  float fnl, tmp;
  char *s;

  if (l->label == CNULL) return;

  if (adjust) {
    l->x = ctop(l->x, g->x_axis);
    l->y = ctop(l->y, g->y_axis);
  }
  if (l->linesep == FSIG) l->linesep = l->fontsize;

  l->nlines = 0;
  for (i = 0; l->label[i] != '\0'; i++) {
    if (l->label[i] == '\n') {
      l->label[i] = '\0';
      l->nlines++;
    }
  }
  fnl = (float) l->nlines;

  len = 0.0;
  s = l->label;
  for (i = 0; i <= l->nlines; i++) {
    tmp = l->fontsize * FCPI / FPPI * strlen(s) * 0.8;
    len = MAX(len, tmp);
    if (i != l->nlines) {
      f = strlen(s);
      s[f] = '\n';
      s = &(s[f+1]);
    }
  }
  height = (l->fontsize * (fnl+1) + l->linesep * fnl) * FCPI / FPPI;
  process_label_max_n_mins(l, len, height);
}
   
process_label_max_n_mins(l, len, height)
Label l;
float len;
float height;
{
  float xlen, ylen, xheight, yheight;
  float x, y;

  xlen = len * cos(l->rotate * Pi / 180.00);
  ylen = height * cos((l->rotate + 90.0) * Pi / 180.00);
  xheight = len * sin(l->rotate * Pi / 180.00);
  yheight = height * sin((l->rotate + 90.0) * Pi / 180.00);
  
  x = l->x;
  y = l->y;

  if (l->hj == 'c') {
    x -= xlen / 2.0;
    y -= xheight / 2.0;
  } else if (l->hj == 'r') {
    x -= xlen;
    y -= xheight;
  }
  if (l->vj == 'c') {
    x -= ylen / 2.0;
    y -= yheight / 2.0;
  } else if (l->vj == 't') {
    x -= ylen;
    y -= yheight;
  }

  l->xmin = MIN(x, x + xlen);
  l->xmin = MIN(l->xmin, x + xlen + ylen);
  l->xmin = MIN(l->xmin, x + ylen);

  l->ymin = MIN(y, y + xheight);
  l->ymin = MIN(l->ymin, y + yheight);
  l->ymin = MIN(l->ymin, y + xheight + yheight);

  l->xmax = MAX(x, x + xlen);
  l->xmax = MAX(l->xmax, x + xlen + ylen);
  l->xmax = MAX(l->xmax, x + ylen);

  l->ymax = MAX(y, y + xheight);
  l->ymax = MAX(l->ymax, y + yheight);
  l->ymax = MAX(l->ymax, y + xheight + yheight);

}

process_strings(g)
Graph g;
{
  String s;

  for(s = first(g->strings); s != nil(g->strings); s = next(s)) {
    process_label(s->s, g, 1);
  }
}

process_curve(c, g)
Curve c;
Graph g;
{
  if (c->bezier && (c->npts < 4 || (c->npts % 3 != 1))) {
    error_header();
    fprintf(stderr, "  Graph %d Curve %d:\n", g->num, c->num);
    fprintf(stderr, "  Curve has %d points\n", c->npts);
    fprintf(stderr, "  Bezier must have 3n + 1 points (n > 0)\n");
    exit(1);
  }
  c->marksize[0] = (c->marksize[0] == FSIG) ? 
                   4.0 : disttop(c->marksize[0], g->x_axis);
  c->marksize[1] = (c->marksize[1] == FSIG) ? 
                   4.0 : disttop(c->marksize[1], g->y_axis);
  if (c->marktype == 'o') c->marksize[1] = c->marksize[0];
  c->asize[0] = (c->asize[0] == FSIG) ? 
                   6.0 : disttop(c->asize[0], g->x_axis);
  c->asize[1] = (c->asize[1] == FSIG) ? 
                   2.0 : disttop(c->asize[1], g->y_axis) / 2.0;
  c->lmark->x = disttop(c->lmark->x, g->x_axis);
  c->lmark->y = disttop(c->lmark->y, g->y_axis);
  process_label(c->lmark, g, 0);
  if (c->parg == FSIG) c->parg = 0.0;
  if (c->aparg == FSIG) c->aparg = 0.0;
  if (c->pparg == FSIG) c->pparg = 0.0;
}

process_curves(g)
Graph g;
{
  Curve c;
  for(c = first(g->curves); c != nil(g->curves); c = next(c)) {
    process_curve(c, g);
  }
}
 
process_extrema(g)  /* This finds all the minval/maxvals for bbox calc */
Graph g;
{
  Curve c;
  String s;
  Axis xa, ya;

  xa = g->x_axis;
  ya = g->y_axis;

  g->xminval = 0.0;
  g->yminval = 0.0;
  g->xmaxval = xa->psize;
  g->ymaxval = ya->psize;
  
  if (xa->draw_axis_label) process_label_extrema(xa->label, g);
  if (ya->draw_axis_label) process_label_extrema(ya->label, g);
  if (xa->draw_hash_labels) process_label_extrema(xa->hl, g);
  if (ya->draw_hash_labels) process_label_extrema(ya->hl, g);

  if (xa->draw_hash_marks) {
      g->yminval = MIN(g->yminval, xa->draw_hash_marks_at);
      g->yminval = MIN(g->yminval, 
                       xa->draw_hash_marks_at + HASH_DIR(xa) * HASH_SIZE);
      g->ymaxval = MAX(g->ymaxval, xa->draw_hash_marks_at);
      g->ymaxval = MAX(g->ymaxval, 
                       xa->draw_hash_marks_at + HASH_DIR(xa) * HASH_SIZE);
  }
  if (ya->draw_hash_marks) {
      g->xminval = MIN(g->xminval, ya->draw_hash_marks_at);
      g->xminval = MIN(g->xminval, 
                       ya->draw_hash_marks_at + HASH_DIR(ya) * HASH_SIZE);
      g->xmaxval = MAX(g->xmaxval, ya->draw_hash_marks_at);
      g->xmaxval = MAX(g->xmaxval, 
                       ya->draw_hash_marks_at + HASH_DIR(ya) * HASH_SIZE);
  }
  process_label_extrema(g->title, g);  

  if (g->legend->type == 'c') {
    for (c = first(g->curves); c != nil(g->curves); c = next(c)) {
      process_label_extrema(c->l, g);
    }
  } else if (g->legend->type == 'u' && g->legend->anylines >= 0) {
    process_label_extrema(g->legend->l, g);
  }
  for(s = first(g->strings); s != nil(g->strings); s = next(s)) {
    process_label_extrema(s->s, g);
  }
}

process_label_extrema(l, g)
Label l;
Graph g;
{
  if (l->label == CNULL) return;
  g->yminval = MIN(g->yminval, l->ymin);
  g->ymaxval = MAX(g->ymaxval, l->ymax);
  g->xminval = MIN(g->xminval, l->xmin);
  g->xmaxval = MAX(g->xmaxval, l->xmax);
}

process_graph(g)
Graph g;
{
  g->x_translate = intop(g->x_translate);
  g->y_translate = intop(g->y_translate);
  process_axis1(g->x_axis, g);
  process_axis1(g->y_axis, g);
  process_axis2(g->x_axis, g);
  process_axis2(g->y_axis, g);
  process_curves(g);
  process_legend(g);
  process_strings(g);
  process_title(g);
  process_extrema(g);
}

process_graphs(gs)
Graphs gs;
{
  Graphs the_g;
  Graph g;
  float diff, max_y, min_y, max_x, min_x;
  int do_bb, i;

  Pi = acos(-1.0);
  for (the_g = first(gs); the_g != nil(gs); the_g = next(the_g)) {
    for (g = first(the_g->g); g != nil(the_g->g); g = next(g)) process_graph(g);
    max_x = 0.0;
    min_x = 0.0;
    max_y = 0.0;
    min_y = 0.0;
    for (g = first(the_g->g); g != nil(the_g->g); g = next(g)) {
      max_y = MAX(max_y, g->y_translate + g->ymaxval);
      min_y = MIN(min_y, g->y_translate + g->yminval);
      max_x = MAX(max_x, g->x_translate + g->xmaxval);
      min_x = MIN(min_x, g->x_translate + g->xminval);
    }

    if (the_g->height >= 0.00) {
      the_g->height *= FCPI;
      if (the_g->height > max_y - min_y) {
        diff = (the_g->height - max_y + min_y) / 2.0;
        max_y += diff;
        min_y -= diff;
      } else {
        the_g->height = max_y - min_y;
      }
    } else {
      the_g->height = max_y - min_y;
    }
    if (the_g->width >= 0.00) {
      the_g->width *= FCPI;
      if (the_g->width > max_x - min_x) {
        diff = (the_g->width - max_x + min_x) / 2.0;
        max_x += diff;
        min_x -= diff;
      } else {
        the_g->width = max_x - min_x;
      }
    } else {
      the_g->width = max_x - min_x;
    }

    do_bb = 1;
    for (i = 0; i < 4; i++) do_bb = (do_bb && the_g->bb[i] == ISIG);
    if (do_bb) {
      the_g->bb[0] = (int) (min_x - 1.0);
      the_g->bb[1] = (int) (min_y - 1.0);
      the_g->bb[2] = (int) (max_x + 1.0);
      the_g->bb[3] = (int) (max_y + 1.0);
    } 
  }
}
