
/* "WOL", an integrated circuit layout tool,
   Copyright (C) 1983, 1990 California Institute of Technology.
   Author: Massimo Sivilotti
   Thanks to: Glenn Gribble, Marty Sirkin, Sylvie Rychebusch
	      Maryann Mayer, Carver Mead, Rick Koshi, Torre Lande
   Maintainer: John Lazzaro
   Maintainers's address: lazzaro@hobiecat.cs.caltech.edu;
                          CB 425/ CU Boulder/Boulder CO 91125. 
			  Send questions, bug fixes, to this address.

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation (Version 1, 1989).

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; see the file COPYING.  If not, write to
the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */

/* Output from p2c, the Pascal-to-C translator */
/* p2c: wolopt.text, line 9: Note: Range checking is OFF [216] */
/* p2c: wolopt.text, line 10: Note: Stack checking is OFF [217] */
/* p2c: wolopt.text, line 16: Note: Range checking is ON [216] */
/* p2c: hpgl.text, line 4: Note: Range checking is OFF [216] */
/* From input file "hpgl.text" */


/* Change these for testing */




#include "global.h"


#define HPGL_PLOTTER_G
#include "hpgl_plotter.h"


#define plotter         705   /* HPIB address of plotter */

#define plotter_sc      (plotter / 100)


Static short xpos, ypos;   /* where we last put the pen */
Static boolean penup;
Static short newcolor;   /* -1 if color already taken */

Static boolean scaling_on;   /* use scaling/transform stuff? */
Static boolean realsize;   /* use plotter's real size? */
Static struct {
  /* scaling window size */
  long llx, lly, urx, ury;
} size;


void pl_transform(long *rx, long *ry)
{
  if (!scaling_on)
    return;
  tr_2(*rx, *ry);
  *rx = tr_ax;
  *ry = tr_ay;
  /*x := rx;
  {y := ry;
  {rx := (x*tr_ctm.a+y*tr_ctm.c+tr_ctm.e) div tr_ctm.g;
  {ry := (x*tr_ctm.b+y*tr_ctm.d+tr_ctm.f) div tr_ctm.g;*/
}


const tr_matrix ident_mat = {
  1, 0, 0, 1, 0, 0, 1
};


void pl_ident(void)
{
  tr_ctm = ident_mat;
}


Static void pl_print_matrix(tr_matrix m)
{
  printf("|%6ld%6ld|    1\n", m.a, m.b);
  printf("|%6ld%6ld|   ---\n", m.c, m.d);
  printf("|%6ld%6ld|%6ld\n", m.e, m.f, m.g);
}


void pl_tran(long dx, long dy)
{
  tr_ctm.e += tr_ctm.a * dx + tr_ctm.c * dy;
  tr_ctm.f += tr_ctm.b * dx + tr_ctm.d * dy;
}


void pl_scale(long x, long y, long num)
{
  tr_ctm.a *= x;
  tr_ctm.b *= x;
  tr_ctm.c *= y;
  tr_ctm.d *= y;
  tr_ctm.e *= num;
  tr_ctm.f *= num;
  tr_ctm.g *= num;
}


/* pre-multiply the tr_ctm */
Static void pl_premult(tr_matrix *m)
{
  tr_matrix tmpmat;

  tmpmat.a = m->a * tr_ctm.a + m->b * tr_ctm.c;
  tmpmat.b = m->a * tr_ctm.b + m->b * tr_ctm.d;
  tmpmat.c = m->c * tr_ctm.a + m->d * tr_ctm.c;
  tmpmat.d = m->c * tr_ctm.b + m->d * tr_ctm.d;
  tmpmat.e = m->e * tr_ctm.a + m->f * tr_ctm.c + m->g * tr_ctm.e;
  tmpmat.f = m->e * tr_ctm.b + m->f * tr_ctm.d + m->g * tr_ctm.f;
  tmpmat.g = m->g * tr_ctm.g;
  tr_ctm = tmpmat;
}


void pl_rot(long cos, long sin)
{
  /* cosine, sine of rotation */
  long a, b, c, d;

  a = tr_ctm.a;
  b = tr_ctm.b;
  c = tr_ctm.c;
  d = tr_ctm.d;
  tr_ctm.a = cos * a + sin * tr_ctm.c;
  tr_ctm.b = cos * b + sin * tr_ctm.d;
  tr_ctm.c = cos * tr_ctm.c - sin * a;
  tr_ctm.d = cos * tr_ctm.d - sin * b;
  /*pl_print_matrix(tr_ctm);*/
}


void pl_xform(long xf)
{
  switch (xf) {

  case 0:   /* do nothing */
    break;

  case 1:  /* rotate by 90 */
    pl_rot(0, 1);
    break;

  case 2:  /* rotate by 180 */
    pl_rot(-1, 0);
    break;

  case 3:  /* rotate by 270 */
    pl_rot(0, -1);
    break;

  case 4:  /* mirror in x */
    pl_scale(-1, 1, 1);
    break;

  case 5:  /* mx,  rotate by 90 */
    pl_rot(0, 1);
    pl_scale(-1, 1, 1);
    break;

  case 6:  /* mx, rotate by 180 */
    pl_rot(-1, 0);
    pl_scale(-1, 1, 1);
    break;

  case 7:  /* mx, rotate by 270 */
    pl_rot(0, -1);
    pl_scale(-1, 1, 1);
    break;

  default:
    printf("\007ILLEGAL xform in PL_XFORM\n");
    break;
  }
}


void pl_out(Char *s)
{
  set_timeout(plotter_sc, 0.0);
/* p2c: hpgl.text, line 169: Note: Character >= 128 encountered [281] */
/* p2c: hpgl.text, line 169: Note: Character >= 128 encountered [281] */
/* p2c: hpgl.text, line 169:
 * Note: WRITE statement contains color/attribute characters [203] */
  printf("\211%s\210", s);
  P_writestring(plotter, s);
}


void pl_in(Char *s)
{
  set_timeout(plotter_sc, 0.0);
  P_readstring(plotter, s);
/* p2c: hpgl.text, line 177: Note: Character >= 128 encountered [281] */
/* p2c: hpgl.text, line 177: Note: Character >= 128 encountered [281] */
/* p2c: hpgl.text, line 177:
 * Note: WRITE statement contains color/attribute characters [203] */
  printf("\213%s\210", s);
}


void pl_scaleon(void)
{
  scaling_on = true;
}


void pl_scaleoff(void)
{
  scaling_on = false;
}


void pl_init(void)
{
  pl_out("DF;OI;");   /* default, get id */
  pl_in(pl_id);   /* read plotter id */
  pl_scaleoff();
  penup = true;
  realsize = true;
  newcolor = 1;   /* give user a color if he plots */
}


#define error           8   /* 1/8 */


/* Local variables for pl_scaleto: */
struct LOC_pl_scaleto {
  long n;   /* scaling stuff */
} ;

Local boolean errf(long scalei, double scaler, struct LOC_pl_scaleto *LINK)
{
  return ((double)error / LINK->n * fabs(scalei - LINK->n * scaler) >= scaler);
}


void pl_scaleto(long bbllx, long bblly, long bburx, long bbury,
		boolean samescale)
{
  struct LOC_pl_scaleto V;
  long dx, dy;   /* size of bbox */
  long llx, lly, urx, ury, ox, oy;   /* offsets (transform) */
  long sx, sy;
  double scalex, scaley;   /* scaling information */

  pl_getsize(&llx, &lly, &urx, &ury);
  dx = bburx - bbllx;
  if (dx == 0)
    dx = 1;
  dy = bbury - bblly;
  if (dy == 0)
    dy = 1;
  scalex = (double)(urx - llx) / dx;
  scaley = (double)(ury - lly) / dy;
  if (samescale) {
    if (scalex < scaley)
      scaley = scalex;
    else
      scalex = scaley;
  }
  ox = llx - (long)floor(bbllx * scalex + 0.5);
  oy = lly - (long)floor(bblly * scaley + 0.5);

  pl_ident();
  pl_tran(ox, oy);
  V.n = 1;
  sx = (long)floor(scalex + 0.5);
  sy = (long)floor(scaley + 0.5);
  while (V.n < 32 && (errf(sx, scalex, &V) || errf(sy, scaley, &V))) {
    V.n *= 2;
    sx = (long)floor(V.n * scalex + 0.5);
    sy = (long)floor(V.n * scaley + 0.5);
  }
  pl_scale(sx, sy, V.n);
  pl_scaleon();
  pl_print_matrix(tr_ctm);
}

#undef error


void pl_setclip(long llx, long lly, long urx, long ury)
{
  Char out[256];
  long p;

  penup = true;
  sprintf(out, ";PU;IW%ld,%ld,%ld,%ld;", llx, lly, urx, ury);
  p = strlen(out) + 1;
  pl_out(out);
}


void pl_setsize(long llx, long lly, long urx, long ury)
{
  Char out[256];
  long p;

  penup = true;
  sprintf(out, ";PU;IP%ld,%ld,%ld,%ld;", llx, lly, urx, ury);
  p = strlen(out) + 1;
  pl_out(out);
  size.llx = llx;
  size.lly = lly;
  size.urx = urx;
  size.ury = ury;
  realsize = false;
}


void pl_getsize(long *llx, long *lly, long *urx, long *ury)
{
  Char result[256];
  Char c;
  long p;

  if (!realsize) {
    *llx = size.llx;
    *lly = size.lly;
    *urx = size.urx;
    *ury = size.ury;
    return;
  }
  pl_out(";PU;OP;");
  penup = true;
  pl_in(result);
  TRY(try1);
    sscanf(result, "%ld%c%ld%c%ld%c%ld%ln", llx, &c, lly, &c, urx, &c, ury,
	   &p);
    p++;
  RECOVER(try1);
    if (P_escapecode != -10)
      _Escape(P_escapecode);
    printf("pl_getsize: bad data from plotter 'OP' \"%s\"\n", result);
    *llx = 500;
    *lly = 500;
    *urx = 9500;
    *ury = 7000;
  ENDTRY(try1);
}


Static void penposition(boolean down)
{
  Char out[256];
  long len;

  sprintf(out, ";PU");
  len = strlen(out) + 1;
  if (newcolor > 0) {
    sprintf(out + len - 1, ";SP%d", newcolor);
    len = strlen(out) + 1;
  }
  newcolor = -1;
  sprintf(out + len - 1, ";PA%d,%d", xpos, ypos);
  len = strlen(out) + 1;
  if (down) {
    sprintf(out + len - 1, ";PD;PR");
    len = strlen(out) + 1;
  }
  pl_out(out);
  penup = !down;
}


void pl_move(long x, long y)
{
  pl_transform(&x, &y);
  penup = true;
  xpos = x;
  ypos = y;
}


void pl_draw(long x, long y)
{
  Char out[256];
  long len;

  pl_transform(&x, &y);
  out[0] = '\0';
  if (penup)
    penposition(true);
  else
    strcpy(out, ",");
  sprintf(out + strlen(out), "%ld,%ld", x - xpos, y - ypos);
  len = strlen(out) + 1;
  xpos = x;
  ypos = y;
  pl_out(out);
}


void pl_box(long lx, long ly, long hx, long hy)
{
  pl_move(lx, ly);
  pl_draw(lx, hy);
  pl_draw(hx, hy);
  pl_draw(hx, ly);
  pl_draw(lx, ly);
}


void pl_end(void)
{
  long a, b, c, d;
  Char out[256];

  realsize = true;   /* force it to read P2 */
  pl_getsize(&a, &b, &c, &d);   /* move to P2 and try to spit out paper?? */
  sprintf(out, ";PU;SP0;PA%ld,%ld;", c, d);
  a = strlen(out) + 1;
  pl_out(out);
  penup = true;
  newcolor = -1;
}


void pl_color(short pen)
{
  /* put pen up */
  pl_out(";PU;");
  penup = true;
  /* indicate need for new color */
  if (pen > 0)
    newcolor = pen;
  else {
    pl_out("SP0;");   /* put away pens */
    newcolor = -1;
  }
}


void pl_text(Char *s)
{
  Char result[256];
  long p, x, y;
  Char c;
  Char STR2[256];

  penposition(false);
  sprintf(STR2, ";LB%s\003;PU;OC;", s);
  pl_out(STR2);
  pl_in(result);
  TRY(try2);
    sscanf(result, "%ld%c%ld%ln", &x, &c, &y, &p);
    p++;
    xpos = x;
    ypos = y;
  RECOVER(try2);
    if (P_escapecode != -10)
      _Escape(P_escapecode);
    printf("pl_text: bad data from plotter 'OC' \"%s\"\n", result);
    /* can't change xpos and ypos */
  ENDTRY(try2);
  penup = true;
}


#define min_width       0.0030


void pl_text_in_box(long x1, long y1, long x2, long y2, Char *s_)
{
  Char s[256];
  long a, b, c, d;
  boolean newsizes;
  double neww, newh;
  Char out[256];
  long p;
  Char ch;
  long bw, bh;   /* box height and width */
  long pw, ph;   /* plotter height and width */

  long run, rise;   /* from CTM */
  Char STR2[256];

  /*pl_box(x1,y1,x2,y2);*/

  strcpy(s, s_);
  /* Figure out the current transformation matrix */
  /* Matrix is always at a right-angle */
  run = 0;
  rise = 0;   /* default */
  if (tr_ctm.a > 0)
    run = 1;
  else if (tr_ctm.a < 0)
    run = -1;
  else if (tr_ctm.c > 0)
    rise = -1;
  else if (tr_ctm.c < 0)
    rise = 1;
  sprintf(out, ";PU;DI%ld,%ld", run, rise);
  p = strlen(out) + 1;
  pl_out(out);
  penup = true;


  pl_transform(&x1, &y1);
  pl_transform(&x2, &y2);
  bw = labs(x2 - x1) * 9 / 10;   /* pretend 90% normal size */
  bh = labs(y2 - y1) * 9 / 10;
  if (rise != 0) {   /* switch width and height */
    p = bw;
    bw = bh;
    bh = p;
  }

  pl_getsize(&a, &b, &c, &d);
  pw = labs(c - a) * 3 / 2;   /* 1.5 fudge for white space on plotter */
  ph = labs(d - b);

  /* We are using default character sizes.  Thus, characters are */
  /* .75% of |c-a| wide and 1.5% of |d-b| high. */
  newsizes = false;   /* use good old sizes */
  neww = 0.0075;   /* default values */
  newh = 0.015;   /* used by plotter */
  if (strlen(s) * neww * pw > bw) {
    neww = (double)bw / (strlen(s) * pw);
    if (neww < min_width) {
      neww = min_width;
      s[(long)(bw / (pw * neww))] = '\0';
/* p2c: hpgl.text, line 452:
 * Note: Modification of string length may translate incorrectly [146] */
      if (strlen(s) < 1)   /* ABORT!!! */
	goto _L1;
    }
    newh = 2 * neww;   /* shrink newheight for proportional chars */
    newsizes = true;
  }
  if (newh * ph > bh) {
    newh = (double)bh / ph;
    if (newh < 2 * min_width)   /* ABORT!!! (cell too short) */
      goto _L1;
    newsizes = true;
  }
  if (newsizes) {
    sprintf(out, ";PU;SR%0.2f,%0.2f", neww * 100, newh * 100);
    p = strlen(out) + 1;
    pl_out(out);
    penup = true;
  }
  /* now figure out where to go */
  if (rise == 0) {
    xpos = (long)floor(
	     (x1 + x2 + run * neww * pw * (1.0 / 3 - strlen(s))) / 2 + 0.5);
    ypos = (long)floor((y1 + y2 - run * newh * ph) / 2 + 0.5);
  } else {
    xpos = (long)floor((x1 + x2 + rise * newh * ph) / 2 + 0.5);
    ypos = (long)floor(
	     (y1 + y2 + rise * neww * pw * (1.0 / 3 - strlen(s))) / 2 + 0.5);
  }
  penposition(false);
  sprintf(STR2, ";LB%s\003;PU;OC;", s);
  pl_out(STR2);
  pl_in(out);
  TRY(try3);
    sscanf(out, "%ld%c%ld%ln", &x1, &ch, &y1, &p);
    p++;
    xpos = x1;
    ypos = y1;
  RECOVER(try3);
    if (P_escapecode != -10)
      _Escape(P_escapecode);
    misc_printerror(P_escapecode, P_ioresult);
    printf("pl_boxit: bad data from plotter 'OC' \"%s\"\n", out);
    /* can't change xpos and ypos */
  ENDTRY(try3);
  penup = true;
  if (newsizes)   /* restore default */
    pl_out(";PU;SR0.75,1.5");
_L1: ;
}

#undef min_width




/* End. */
