Source file: /~heha/hs/dos/hp2xx_hs.zip/hpgl.c

/* Copyright (c) 1991 - 1994 Heinz W. Werntges.  All rights reserved.
   Parts Copyright (c) 1999 - 2001 Martin Kroeker All rights reserved.
 */

/** HPGL.c: HPGL parser & i/o part of HP2xx (based on D. Donath's "HPtoGF.c")
 **
 ** 91/01/13  V 1.00  HWW  Originating
 ** 91/01/19  V 1.01  HWW  reorganized
 ** 91/01/24  V 1.02  HWW  ESC.-Sequences acknowledged (preliminary!!)
 ** 91/01/29  V 1.03  HWW  Incl. SUN portation
 ** 91/01/31  V 1.04  HWW  Parser: ESC sequences should be skipped now
 ** 91/02/10  V 1.05  HWW  Parser renewed
 ** 91/02/15  V 1.06  HWW  stdlib.h supported
 ** 91/02/19  V 1.07a HWW  parser refined, bugs fixed
 ** 91/06/09  V 1.08  HWW  New options added; some restructuring
 ** 91/06/16  V 1.09  HWW  VGA mode added; some renaming; silent_mode!
 ** 91/06/20  V 1.10  HWW  Rotation added
 ** 91/10/15  V 1.11  HWW  ANSI_C; header files reorganized
 ** 91/10/20  V 1.11a HWW  VAX_C support
 ** 91/10/25  V 1.11b HWW  Support of LT; and LT0; (line type, partial)
 ** 91/11/20  V 1.12  HWW  SPn; support: many changes!
 ** 91/11/21  V 1.12b HWW  First comma in "PA,xxxx,yyyy..." accepted
 ** 91/12/22  V 1.13  HWW  Multiple MOVE compression; "plot_rel", "old_pen"
 ** 92/01/13  V 1.13c HWW  VAX problem with ungetc()/fscanf() fixed; bug fixed
 ** 92/01/15  V 1.13d HWW  "vga" --> "pre"
 ** 92/01/30  V 1.14c HWW  Parser: no need of ';', better portable
 ** 92/02/06  V 1.15a HWW  Parser: AR, AA, CI, read_float() added;
 **			   toupper() removed (MACH problems)
 ** 92/02/19  V 1.16c HWW  LB etc. supported
 ** 92/02/23  V 1.17b HWW  LB etc. improved, PG supported
 ** 92/02/25  V 1.17c HWW  Parser improved: SP, LT, multi-mv suppression
 ** 92/03/01  V 1.17d HWW  Char sizes: debugged
 ** 92/03/03  V 1.17e HWW  LB_Mode introduced
 ** 92/04/15  V 1.17f HWW  Width x Height limit assumed
 ** 92/05/21  V 1.18a HWW  Multiple-file usage
 ** 92/05/28  V 1.19a HWW  XT, YT, TL, SM added
 ** 92/10/20  V 1.20c HWW  More line types added (debugged)
 ** 92/11/08  V 1.20d HWW  Interval of active pages
 ** 92/12/13  V 1.20e HWW  truesize option added
 ** 93/02/10  V 1.21a HWW  Arcs & circles now properly closed;
 **			   Bug fixed: SC does not interfere with last move
 ** 93/03/10  V 1.21b HWW  Bug fixed in LT scanner part
 ** 93/03/22, V 1.21c HWW  HYPOT() workaround for a weird BCC behavior;
 ** 93/04/02		   Line_Generator(): Case *pb==*pa caught
 ** 93/04/13  V 1.22a HWW  UC supported (code by Alois Treindl)
 ** 93/04/25  V 1.22b HWW  LB/PR bug fix by E. Norum included
 ** 93/05/20  V 1.22c HWW  LT1 pattern adjustment (report by E. Frambach)
 ** 93/09/02  V 1.22d HWW  EA (rect) added (by Th. Hiller)
 ** 94/01/01  V 1.22e HWW  Misc. additions suggested by L. Lowe:
 **			    1) PlotCmd_from_tmpfile(): int --> PlotCmd
 **                         2) ES: 2nd parameter now optional
 **                         3) evaluate_HPGL(): center_mode introduced
 ** 94/02/14  V 1.30a HWW  Re-organized; many changes; min/max bug fixed
 ** 99/02/28          MK   IW,CA,CS,SA,SS commands added
 ** 99/04/24          MK   PC,PW commands added
 ** 99/05/10          MK   RO command added (code by rs@daveg.com) 
 ** 99/05/18          MK   partial PE support (by Eugene Doudine)
 ** 99/06/05          MK   PC improvements and fixes
 ** 99/11/30          MK   support for fractional PE; PS/RO fixes
 ** 00/02/06          MK   allow commandline overrides for PC/PW
 ** 00/02/13          MK   DV support (backport from delayed 3.4.prealpha)
 ** 00/02/26          MK   ER,EP,FP,FT,PM,PT,RA,RR,WG commands added
 ** 00/02/27          MK   WU command added
 ** 00/03/02          MK   SC types 1 and 2, more robust handling of PE,
 **                        removed PE_line(), split lines() into file reader
 **                        and common linedrawing backend for PD/PA and PE
 **                        added PJL parser and RTL escape sequences 
 **                        (all these patches provided by Eugene Doudine) 
 ** 00/03/03          MK   convert IW parameters if scaling is in effect 
 ** 00/03/05          MK   AT/RT (arc through three points) added
 ** 01/01/01	      MK   UL added and PW rewritten (Andrew J.Bird)
 ** 		           empty PUPD sequence now draws a small dot
 **			   linedrawing fixed (added two moves when IW was
 **	 		   in effect, ever since IW support was added)
 **/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include "bresnham.h"
#include "hp2xx.h"
#include "chardraw.h"
#include "clip.h"
#include "pendef.h"
#include "lindef.h"

#define	ETX		'\003'

#define P1X_default	603.0	/* DIN A4 defaults        */
#define P1Y_default	521.0
#define P2X_default	10603.0
#define P2Y_default	7721.0



#ifdef __TURBOC__
#define	HYPOT(x,y)	sqrt((x)*(x)+(y)*(y))
#else
#define	HYPOT(x,y)	hypot(x,y)
#endif


/**
 ** Globals needed in chardraw.c:
 **/
				/* Line type selected by HP-GL code     */
				/* Currently effective line type        */
LineType CurrentLineType = LT_solid;

HPGL_Pt HP_pos =
{0};				/* Actual plotter pen position  */
HPGL_Pt P1 =
{P1X_default, P1Y_default};	/* Scaling points */
HPGL_Pt P2 =
{P2X_default, P2Y_default};
int iwflag = 0;			/*MK */
int mode_vert = 0;
HPGL_Pt C1 =
{P1X_default, P1Y_default};	/* Clipping points        */
HPGL_Pt C2 =
{P2X_default, P2Y_default};
HPGL_Pt S1 =
{P1X_default, P1Y_default};	/* Scaled       */
HPGL_Pt S2 =
{P2X_default, P2Y_default};	/* points       */
HPGL_Pt Q;			/* Delta-P/Delta-S: Initialized with first SC   */
HPGL_Pt M;			/* maximum coordinates set by PS instruction */
/**
 ** Global from chardraw.c:
 **/
extern TextPar tp;

/**
 ** "Local" globals (I know this is messy...) :
 **/
static float xmin, xmax, ymin, ymax, neg_ticklen, pos_ticklen;
static double Diag_P1_P2,pat_pos;
static HPGL_Pt p_last =
{M_PI, M_PI};			/* Init. to "impossible" values */

static HPGL_Pt polygons[MAXPOLY];
static int vertices = -1;
static short polygon_mode = FALSE;
static int filltype = 1;
static float hatchspace=0.;
static float hatchangle=0.;
static float thickness=0.;
static short polygon_penup = FALSE;

static float rot_cos, rot_sin;

static short rotate_flag = FALSE;	/* Flags tec external to HP-GL  */
static short ps_flag = FALSE;
static double rot_ang = 0.;
short scale_flag = FALSE;
static short mv_flag = FALSE;
#ifdef	ATARI
extern short silent_mode = FALSE;	/* Don't clobber ATARI preview! */
#else
static short silent_mode = FALSE;
#endif
static short fixedcolor = FALSE;
static short fixedwidth = FALSE;
static short record_off = FALSE;
static short first_page = 0;
static int last_page = 0;
static int n_unexpected = 0;
static int n_unknown = 0;
static int page_number = 1;
static long vec_cntr_r = 0L;
static long vec_cntr_w = 0L;
static short pen = -1;
static short pens_in_use[NUMPENS];
static short pen_down = FALSE;	/* Internal HP-GL book-keeping: */
static short plot_rel = FALSE;
static short wu_relative = FALSE; 
static char StrTerm = ETX;	/* String terminator char       */
static char *strbuf = NULL;
static unsigned int strbufsize = MAX_LB_LEN + 1;
static char symbol_char = '\0';	/* Char in Symbol Mode (0=off)  */

static FILE *td;


/* Known HPGL commands, ASCII-coded as High-byte/low-byte int's */

#define AA	0x4141
#define AF	0x4146
#define AH	0x4148
#define AR	0x4152
#define AT      0x4154
#define BL	0x424C
#define BP      0x4250
#define CA      0x4341		/*MK */
#define CI	0x4349
#define CO	0x434F          /*AJB*/
#define CP	0x4350
#define CS      0x4353		/*MK */
#define DF	0x4446
#define DI	0x4449
#define DR	0x4452
#define DT	0x4454
#define DV      0x4456
#define EA	0x4541
#define EC	0x4543          /*AJB*/
#define EP      0x4550
#define ER      0x4552
#define ES	0x4553
#define EW      0x4557		/*MK */
#define FP      0x4650
#define FT      0x4654
#define IN	0x494E
#define IP	0x4950
#define IW      0x4957		/*MK */
#define LB	0x4C42
#define LO	0x4C4F
#define LT	0x4C54
#define MG      0x4D47
#define NP      0x4E50
#define NR      0x4E52
#define OP	0x4F50
#define PA	0x5041
#define PB	0x5042
#define PC      0x5043		/*MK */
#define PD	0x5044
#define PE      0x5045
#define PG	0x5047
#define PM      0x504D
#define PR	0x5052
#define PS      0x5053
#define PT      0x5054
#define PU	0x5055
#define PW	0x5057		/*MK */
#define RA      0x5241
#define RO	0x524F		/*RS */
#define RR      0x5252
#define RT      0x5254
#define SA      0x5341		/*MK */
#define SC	0x5343
#define SI	0x5349
#define SL	0x534C
#define SM	0x534D
#define SP	0x5350
#define SR	0x5352
#define SS      0x5353		/*MK */
#define TL	0x544C
#define UC	0x5543
#define UL	0x554C          /*AJB*/
#define WD	0x5744
#define WG      0x5747
#define WU      0x5755
#define XT	0x5854
#define YT	0x5954




static void
par_err_exit (int code, int cmd)
/*par_err_exit (short code, short cmd)*/
{
const  char *msg;

  switch (code)
    {
    case 0:
      msg = "Illegal parameters";
      break;
    case 1:
      msg = "Error in first parameter";
      break;
    case 2:
      msg = "No second parameter";
      break;
    case 3:
      msg = "No third parameter";
      break;
    case 4:
      msg = "No fourth parameter";
      break;
    case 98:
      msg = "sscanf error: corrupted file?";
      break;
    case 99:
    default:
      msg = "Internal error";
      break;
    }
  Eprintf ("\nError in command %c%c: %s\n", cmd >> 8, cmd & 0xFF, msg);
  Eprintf (" @ Cmd %ld\n", vec_cntr_w);
  exit (ERROR);
}




static void
reset_HPGL (void)
{
  p_last.x = p_last.y = M_PI;
  pen_down = FALSE;
  plot_rel = FALSE;
  pen = -1;
  n_unexpected = 0;
  n_unknown = 0;
  mv_flag = FALSE;

  CurrentLineType = LT_solid;

  set_line_style_defaults();

  StrTerm = ETX;
  if (strbuf == NULL)
    {
      strbuf = malloc (strbufsize);
      if (strbuf == NULL)
	{
	  fprintf (stderr, "\nNo memory !\n");
	  exit (ERROR);
	}
    }
  strbuf[0] = '\0';

  P1.x = P1X_default;
  P1.y = P1Y_default;
  P2.x = P2X_default;
  P2.y = P2Y_default;
  Diag_P1_P2 = HYPOT (P2.x - P1.x, P2.y - P1.y);
  CurrentLinePatLen = 0.04 * Diag_P1_P2;
  pat_pos = 0.0;
  scale_flag = FALSE;
  S1 = P1;
  S2 = P2;
  Q.x = Q.y = 1.0;
  HP_pos.x = HP_pos.y = 0.0;
  neg_ticklen = 0.005;		/* 0.5 %        */
  pos_ticklen = 0.005;
  symbol_char = '\0';

  init_text_par ();
}



static void
init_HPGL (const GEN_PAR * pg, const IN_PAR * pi)
{
/**
 ** Re-init. global var's for multiple-file applications
 **/

  td = pg->td;
  silent_mode = (short)pg->quiet;
  xmin = pi->x0;
  ymin = pi->y0;
  xmax = pi->x1;
  ymax = pi->y1;
  fixedcolor = (short)pi->hwcolor;
  fixedwidth = (short)pi->hwsize;

/*  pens_in_use = 0; */

  /**
   ** Record ON if no page selected (pg->page == 0)!
   **/
  first_page = (short)pi->first_page;	/* May be 0     */
  last_page = pi->last_page;	/* May be 0     */
  page_number = 1;
  record_off =(short)( (first_page > page_number)
    || ((last_page < page_number) && (last_page > 0)));

  rot_ang = pi->rotation;
  rotate_flag =(short)( (rot_ang != 0.0) ? TRUE : FALSE);
  if (rotate_flag)
    {
      rot_cos = cos (M_PI * rot_ang / 180.0);
      rot_sin = sin (M_PI * rot_ang / 180.0);
    }

  vec_cntr_r = 0L;
  vec_cntr_w = 0L;

  reset_HPGL ();
}



static void
User_to_Plotter_coord (const HPGL_Pt * p_usr, HPGL_Pt * p_plot)
/**
 ** 	Utility: Transformation from (scaled) user coordinates
 **	to plotter coordinates
 **/
{
  p_plot->x = P1.x + (p_usr->x - S1.x) * Q.x;
  p_plot->y = P1.y + (p_usr->y - S1.y) * Q.y;
}



static void
Plotter_to_User_coord (const HPGL_Pt * p_plot, HPGL_Pt * p_usr)
/**
 ** 	Utility: Transformation from plotter coordinates
 **	to (scaled) user coordinates
 **/
{
  p_usr->x = S1.x + (p_plot->x - P1.x) / Q.x;
  p_usr->y = S1.y + (p_plot->y - P1.y) / Q.y;
}



static void
PlotCmd_to_tmpfile (PlotCmd cmd) {
 if (record_off) return;	/* Wrong page!  */
 if (!silent_mode) switch (vec_cntr_w++) {
  case 0:	Eprintf ("Writing Cmd: ");	break;
  case 1:	Eprintf ("1 ");		break;
  case 2:	Eprintf ("2 ");		break;
  case 5:	Eprintf ("5 ");		break;
  case 10:	Eprintf ("10 ");	break;
  case 20:	Eprintf ("20 ");	break;
  case 50:	Eprintf ("50 ");	break;
  case 100:	Eprintf ("100 ");	break;
  case 200:	Eprintf ("200 ");	break;
  case 500:	Eprintf ("500 ");	break;
  case 1000:	Eprintf ("1k ");	break;
  case 2000:	Eprintf ("2k ");	break;
  case 5000:	Eprintf ("5k ");	break;
  case 10000:	Eprintf ("10k ");	break;
  case 20000:	Eprintf ("20k ");	break;
  case 50000L:	Eprintf ("50k ");	break;
  case 100000L:	Eprintf ("100k ");	break;
  case 200000L:	Eprintf ("200k ");	break;
  case 500000L:	Eprintf ("500k ");	break;
  case 1000000L:Eprintf ("1M ");	break;
  case 2000000L:Eprintf ("2M ");	break;
 }

 if (fputc ((int) cmd, td) == EOF) {
  PError ("PlotCmd_to_tmpfile");
  Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
  exit (ERROR);
 }
}


static void Pen_Width_to_tmpfile (int pen,int width) {
  PEN_N tp;
  PEN_W tw;

  tp=(unsigned short)pen;
  tw=(unsigned short)width;

  if (record_off)		/* Wrong page!  */
    return;

  if (fwrite(&tp, sizeof(tp), 1, td) != 1) {
      PError ("Pen_Width_to_tmpfile - pen");
      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
      exit (ERROR);
  }
  if (fwrite(&tw, sizeof(tw), 1, td) != 1) {
      PError ("Pen_Width_to_tmpfile - width");
      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
      exit (ERROR);
  }
}

static void Pen_Color_to_tmpfile (int pen,int red,int green, int blue) {
  PEN_N tp;
  PEN_C r,g,b;

  tp=(unsigned short)pen;
  r=(unsigned short)red;
  g=(unsigned short)green;
  b=(unsigned short)blue;

  if (record_off)		/* Wrong page!  */
    return;

  if (fwrite(&tp, sizeof(tp), 1, td) != 1) {
      PError ("Pen_Color_to_tmpfile - pen");
      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
      exit (ERROR);
  }
  if (fwrite(&r, sizeof(r), 1, td) != 1) {
      PError ("Pen_Color_to_tmpfile - red component");
      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
      exit (ERROR);
  }
  if (fwrite(&g, sizeof(g), 1, td) != 1) {
      PError ("Pen_Color_to_tmpfile - green component");
      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
      exit (ERROR);
  }
  if (fwrite(&b, sizeof(b), 1, td) != 1) {
      PError ("Pen_Color_to_tmpfile - blue component");
      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
      exit (ERROR);
  }
}

static void
HPGL_Pt_to_tmpfile (const HPGL_Pt * pf)
{
  if (record_off)		/* Wrong page!  */
    return;

  if (fwrite ((VOID *) pf, sizeof (*pf), 1, td) != 1)
    {
      PError ("HPGL_Pt_to_tmpfile");
      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
      exit (ERROR);
    }
  xmin = MIN (pf->x, xmin);
  ymin = MIN (pf->y, ymin);
  xmax = MAX (pf->x, xmax);
  ymax = MAX (pf->y, ymax);
}




/**
 **	Low-level vector generation & file I/O
 **/

static void
LPattern_Generator (HPGL_Pt * pa,
		    double dx, double dy,
		    double start_of_pat, double end_of_pat)
/**
 **	Generator of Line type patterns:
 **
 **	pa:		Start point (ptr) of current line segment
 **	dx, dy:		Components of c * (*pb - *pa), c holding
 **				dx^2 + dy^2 = pattern_length^2
 **	start_of_pat:	Fraction of start point within pattern
 **	end_of_pat:	Fraction of end   point within pattern
 **			Valid: 0 <= start_of_pat <= end_of_pat <= 1
 **
 **	A pattern consists of alternating "line"/"point" and "gap" elements,
 **	always starting with a line/point. A point is a line of zero length.
 **	The table below contains the relative lengths of the elements
 **	of all line types except LT0; and LT; (7), which are treated separately.
 **	These lengths always add up to 1. A negative value terminates a pattern.
 **/
{
  double length_of_ele, start_of_action, end_of_action;
  static double *p_cur_pat;

  p_cur_pat = lt[(LT_MIN*-1) + (int) CurrentLinePattern]; /* was CurrentLineType */

  if (CurrentLineType == LT_adaptive)
    for (;;)
      {
	length_of_ele = (double) *p_cur_pat++ / 100;	/* Line or point        */
	if (length_of_ele < 0)
	  return;
	if (length_of_ele == 0.0)
	  PlotCmd_to_tmpfile (PLOT_AT);
	else
	  PlotCmd_to_tmpfile (DRAW_TO);

	pa->x += dx * length_of_ele;
	pa->y += dy * length_of_ele;
	HPGL_Pt_to_tmpfile (pa);

	length_of_ele = (double) *p_cur_pat++ / 100;	/* Gap        */
	if (length_of_ele < 0)
	  return;
	pa->x += dx * length_of_ele;
	pa->y += dy * length_of_ele;
	PlotCmd_to_tmpfile (MOVE_TO);
	HPGL_Pt_to_tmpfile (pa);
      }
  else                                 /* LT_fixed */
    for (end_of_action = 0.0;;)
      {
	    /**
	     ** Line or point:
	     **/
	start_of_action = end_of_action;
	length_of_ele = (double) *p_cur_pat++ / 100;
	if (length_of_ele < 0)
	  return;
	end_of_action += length_of_ele;
	if (end_of_action > start_of_pat)	/* If anything to do:   */
	  {
	    if (start_of_pat <= start_of_action)
	      {			/* If start is valid    */
		if (end_of_action <= end_of_pat)
		  {		/* Draw full element    */
		    pa->x += dx * length_of_ele;
		    pa->y += dy * length_of_ele;
		    if (length_of_ele == 0.0)
		      PlotCmd_to_tmpfile (PLOT_AT);
		    else
		      PlotCmd_to_tmpfile (DRAW_TO);
		    HPGL_Pt_to_tmpfile (pa);
		  }
		else
		  /* End_of_action beyond End_of_pattern:   */
		  {		/* --> Draw only first part of element: */
		    pa->x += dx * (end_of_pat - start_of_action);
		    pa->y += dy * (end_of_pat - start_of_action);
		    if (length_of_ele == 0.0)
		      PlotCmd_to_tmpfile (MOVE_TO);
		    else
		      PlotCmd_to_tmpfile (DRAW_TO);
		    HPGL_Pt_to_tmpfile (pa);
		    return;
		  }
	      }
	    else
	      /* Start_of_action before Start_of_pattern:       */
	      {
		if (end_of_action <= end_of_pat)
		  {		/* Draw remainder of element            */
		    if (length_of_ele == 0.0)
		      PlotCmd_to_tmpfile (PLOT_AT);
		    else
		      PlotCmd_to_tmpfile (DRAW_TO);
		    pa->x += dx * (end_of_action - start_of_pat);
		    pa->y += dy * (end_of_action - start_of_pat);
		    HPGL_Pt_to_tmpfile (pa);
		  }
		else
		  /* End_of_action beyond End_of_pattern:   */
		  /* Draw central part of element & leave   */
		  {
		    if (end_of_pat == start_of_pat)
		      PlotCmd_to_tmpfile (PLOT_AT);
		    else
		      PlotCmd_to_tmpfile (DRAW_TO);
		    pa->x += dx * (end_of_pat - start_of_pat);
		    pa->y += dy * (end_of_pat - start_of_pat);
		    HPGL_Pt_to_tmpfile (pa);
		    return;
		  }
	      }
	  }

	    /**
	     ** Gap (analogous to line/point):
	     **/
	start_of_action = end_of_action;
	length_of_ele = (double) *p_cur_pat++ / 100;
	if (length_of_ele < 0)
	  return;
	end_of_action += length_of_ele;
	if (end_of_action > start_of_pat)	/* If anything to do:   */
	  {
	    if (start_of_pat <= start_of_action)
	      {			/* If start is valid    */
		if (end_of_action <= end_of_pat)
		  {		/* Full gap             */
		    pa->x += dx * length_of_ele;
		    pa->y += dy * length_of_ele;
		    PlotCmd_to_tmpfile (MOVE_TO);
		    HPGL_Pt_to_tmpfile (pa);
		  }
		else
		  /* End_of_action beyond End_of_pattern:   */
		  {		/* --> Apply only first part of gap:    */
		    pa->x += dx * (end_of_pat - start_of_action);
		    pa->y += dy * (end_of_pat - start_of_action);
		    PlotCmd_to_tmpfile (MOVE_TO);
		    HPGL_Pt_to_tmpfile (pa);
		    return;
		  }
	      }
	    else
	      /* Start_of_action before Start_of_pattern:       */
	      {
		if (end_of_action <= end_of_pat)
		  {		/* Apply remainder of gap               */
		    pa->x += dx * (end_of_action - start_of_pat);
		    pa->y += dy * (end_of_action - start_of_pat);
		    PlotCmd_to_tmpfile (MOVE_TO);
		    HPGL_Pt_to_tmpfile (pa);
		  }
		else
		  /* End_of_action beyond End_of_pattern:   */
		  /* Apply central part of gap & leave      */
		  {
		    if (end_of_pat == start_of_pat)
		      return;	/* A null move  */
		    pa->x += dx * (end_of_pat - start_of_pat);
		    pa->y += dy * (end_of_pat - start_of_pat);
		    PlotCmd_to_tmpfile (MOVE_TO);
		    HPGL_Pt_to_tmpfile (pa);
		    return;
		  }
	      }
	  }
      }
}
/*
   struct PE_flags{
   int abs;
   int up;
   int sbmode;
   int fract;
   int pen;
   } ;
 */
int
read_PE_flags (const GEN_PAR * pg, int c, FILE * hd, PE_flags * fl)
{
  short old_pen;
  float ftmp;
  int ctmp;
  switch (c)
    {
    case 183:
    case '7':
      /* seven bit mode */
      fl->sbmode = 1;
      break;

    case 186:
    case ':':
      /* select pen */
      if (EOF == (fl->pen = getc (hd)))
	{
	  par_err_exit (98, PE);
	}
      old_pen = pen;
      read_PE_coord (fl->pen, hd, fl, &ftmp);
      pen = ftmp;
      if (pen < 0 || pen > pg->maxpens)
	{
	  Eprintf (
		    "\nIllegal pen number %d: replaced by %d\n", pen, pen % pg->maxpens);
	  n_unexpected++;
	  pen%=(short)pg->maxpens;
	}
      if (old_pen != pen)
	{
	  if ((fputc (SET_PEN, td) == EOF) ||
	      (fputc (pen, td) == EOF))
	    {
	      PError ("Writing to temporary file:");
	      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
	      exit (ERROR);
	    }
	}
      if (pen)
	pens_in_use[pen] = 1;
      /*         pens_in_use |= (1 << (pen-1)); */
/*MK */
      break;

    case 190:
    case '>':
      /* fractional data */

      if (EOF == (ctmp = getc (hd)))
	{
	  par_err_exit (98, PE);
	}
      fl->fract = decode_PE_char (ctmp, fl);
      fl->fract = ((fl->fract >> 1) * ((fl->fract & 0x01) ? -1 : 1));
/*      fprintf(stderr,"PE > flag, fract =%d (%d decimals) ",fl->fract, fl->fract/3); */
      break;

    case 188:
    case '<':
      /* pen up */
      fl->up = 1;
      break;

    case 189:
    case '=':
      /* abs plotting */

      fl->abs = 1;
      break;

    default:
      return (0);
    }
  return (1);
}

int 
isPEterm (int c, PE_flags * fl)
{
  if ((fl->sbmode) && ((c > 94) || (c < 63)))
    return 1;
  if ((!fl->sbmode) && ((c > 190) || (c < 63)))
    return 1;
  return (0);
}


int 
decode_PE_char (int c, PE_flags * fl)
{
  if (fl->sbmode)
    {
      c &= 0x7f;
      return ((c > 94) ? (c - 95) : (c - 63));
    }
  else
    {
      return ((c > 190) ? (c - 191) : (c - 63));
    }
}

int 
read_PE_coord (int c, FILE * hd, PE_flags * fl, float *fv)
{
  long lv = 0;
  int i = 0;
  int shft = (fl->sbmode) ? 5 : 6;

  for (;;)
    {
      if (c < 63) {
       if (!i) {     /* avoid endless getc/ungetc loop with broken files */
        Eprintf("error in PE data!\n");
        return 0;
       }
	  ungetc (c, hd);
	  break;
	}
      lv |= ((long) decode_PE_char (c, fl)) << (i * shft);
      i++;
      if (isPEterm (c, fl))
	{
	  break;
	}
      if (EOF == (c = getc (hd)))
	{
	  par_err_exit (98, PE);
	}
    }
  *fv = (float) (((lv >> 1) * ((lv & 0x01) ? -1 : 1)) << fl->fract);
  return (1);
}


int 
read_PE_pair (int c, FILE * hd, PE_flags * fl, HPGL_Pt * p)
{
  if (!read_PE_coord (c, hd, fl, &(p->x))) return 0;
  if (EOF == (c = getc (hd)))
    {
      par_err_exit (98, PE);
    }
  if (!read_PE_coord (c, hd, fl, &(p->y))) return 0;
  return (1);
}




void 
read_PE (const GEN_PAR * pg, FILE * hd)
{
  int c;

  HPGL_Pt p;
  PE_flags fl;

  fl.fract = 0;
  fl.sbmode = 0;
  fl.abs = 0;
  fl.up = 0;
  fl.pen = 0;

  for (c = getc (hd); (c != EOF) && (c != ';'); c = getc (hd))
    {
      if (!read_PE_flags (pg, c, hd, &fl))
	{
	  if (!read_PE_pair (c, hd, &fl, &p)) continue;
	  pen_down =(short)( (fl.up) ? FALSE : TRUE);
	  line(!fl.abs, p);
	  tp->CR_point = HP_pos;
	  fl.abs = 0;
	  fl.up = 0;
	}
    }
}


static void
Line_Generator (HPGL_Pt * pa, const HPGL_Pt * pb, int mv_flag)
{
  double seg_len, dx, dy, quot;
  int n_pat, i;

  dx = pb->x - pa->x;
  dy = pb->y - pa->y;
  seg_len = HYPOT (dx, dy);

  switch (CurrentLineType) {

    case LT_solid:
      PlotCmd_to_tmpfile (DRAW_TO);
      HPGL_Pt_to_tmpfile (pb);
      return;

    case LT_adaptive:
      if (seg_len == 0.0) {
        if (!silent_mode)
           Eprintf ("Warning: Zero line segment length -- skipped\n");
        return;			/* No line to draw ??           */
      }
      pat_pos = 0.0;		/* Reset to start-of-pattern    */
      n_pat = ceil (seg_len / CurrentLinePatLen);
      dx /= n_pat;
      dy /= n_pat;
      /* Now draw n_pat complete line patterns */
      for (i = 0; i < n_pat; i++)
         LPattern_Generator (pa, dx, dy, 0.0, 1.0);
      return;

    case LT_plot_at:
      PlotCmd_to_tmpfile (PLOT_AT);
      HPGL_Pt_to_tmpfile (pb);
      return;

    case LT_fixed:
      if (seg_len == 0.0) {
        if (!silent_mode)
           Eprintf ("Warning: Zero line segment length -- skipped\n");
        return;			/* No line to draw ??           */
      }

      if (mv_flag)		/* Last move ends old line pattern      */
	pat_pos = 0.0;
      quot = seg_len / CurrentLinePatLen;
      dx /= quot;
      dy /= quot;
      while (quot >= 1.0) {
	  LPattern_Generator (pa, dx, dy, pat_pos, 1.0);
	  quot -= (1.0 - pat_pos);
	  pat_pos = 0.0;
      }
      quot += pat_pos;
      if (quot >= 1.0) {
	  LPattern_Generator (pa, dx, dy, pat_pos, 1.0);
	  quot -= 1.0;
	  pat_pos = 0.0;
      }
      LPattern_Generator (pa, dx, dy, pat_pos, quot);
      pat_pos = quot;
      return;

    default:
      break;
    }

}




void
Pen_action_to_tmpfile (PlotCmd cmd, const HPGL_Pt * p, int scaled)
{
  static HPGL_Pt P_last;
  HPGL_Pt P;
  double tmp;

  if (record_off)		/* Wrong page!  */
    return;

  if (scaled)			/* Rescaling    */
    User_to_Plotter_coord (p, &P);
  else
    P = *p;			/* Local copy   */


  HP_pos = P;			/* Actual plotter pos. in plotter coord */

  if (rotate_flag)		/* hp2xx-specific global rotation       */
    {
      tmp = rot_cos * P.x - rot_sin * P.y;
      P.y = rot_sin * P.x + rot_cos * P.y;
      P.x = tmp;
    }


  /* Extreme values needed for later scaling:    */

  switch (cmd)
    {
    case MOVE_TO:
      mv_flag = TRUE;
      break;

  /**
   ** Multiple-move suppression. In addition,
   ** a move only precedes a draw -- nothing else!
   **/

    case DRAW_TO:
      if (mv_flag)
	{
	  PlotCmd_to_tmpfile (MOVE_TO);
	  HPGL_Pt_to_tmpfile (&P_last);
	}
      /* drop through */
    case PLOT_AT:
      Line_Generator (&P_last, &P, mv_flag);
      mv_flag = FALSE;
      break;

    default:
      Eprintf ("Illegal Pen Action: %d\n", cmd);
      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
      exit (ERROR);
    }
  P_last = P;
}





int
read_float (float *pnum, FILE * hd)
/**
 ** Main work-horse for parameter input:
 **
 ** Search for next number, skipping white space but return if mnemonic met.
 ** If found, read in number
 **	returns	0 if valid number
 **		1 if command ended
 **		2 if scanf failed (possibly corrupted file)
 **	      EOF if EOF met
 **/
{
  int c;
  char *ptr, numbuf[80];

  for (c = getc (hd); (c != '.') && (c != '+') && (c != '-') && ((c < '0') || (c > '9')); c = getc (hd))
    {
      if (c == EOF)		/* Wait for number      */
	return EOF;		/* Should not happen    */
      if (c == ';')
	return 1;		/* Terminator reached   */
      if (((c >= 'A') && (c <= 'Z')) ||
	  ((c >= 'a') && (c <= 'a')) || (c == ESC))
	{
	  ungetc (c, hd);
	  return 1;		/* Next Mnemonic reached */
	}
    }
  /* Number found: Get it */
  ptr = numbuf;
  for (*ptr++ =(char) c, c = getc (hd); ((c >= '0') && (c <= '9')) || (c == '.'); c = getc (hd))
    *ptr++ =(char) c;			/* Read number          */
  *ptr = '\0';
  if (c != EOF)
    ungetc (c, hd);

  if (sscanf (numbuf, "%f", pnum) != 1)
    return 11;			/* Should never happen  */
  return 0;
}




static void
read_string (char *buf, FILE * hd)
{
  int c, n;

  for (n = 0, c = getc (hd); (c != EOF) && (c != StrTerm); c = getc (hd))
    {
      if (n >(int)(strbufsize / 2))
	{
	  strbufsize *= 2;
	  strbuf = realloc (strbuf, strbufsize);
	  if (strbuf == NULL)
	    {
	      fprintf (stderr, "\nNo memory !\n");
	      exit (ERROR);
	    }
	  buf = strbuf + n;
	}
      if ((unsigned)n++ < strbufsize)
	*buf++ = (char)c;
    }
  if (c == StrTerm && c != ETX)
    *buf++ = (char)c;
  *buf = '\0';
}




static void
read_symbol_char (FILE * hd)
{
  int c;

  for (c = getc (hd); /* ended by switch{} */ ; c = getc (hd))
    switch (c)
      {
      case ' ':
      case _HT:
      case _LF:
	break;			/* Skip white space             */
      case _CR:
      case EOF:
      case ';':		/* CR or "term" end symbol mode */
	symbol_char = '\0';
	return;
      default:
	if (c < ' ' || c > '~')
	  break;		/* Ignore unprintable chars     */
	else
	  {
	    symbol_char = (char)c;
	    return;
	  }
      }
}




static void
read_ESC_HP7550A (FILE * hd)
/*
 * Read & skip HP 7550A control commands (ESC.-Commands)
 */
{
  int c;

  switch (getc (hd))
    {
    case EOF:
      n_unexpected++;
      Eprintf ("\nUnexpected EOF!\n");
      return;
    case 'A':
    case 'B':
    case 'E':
    case 'J':
    case 'K':
    case 'L':
    case 'O':
    case 'U':
    case 'Y':
    case '(':
    case ')':
      return;			/* Commands without parameters  */
    case '@':
    case 'H':
    case 'I':
    case 'M':
    case 'N':
    case 'P':
    case 'Q':
    case 'S':
    case 'T':
      do
	{			/* Search for terminator ':'    */
	  c = getc (hd);
	}
      while ((c != ':') && (c != EOF));
      if (c == EOF)
	{
	  n_unexpected++;
	  Eprintf ("\nUnexpected EOF!\n");
	}
      return;
    default:
      n_unknown++;
      return;
    }
}


static int
read_PJL(FILE *hd)
/*
 * a simple PJL parser
 * just reads PJL header and
 * return
 *   TRUE if PJL enters HPGL context,
 *   FALSE  if not
 *  *
 * PJL lines are like this:
 * @PJL[ command][ args][\r]\n
 * (however I've seen some wrong PJL files with \n\r )
 * @PJL must be uppercase, ther rest of string is not
 * case sensitive
 * The last line of a PJL header is like these:
 * @PJL ENTER LANGUAGE = HPGL2
 * @PJL EOJ [NAME = "something"]
 */
{
#define PJLBS 80

  char strbuf[PJLBS];
  int i,ov,ctmp,qt,el=0,nw=0,rc=-2,nl=0;
  for (;;) {
    /* read word*/
    for( i=ov=qt=0;;i++) {
      ctmp=getc(hd);
      if (PJLBS-1==i) {
       if (!silent_mode) Eprintf("PJL buffer overflow, rest of token dropped\n");
       ov=1;
       strbuf[i]='\0';
      }
      if (!ov) strbuf[i]=(0==nw || qt)?(char)ctmp:(char)toupper(ctmp);
      if (EOF==ctmp) {
       if (!ov) strbuf[i]=0;
       break;
      } else if ('='==ctmp && 0==i) {
       strbuf[i]='=';
       strbuf[++i]='\0';
       ctmp=' ';
       break;
      } else if (strchr(" \t=",ctmp)) {
       if (!qt) {
         if (!ov) strbuf[i]=0;
         break;
       }
      } else if ('\n'==ctmp || '\r'==ctmp) {
       if (!ov) strbuf[i]=0;
       nl=1;
       break;
      } else if ('"'==ctmp) { 
       qt=!qt;
      }
    }
    /* handle word */
    if (i)   {
#ifdef DEBUG_ESC
      Eprintf("word %d: read %d bytes: '%s'\n",nw,i,strbuf);
#endif
      if (0==nw && strcmp(strbuf,"@PJL")) {
       Eprintf("unexpected end of a PJL header!\n");
       return(TRUE);
      } else if (1==nw && !strcmp(strbuf,"EOJ")) {
       if (!silent_mode) Eprintf("end of a PJL job\n");
       rc=TRUE;
      } else if (1==nw && !strcmp(strbuf,"ENTER")) {
       el++;
      } else if (2==nw && 1==el && !strcmp(strbuf,"LANGUAGE")) {
       el++;
      } else if (3==nw && 2==el && !strcmp(strbuf,"=")) {
       el++;
      } else if (4==nw && 3==el ) {
         if (!silent_mode) Eprintf("Entering %s context\n",strbuf);
         rc=strncmp(strbuf,"HPGL",4)?FALSE:TRUE;
      }
      nw++;
    }
    /* read separator */
    for(;EOF!=ctmp;) {
      if (!strchr(" \t\n\r",ctmp)) {
       ungetc(ctmp,hd);
       break;
      }
      ctmp=getc(hd);
      if ('\n'==ctmp) {
       nl=1;
      }
    }
#ifdef DEBUG_ESC
    if (j)   Eprintf("separator: read %d bytes\n",j);
#endif

   if (nl) {
      nw=el=nl=0;
      if (-2!=rc) return rc;
    }
    if (EOF==ctmp) {
      if (!silent_mode) Eprintf ("EOF in PJL context\n");
      return(FALSE);
    }
  }
}

static void
read_ESC_RTL(FILE *hd,int c1,int hp)
/*
 *read and skip ESC% control commands
 */
{
    /*
     * known escapes:
     * ESC%-12345X    UEL (Universal Escape Language)
     *                followed by @PJL..
     *
     * ESC%-1B        Enter HPGL/2 context
     * ESC%0B         -
     * ESC%1B         -
     *
     * ESC%1A         Exit HPGL/2 context
     * ESC%0A         -
     * ESC%-1A        -

     * how a PCL escape looks like:
     * ESC, lowercase letters and digits, an Upper case letter

     */
    int c0,c2,ctmp=0,nf;

    for(c0=ESC,c2=getc(hd),nf=0;
       EOF!=c2;
       c0=c1,c1=c2,c2=getc(hd)) {

      if ((ESC==c0)&&(c1=='%')) {
       if ('-'==c2) {
         c2=getc(hd);
         nf=1;
       }
       switch(c2) {
       case EOF:
         n_unexpected++;
         Eprintf ("\nUnexpected EOF!\n");
         return;
       case '1':
       case '0':
               switch(ctmp=getc(hd)) {
               case 'A':

                 if (hp && !silent_mode) {
#ifdef ESC_DEBUG
                   Eprintf("leaving HPGL context\n");
#endif
                   hp=FALSE;
                 }
                 continue;
               case 'B':
#ifdef ESC_DEBUG
                 if (!silent_mode && !hp) Eprintf("entering HPGL context\n");
#endif
                 return;
               case '2':
                 /* check for UEL */
                   if (nf && '1'==c2 &&
                       '3'==(c2=getc(hd)) &&
                       '4'==(c2=getc(hd)) &&
                       '5'==(c2=getc(hd)) &&
                       'X'==(c2=getc(hd))) {
#ifdef ESC_DEBUG
                     if (!silent_mode) Eprintf("UEL found\n");
#endif
                     if (read_PJL(hd)) {
                       return;
                     } else {
                       hp=0;
                       continue;
                     }
                   } else {
                     ungetc(ctmp,hd);
                     if (hp) return;
                   }
                   break;
               default:
                   Eprintf("unknown escape: ESC%%%s%c%c\n",nf?"-":"",c2,ctmp);
                   ungetc(ctmp,hd);
                   if (hp) return;
               }
               break;
       default:
         Eprintf("unknown escape: ESC%%%s%c",nf?"-":"",c2);
               ungetc(ctmp,hd);
               if (hp)   return;
               break;
       }
      }
    }
}

static void
read_ESC_cmd (FILE *hd,int hp)
/*
 * Read & skip device control commands (ESC.-Commands)

 */
{
    int ctmp;
    switch (ctmp=getc(hd)) {
    case '.':
       read_ESC_HP7550A(hd);
       break;
    case EOF:
       n_unexpected++;
       Eprintf ("\nUnexpected EOF!\n");
       return;
    default:
       read_ESC_RTL(hd,ctmp,hp);
       break;
    }
}



/****************************************************************************/



/**
 **	lines:	Process PA-, PR-, PU-, and  PD- commands
 **/
static void
lines (int relative, FILE * hd)
/**
 ** Examples of anticipated commands:
 **
 **	PA PD0,0,80,50,90,20PU140,30PD150,80;
 **	PU0,0;PD20.53,40.32,30.08,60.2,40,90,;PU100,300;PD120,340...
 **/
{
  HPGL_Pt p;
  int numcmds=0;

  for (;;)
    {
       if (read_float (&p.x, hd)){     /* No number found      */
          if (numcmds >0 ) return;
               if(pen_down){  /*simulate dot created by 'real' pen on PD;PU;*/
                     Pen_action_to_tmpfile   (MOVE_TO, &p_last, scale_flag);
                     Pen_action_to_tmpfile   (DRAW_TO, &p_last, scale_flag);
			}
                return ;
                }                                                                             

      if (read_float (&p.y, hd))	/* x without y invalid! */
	par_err_exit (2, PA);
      line(relative,p);
      numcmds++;
    }      
}


/*
 * line : process a pair of coordinates
 */
void line (int relative, HPGL_Pt p)
 {
  HPGL_Pt pl, porig;
  int outside = 0;
  double x1, y1, x2, y2;

      if (relative)	
	{
	  p.x += p_last.x;
	  p.y += p_last.y;
	}

      porig.x = p.x;
      porig.y = p.y;

      if (iwflag)
	{
	  x1 = P1.x + (p_last.x - S1.x) * Q.x;
	  y1 = P1.y + (p_last.y - S1.y) * Q.y;
	  x2 = P1.x + (p.x - S1.x) * Q.x;
	  y2 = P1.y + (p.y - S1.y) * Q.y;
	  outside = (DtClipLine(C1.x, C1.y, C2.x, C2.y, &x1, &y1, &x2, &y2) == CLIP_NODRAW) ;

	  if (!outside)
	    {
	      p.x = (x2 - P1.x) / Q.x + S1.x;
	      p.y = (y2 - P1.y) / Q.y + S1.y;
	      pl.x = (x1 - P1.x) / Q.x + S1.x;
	      pl.y = (y1 - P1.y) / Q.y + S1.y;
	      if (pl.x != p_last.x || pl.y != p_last.y)
		Pen_action_to_tmpfile (MOVE_TO, &pl, scale_flag);

	    }

	}
      if (polygon_mode && polygon_penup)
	pen_down = FALSE;

      if (pen_down && !outside) {
	  if (polygon_mode) {
	      polygons[++vertices] = p_last;
	      polygons[++vertices] = p;
/*	      fprintf(stderr,"polygon line1: %f %f - %f %f\n",p_last.x,p_last.y,p.x,p.y);*/
	  } else {
	      Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);
/*	      fprintf(stderr,"std line1: %f %f - %f %f\n",p_last.x,p_last.y,p.x,p.y); */
          }
      } else {
      if (iwflag) {
	Pen_action_to_tmpfile (MOVE_TO, &porig, scale_flag);
       } else {
	Pen_action_to_tmpfile (MOVE_TO, &p, scale_flag);
        }
      }

      if (polygon_mode && !polygon_penup)
	{
	  polygons[++vertices] = p_last;
	  polygons[++vertices] = p;
	}
      if (polygon_mode && polygon_penup)
	{
	  polygon_penup = FALSE;
	  pen_down = TRUE;
	}


      if (symbol_char)
	{
	  plot_symbol_char (symbol_char);
	  Pen_action_to_tmpfile (MOVE_TO, &p, scale_flag);
	}
      p_last = porig;
    
}


/**
 **	Arcs, circles and alike
 **/


static void
arc_increment (HPGL_Pt * pcenter, double r, double phi)
{
  HPGL_Pt p;
  int outside = 0;

  p.x = pcenter->x + r * cos (phi);
  p.y = pcenter->y + r * sin (phi);

  if (iwflag)
    {
      if (P1.x + (p.x - S1.x) * Q.x > C2.x || P1.y + (p.y - S1.y) * Q.y > C2.y)
	{
/*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
	  outside = 1;
	}
      if (P1.x + (p.x - S1.x) * Q.x < C1.x || P1.y + (p.y - S1.y) * Q.y < C1.y)
	{
/*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
	  outside = 1;
	}
    }

if (polygon_mode) {
	if (polygon_penup) polygon_penup=FALSE;
	else   if (pen_down && !outside){
  		polygons[++vertices]=p_last;
  		polygons[++vertices]=p;
/*fprintf(stderr,"arcpoint %f %f\n",p.x,p.y);*/

  		}
  else if ((p.x != p_last.x) || (p.y != p_last.y)){
	/*polygon_penup=TRUE;*/
  		polygons[++vertices]=p_last;
        polygons[++vertices]=p;
/*fprintf(stderr,"final arcpoint %f %f\n",p.x,p.y);*/
        }
  }else{
  if (pen_down && !outside)
    Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);
  else if ((p.x != p_last.x) || (p.y != p_last.y))
    Pen_action_to_tmpfile (MOVE_TO, &p, scale_flag);
  }
  p_last = p;
}

static void
tarcs (int relative, FILE * hd)
{
  HPGL_Pt p, p2, p3, center, d;
  float alpha, eps;
  double phi, phi0, r;
  double SafeLinePatLen = CurrentLinePatLen;

  if (read_float (&p2.x, hd))	/* No number found      */
    return;

  if (read_float (&p2.y, hd))	/* x without y invalid! */
    par_err_exit (2, AT);

  if (read_float (&p3.x, hd))	/* No endpoint */
    par_err_exit (3, AT);
 
  if (read_float (&p3.y, hd))	/* No endpoint */
    par_err_exit (3, AT);
    
  switch (read_float (&eps, hd)) /* chord angle is optional */
    {
    case 0:
      break;
    case 1:			/* No resolution option */
      eps = 5.0;		/*    so use default!   */
      break;
    case 2:			/* Illegal state        */
      par_err_exit (98, AT);
    case EOF:
      return;
    default:			/* Illegal state        */
      par_err_exit (99, AT);
    }
  eps *= M_PI / 180.0;		/* Deg-to-Rad           */

d = p_last;

  if (!relative)			/* Transform coordinates  */
    {                                   
      p2.x = p2.x - p_last.x;
      p2.y = p2.y - p_last.y;
      p3.x = p3.x - p_last.x;
      p3.y = p3.y - p_last.y;
    }

/*    
    2*p2.x*h+2*p2.y*k = p2.x^2 + p2.y^2
    
    k= (p2.x^2 + p2.y^2 - 2*p2.x*h) /2*p2.y
     
    2*p3.x*h+2*p3.y*k = p3.x^2 + p3.y^2 
   

2* p3.x*h +2*p3.y * (p2.x^2 + p2.y^2 -2*p2.x*h) / 2*p2.y = (p3.x^2 + p3.y^2)   
2* p3.x*h +2*p3.y * (p2.x^2 + p2.y^2 -2*p2.x*h)  = (p3.x^2 + p3.y^2) *2*p2.y  

2*p3.x*h + 2*p3.y*p2.x^2 + 2*p3.y*p2.y^2 - 4*p2.x*p3.y*h =...
(2*p3.x-4*p2.y*p3.y)*h  + 2*p3.y*p2.x^2 + 2*p3.y*p2.y^2 = ...
h = ( 2*p2.y*(p2.x^2 + p2.y^2) -2*p3.y*p2.x^2 - 2*p3.y*p2.y^2 )  / 2*p3.x-4*p2.x*p3.y
*/
center.x = (2.*p2.y*(p3.x*p3.x+p3.y*p3.y) - 2.*p3.y*p2.x*p2.x 
            - 2.*p3.y*p2.y*p2.y )/ (2.*p3.x-4.*p2.x*p3.y) ;
center.y = ( p2.x*p2.x + p2.y*p2.y - 2.*p2.x* center.x) / (2.*p2.y);

r= sqrt(center.x*center.x + center.y*center.y); 
    
   center.x = center.x + p_last.x;
   center.y = center.y + p_last.y;


	d.x=p_last.x - center.x;
	d.y=p_last.y - center.y;

  phi0 = atan2 (d.y, d.x);

	d.x=p3.x + p_last.x - center.x;
	d.y=p3.y + p_last.y - center.y;

  alpha = 2.* atan2 (d.y, d.x);
/*
fprintf(stderr,"AT: P1 at %f %f , P2 %f %f, P3 %f %f, center %f %f radius %f\n",
p_last.x,p_last.y,p2.x+p_last.x,p2.y+p_last.y,p3.x+p_last.x,p3.y+p_last.y,
center.x,center.y,r);
*/
  if (CurrentLineType == LT_adaptive)	/* Adaptive patterns:   */
    {
      p.x = r * cos (eps);	/* A chord segment      */
      p.y = r * sin (eps);
      if (scale_flag)
	User_to_Plotter_coord (&p, &p);

      /*      Pattern length = chord length           */
      CurrentLinePatLen = HYPOT (p.x, p.y);
    }

  if (alpha > 0.0)
    {
      for (phi = phi0 + MIN (eps, alpha); phi < phi0 + alpha; phi += eps)
	arc_increment (&center, r, phi);
      arc_increment (&center, r, phi0 + alpha);		/* to endpoint */
    }
  else
    {
      for (phi = phi0 - MIN (eps, -alpha); phi > phi0 + alpha; phi -= eps)
	arc_increment (&center, r, phi);
      arc_increment (&center, r, phi0 + alpha);		/* to endpoint */
    }

   CurrentLinePatLen=SafeLinePatLen;	                /* Restore */

   p_last.x=p_last.x+p3.x;
   p_last.y=p_last.y+p3.y;

}
   
static void
arcs (int relative, FILE * hd)
{
  HPGL_Pt p, d, center;
  float alpha, eps;
  double phi, phi0, r;
  double SafeLinePatLen = CurrentLinePatLen;

  if (read_float (&p.x, hd))	/* No number found      */
    return;

  if (read_float (&p.y, hd))	/* x without y invalid! */
    par_err_exit (2, AA);

  if (read_float (&alpha, hd))	/* Invalid without angle */
    par_err_exit (3, AA);
  else
    alpha *= M_PI / 180.0;	/* Deg-to-Rad           */

  switch (read_float (&eps, hd))
    {
    case 0:
      break;
    case 1:			/* No resolution option */
      eps = 5.0;		/*    so use default!   */
      break;
    case 2:			/* Illegal state        */
      par_err_exit (98, AA);
    case EOF:
      return;
    default:			/* Illegal state        */
      par_err_exit (99, AA);
    }
  eps *= M_PI / 180.0;		/* Deg-to-Rad           */


  if (relative)			/* Process coordinates  */
    {
      d = p;			/* Difference vector    */
      center.x = d.x + p_last.x;
      center.y = d.y + p_last.y;
    }
  else
    {
      d.x = p.x - p_last.x;
      d.y = p.y - p_last.y;
      center.x = p.x;
      center.y = p.y;
    }

  if (((r = sqrt (d.x * d.x + d.y * d.y)) == 0.0) || (alpha == 0.0))
    return;			/* Zero radius or zero arc angle given  */

  phi0 = atan2 (-d.y, -d.x);

  if (CurrentLineType == LT_adaptive)	/* Adaptive patterns:   */
    {
      p.x = r * cos (eps);	/* A chord segment      */
      p.y = r * sin (eps);
      if (scale_flag)
	User_to_Plotter_coord (&p, &p);

      /*      Pattern length = chord length           */
      CurrentLinePatLen = HYPOT (p.x, p.y);
    }

  if (alpha > 0.0)
    {
      for (phi = phi0 + MIN (eps, alpha); phi < phi0 + alpha; phi += eps)
	arc_increment (&center, r, phi);
      arc_increment (&center, r, phi0 + alpha);		/* to endpoint */
    }
  else
    {
      for (phi = phi0 - MIN (eps, -alpha); phi > phi0 + alpha; phi -= eps)
	arc_increment (&center, r, phi);
      arc_increment (&center, r, phi0 + alpha);		/* to endpoint */
    }

   CurrentLinePatLen = SafeLinePatLen;	                /* Restore */
}

static void
fwedges (FILE * hd, float cur_pensize)		/*derived from circles */
{
  HPGL_Pt p, center, wpolygon[MAXPOLY];
  float eps, r, start, sweep;
  double phi;
  double SafeLinePatLen = CurrentLinePatLen;
  int outside = 0;
  int i;

  if (read_float (&r, hd))	/* No radius found      */
    return;
  if (read_float (&start, hd))	/* No start angle found */
    return;

  if (read_float (&sweep, hd))	/* No sweep angle found */
    return;

  switch (read_float (&eps, hd))	/* chord angle */
    {
    case 0:
      break;
    case 1:			/* No resolution option */
      eps = 5.0;		/*    so use default!   */
      break;
    case 2:			/* Illegal state        */
      par_err_exit (98, EW);
    case EOF:
      return;
    default:			/* Illegal state        */
      par_err_exit (99, EW);
    }
  eps *= M_PI / 180.0;		/* Deg-to-Rad           */
  start *= M_PI / 180.0;	/* Deg-to-Rad           */
  sweep *= M_PI / 180.0;	/* Deg-to-Rad           */


  center = p_last;		/* reference point is last position */
  wpolygon[0] = p_last;
  if (r == 0.0)			/* Zero radius given    */
    return;

  wpolygon[1].x = center.x + r * cos (start);
  wpolygon[1].y = center.y + r * sin (start);

  if (CurrentLineType == LT_adaptive)	/* Adaptive patterns    */
    {
      p.x = r * cos (eps);	/* A chord segment      */
      p.y = r * sin (eps);
      if (scale_flag)
	User_to_Plotter_coord (&p, &p);

      /*      Pattern length = chord length           */
      CurrentLinePatLen = HYPOT (p.x, p.y);
    }
  i = 1;
  for (phi = eps; phi <= sweep; phi += eps)
    {
      p.x = center.x + r * cos (start + phi);
      p.y = center.y + r * sin (start + phi);
      if (iwflag)
	{
	  if (P1.x + (p.x - S1.x) * Q.x > C2.x || P1.y + (p.y - S1.y) * Q.y > C2.y)
	    {
/*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
	      outside = 1;
	    }
	  if (P1.x + (p.x - S1.x) * Q.x < C1.x || P1.y + (p.y - S1.y) * Q.y < C1.y)
	    {
/*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
	      outside = 1;
	    }
	}
      if (!outside)
	{
	  i++;
	  wpolygon[i] = wpolygon[i - 1];
	  i++;
	  wpolygon[i] = p;
	}
      outside = 0;
    }
  i++;
  wpolygon[i] = p;
  i++;
  wpolygon[i] = center;
  	if (hatchspace==0.) hatchspace=cur_pensize;
	if (filltype<3 && thickness > 0.) hatchspace=thickness; 
  fill (wpolygon, i, P1, P2, scale_flag, filltype, hatchspace, hatchangle);

  CurrentLinePatLen = SafeLinePatLen;	                /* Restore */

}



static void
circles (FILE * hd)
{
  HPGL_Pt p, center ,polyp;
  float eps, r;
  double phi;
  double SafeLinePatLen = CurrentLinePatLen;
  int outside = 0;

  if (read_float (&r, hd))	/* No radius found      */
    return;

  switch (read_float (&eps, hd))
    {
    case 0:
      break;
    case 1:			/* No resolution option */
      eps = 5.0;		/*    so use default!   */
      break;
    case 2:			/* Illegal state        */
      par_err_exit (98, CI);
    case EOF:
      return;
    default:			/* Illegal state        */
      par_err_exit (99, CI);
    }
  eps *= M_PI / 180.0;		/* Deg-to-Rad           */


  center = p_last;

  if (r == 0.0)			/* Zero radius given    */
    return;

  p.x = center.x + r;
  p.y = center.y;
  Pen_action_to_tmpfile (MOVE_TO, &p, scale_flag);
  if (polygon_mode){
  		polyp.x=p.x;
  		polyp.y=p.y;
  		}
  if (CurrentLineType == LT_adaptive)	/* Adaptive patterns    */
    {
      p.x = r * cos (eps);	/* A chord segment      */
      p.y = r * sin (eps);
      if (scale_flag)
	User_to_Plotter_coord (&p, &p);

      /*      Pattern length = chord length           */
      CurrentLinePatLen = HYPOT (p.x, p.y);
    }

  for (phi = eps; phi < 2.0 * M_PI; phi += eps)
    {
      p.x = center.x + r * cos (phi);
      p.y = center.y + r * sin (phi);
      if (iwflag)
	{
	  if (P1.x + (p.x - S1.x) * Q.x > C2.x || P1.y + (p.y - S1.y) * Q.y > C2.y)
	    {
/*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
	      outside = 1;
	    }
	  if (P1.x + (p.x - S1.x) * Q.x < C1.x || P1.y + (p.y - S1.y) * Q.y < C1.y)
	    {
/*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
	      outside = 1;
	    }
	}

      if (!outside){
	if (polygon_mode){
  		polygons[++vertices]=polyp;
  		polygons[++vertices]=p;
  		polyp.x=p.x;
  		polyp.y=p.y;
		}else{
	Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);
        } 
      }else
	Pen_action_to_tmpfile (MOVE_TO, &p, scale_flag);
      outside = 0;
    }
  p.x = center.x + r;		/* Close circle at r * (1, 0)   */
  p.y = center.y;
	if (polygon_mode){
  		polygons[++vertices]=polyp;
  		polygons[++vertices]=p;
		}else
  Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);

  Pen_action_to_tmpfile (MOVE_TO, &center, scale_flag);

  CurrentLinePatLen = SafeLinePatLen;	                /* Restore */
}

static void
wedges (FILE * hd)		/*derived from circles */
{
  HPGL_Pt p, center;
  float eps, r, start, sweep;
  double phi;
  double SafeLinePatLen = CurrentLinePatLen;
  int outside = 0;

  if (read_float (&r, hd))	/* No radius found      */
    return;

  if (read_float (&start, hd))	/* No start angle found */
    return;

  if (read_float (&sweep, hd))	/* No sweep angle found */
    return;

  switch (read_float (&eps, hd))	/* chord angle */
    {
    case 0:
      break;
    case 1:			/* No resolution option */
      eps = 5.0;		/*    so use default!   */
      break;
    case 2:			/* Illegal state        */
      par_err_exit (98, EW);
    case EOF:
      return;
    default:			/* Illegal state        */
      par_err_exit (99, EW);
    }
  eps *= M_PI / 180.0;		/* Deg-to-Rad           */
  start *= M_PI / 180.0;	/* Deg-to-Rad           */
  sweep *= M_PI / 180.0;	/* Deg-to-Rad           */


  center = p_last;		/* reference point is last position */

  if (r == 0.0)			/* Zero radius given    */
    return;

  p.x = center.x + r * cos (start);
  p.y = center.y + r * sin (start);
  Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);

  if (CurrentLineType == LT_adaptive)	/* Adaptive patterns    */
    {
      p.x = r * cos (eps);	/* A chord segment      */
      p.y = r * sin (eps);
      if (scale_flag)
	User_to_Plotter_coord (&p, &p);

      /*      Pattern length = chord length           */
      CurrentLinePatLen = HYPOT (p.x, p.y);
    }

  for (phi = eps; phi <= sweep; phi += eps)
    {
      p.x = center.x + r * cos (start + phi);
      p.y = center.y + r * sin (start + phi);
      if (iwflag)
	{
	  if (P1.x + (p.x - S1.x) * Q.x > C2.x || P1.y + (p.y - S1.y) * Q.y > C2.y)
	    {
/*fprintf(stderr,"IW set:point %f %f >P2\n",p.x,p.y); */
	      outside = 1;
	    }
	  if (P1.x + (p.x - S1.x) * Q.x < C1.x || P1.y + (p.y - S1.y) * Q.y < C1.y)
	    {
/*fprintf(stderr,"IW set:point  %f %f <P1\n",p.x,p.y); */
	      outside = 1;
	    }
	}
      if (!outside)
	Pen_action_to_tmpfile (DRAW_TO, &p, scale_flag);
      else
	Pen_action_to_tmpfile (MOVE_TO, &p, scale_flag);
      outside = 0;
    }

  Pen_action_to_tmpfile (DRAW_TO, &center, scale_flag);

  CurrentLinePatLen = SafeLinePatLen;	                /* Restore */
}


/**
 ** Rectangles --  by Th. Hiller (hiller@tu-harburg.d400.de)
 **/

static void
rect (int relative, int filled, float cur_pensize, FILE * hd)
{
  HPGL_Pt p;
  HPGL_Pt p1;

  for (;;)
    {
      if (read_float (&p.x, hd))	/* No number found */
	return;

      if (read_float (&p.y, hd))	/* x without y invalid! */
	par_err_exit (2, EA);


      if (relative)		/* Process coordinates */
	{
	  p.x += p_last.x;
	  p.y += p_last.y;
	}
      if (!filled)
	{
	  p1.x = p_last.x;
	  p1.y = p.y;
	  Pen_action_to_tmpfile (DRAW_TO, &p1, scale_flag);
	  p1.x = p.x;
	  p1.y = p.y;
	  Pen_action_to_tmpfile (DRAW_TO, &p1, scale_flag);
	  p1.x = p.x;
	  p1.y = p_last.y;
	  Pen_action_to_tmpfile (DRAW_TO, &p1, scale_flag);
	  p1.x = p_last.x;
	  p1.y = p_last.y;
	  Pen_action_to_tmpfile (DRAW_TO, &p1, scale_flag);
	}
      else
	{
	  vertices = 0;
	  polygons[vertices] = p_last;
	  p1.x = p_last.x;
	  p1.y = p.y;
	  polygons[++vertices] = p1;
	  polygons[++vertices] = p1;
	  polygons[++vertices] = p;
	  polygons[++vertices] = p;
	  p1.x = p.x;
	  p1.y = p_last.y;
	  polygons[++vertices] = p1;
	  polygons[++vertices] = p1;
	  polygons[++vertices] = p_last;
	  	if (hatchspace==0.) hatchspace=cur_pensize;
	if (filltype<3 && thickness > 0.) hatchspace=thickness; 
	  fill (polygons, vertices, P1, P2, scale_flag, filltype, hatchspace, hatchangle);
	}
      Pen_action_to_tmpfile (MOVE_TO, &p_last, scale_flag);
    }
}




static void
ax_ticks (int mode)
{
  HPGL_Pt p0, p1, p2;
  int SafeLineType = CurrentLineType;

  p0 = p1 = p2 = p_last;
/**
 ** According to the HP-GL manual,
 ** XT & YT are not affected by LT
 **/
  CurrentLineType = LT_solid;

  if (mode == 0)		/* X tick       */
    {
        if (scale_flag){
         p1.y -= neg_ticklen * (P2.y - P1.y) / Q.y;
         p2.y += pos_ticklen * (P2.y - P1.y) / Q.y;
       }else{
      p1.y -= neg_ticklen * (P2.y - P1.y);
      p2.y += pos_ticklen * (P2.y - P1.y);
	}
    }
  else
    /* Y tick */
    {
      if (scale_flag){
         p1.x -= neg_ticklen * (P2.x - P1.x) / Q.x;
         p2.x += pos_ticklen * (P2.x - P1.x) / Q.x;
       }else{
      p1.x -= neg_ticklen * (P2.x - P1.x);
      p2.x += pos_ticklen * (P2.x - P1.x);
    	}
    }

  Pen_action_to_tmpfile (MOVE_TO, &p1, scale_flag);
  Pen_action_to_tmpfile (DRAW_TO, &p2, scale_flag);
  Pen_action_to_tmpfile (MOVE_TO, &p0, scale_flag);

  CurrentLineType = SafeLineType;
}



/**
 **	Process a single HPGL command
 **/

void read_HPGL_cmd (GEN_PAR * pg, short cmd, FILE * hd) {
  short old_pen;
  HPGL_Pt p1, p2={0,0};
  float ftmp;
  float csfont;
  int mypen, myred, mygreen, myblue, i;
  float mywidth, myheight;
  char tmpstr[1024];
  char SafeTerm;
/**
 ** Each command consists of 2 characters. We unite them here to a single int
 ** to allow for easy processing within a big switch statement:
 **/

  switch (cmd & 0xDFDF)		/* & forces to upper case       */
    {
  /**
   ** Commands appear in alphabetical order within each topic group
   ** except for command synonyms.
   **/
    case AA:			/* Arc Absolute                 */
      arcs (FALSE, hd);
      tp->CR_point = HP_pos;
      break;
    case AR:			/* Arc Relative                 */
      arcs (TRUE, hd);
      tp->CR_point = HP_pos;
      break;
    case AT:			/* Arc Absolute, through Three points */
      tarcs (FALSE, hd);
      break;
    case CA:			/* Alternate character set      */
      if (read_float (&csfont, hd))	/* just CA;    */
	tp->altfont = 0;
      else
	tp->altfont = csfont;
      break;
    case CI:			/* Circle                       */
      circles (hd);
      break;
    case CO:                    /* Comment                      */
      SafeTerm=StrTerm;
      StrTerm=';';
      read_string(tmpstr,hd);
      StrTerm=SafeTerm;
      if (!silent_mode) printf("\n%s\n",tmpstr);
      break;
    case CS:			/*character set selection       */
      if (read_float (&csfont, hd))	/* just CS;     */
	tp->font = 0;
      else
	tp->font = csfont;
      tp->stdfont = csfont;
      break;
    case EP:			/* edge polygon */
      for (i = 0; i < vertices; i = i + 2)
	{			/*for all polygon edges */
	  p1.x = polygons[i].x;
	  p1.y = polygons[i].y;
	  Pen_action_to_tmpfile (MOVE_TO, &p1, scale_flag);
	  p1.x = polygons[i + 1].x;
	  p1.y = polygons[i + 1].y;
	  Pen_action_to_tmpfile (DRAW_TO, &p1, scale_flag);
	}
      Pen_action_to_tmpfile (MOVE_TO, &p_last, scale_flag);
      break;

    case EW:			/* Edge Wedge                   */
      wedges (hd);
      break;

    case EC:
    /*  printf("cut paper\n"); */
      break;

    case FP:			/* fill polygon */
    	if (pg->nofill){
    	if (!silent_mode) fprintf(stderr,"FP : suppressed\n");
    	break;
    	}
 	if (hatchspace==0.) hatchspace=pt.width[pen]/10.;
	if (filltype<3 && thickness > 0.) hatchspace=thickness; 
      fill (polygons, vertices, P1, P2, scale_flag, filltype, hatchspace, hatchangle);
      Pen_action_to_tmpfile (MOVE_TO, &p_last, scale_flag);
      break;
    case FT:			/* Fill Type */
      if (read_float (&ftmp, hd))
	{			/* just FT -> FT=1 */
	  filltype = 1;
	  break;
	}
      else
	{
	  filltype = ftmp;
	}
      if (filltype < 3)
	break;

      if (filltype > 4)
	{
	  if (!silent_mode)
	    fprintf (stderr, "No support for user-defined fill types, using type 1 instead\n");
	  filltype = 1;
	}

      if (read_float (&ftmp, hd))
	break;
      else
	hatchspace = ftmp;

      if (read_float (&ftmp, hd))
	break;
      else
	hatchangle = ftmp;
      break;
    case NP:			/* Number of Pens                    */
      if (read_float (&ftmp, hd) || ftmp > NUMPENS)	/* invalid or missing */
	break;
      else
	{
	  pg->maxpens = ftmp;
	  if (!silent_mode)
	    fprintf (stderr, "NP: %d pens requested\n", pg->maxpens);
	}
      break;
    case NR: /*Not ready - pause plotter (noop)*/
	if (read_float(&ftmp,hd)) break;
	break;
    case PA:			/* Plot Absolute                */
      lines (plot_rel = FALSE, hd);
      tp->CR_point = HP_pos;
      break;
    case PC:			/* Pen Color                    */
      if (read_float (&ftmp, hd) || fixedcolor || ftmp > pg->maxpens)
	{			/* invalid or missing */
	}
      else
	{
	  mypen = ftmp;
	  if (read_float (&ftmp, hd))	/* no red component  */
	    myred = 0;
	  else
	    myred = ftmp;
	  if (read_float (&ftmp, hd))	/* no green component  */
	    mygreen = 0;
	  else
	    mygreen = ftmp;
	  if (read_float (&ftmp, hd))	/* no blue component  */
	    myblue = 0;
	  else
	    myblue = ftmp;
	  pg->is_color = TRUE;
	  PlotCmd_to_tmpfile(DEF_PC);
          Pen_Color_to_tmpfile(mypen,myred,mygreen,myblue);
/*          set_color_rgb(mypen,myred,mygreen,myblue);
	  pt.color[mypen] = mypen;
*/	  
	}
      break;
    case PD:			/* Pen  Down                    */
      pen_down = TRUE;
      lines (plot_rel, hd);
      tp->CR_point = HP_pos;
      break;
    case PE:
      read_PE (pg, hd);
      tp->CR_point = HP_pos;
      break;
    case PM:
      if (read_float (&ftmp, hd) || ftmp == 0)
	{			/* no parameters or PM0 */
	  polygon_mode = TRUE;
	  polygon_penup = FALSE;
	  vertices = -1;
	  break;
	}
      if (ftmp == 1)
	{
	  polygon_penup = TRUE;
	  pen_down = FALSE;
	  break;
	}
      if (ftmp == 2)
	{
	  polygon_mode = FALSE;
	}
      break;
    case PR:			/* Plot Relative                */
      lines (plot_rel = TRUE, hd);
      tp->CR_point = HP_pos;
      break;
    case PS:
      if (read_float (&ftmp, hd))
	{			/* no parameters */
	  break;
	}
      else
	{
	  myheight = ftmp;
	}
      if (read_float (&ftmp, hd))
	{			/* no parameters */
/*	  mywidth = MAX(myheight,xmax); ??*/
	mywidth=p2.y;
	}
      else
	{
	  mywidth = ftmp;
	if (mywidth > myheight) {
		mywidth=myheight;
		myheight=ftmp;
		}
	}
      ps_flag = 1;
/*      fprintf(stderr,"min,max vor PS: %f %f %f %f\n",xmin,ymin,xmax,ymax);*/
      M.x = myheight;
      M.y = mywidth;
      p1.x = 0;
      p1.y = 0;
      if (scale_flag)		/* Rescaling    */
	User_to_Plotter_coord (&p1, &p2);
      else
	p2 = p1;		/* Local copy   */


      if (rotate_flag)		/* hp2xx-specific global rotation       */
	{
	  ftmp = rot_cos * p2.x - rot_sin * p2.y;
	  p2.y = rot_sin * p2.x + rot_cos * p2.y;
	  p2.x = ftmp;
	}
      xmin = MIN (p2.x, xmin);
      ymin = MIN (p2.y, ymin);
      xmax = MAX (p2.x, xmax);
      ymax = MAX (p2.y, ymax);
      p1.x = myheight;
      p1.y = mywidth;
#if 1
/* add the following - to get the correct linetype scale etc */
      P1.x=0;
      P1.y=0;
      P2.x=myheight;
      P2.y=mywidth;
      Diag_P1_P2 = HYPOT (P2.x - P1.x, P2.y - P1.y);
      CurrentLinePatLen = 0.04 * Diag_P1_P2;
      S1=P1;
      S2=P2;
/* ajb */
#endif
#if 0
      if (scale_flag)		/* Rescaling    */
	User_to_Plotter_coord (&p1, &p2);
      else
	p2 = p1;		/* Local copy   */


      if (rotate_flag)		/* hp2xx-specific global rotation       */
	{
	  ftmp = rot_cos * p2.x - rot_sin * p2.y;
	  p2.y = rot_sin * p2.x + rot_cos * p2.y;
	  p2.x = ftmp;
	}
      xmin = MIN (p2.x, xmin);
      ymin = MIN (p2.y, ymin);
      xmax = MAX (p2.x, xmax);
      ymax = MAX (p2.y, ymax);
/*      fprintf(stderr,"min,max nach  PS: %f %f %f %f\n",xmin,ymin,xmax,ymax);*/
#endif
      break;
    case PT:      /* Pen thickness (for solid fills - current pen only */
      if (read_float (&ftmp, hd))
	{			/* no parameters */
	 thickness=0.3;
	  break;
	}
      else
	{
	 if (ftmp >= 0.1 && ftmp <= 5.) thickness=ftmp;
	}
    case PU:			/* Pen  Up                      */
      pen_down = FALSE;
      lines (plot_rel, hd);
      tp->CR_point = HP_pos;
      break;
    case PW:			/* Pen Width                    */
      if (fixedwidth)
	{
	  if (!silent_mode)
	    fprintf (stderr, "PW: ignored (hardware mode)\n");
	  break;
	}
      if (read_float (&ftmp, hd))
	{			/* no parameters -> set defaults */
	  mywidth = 0.35;
	  if (wu_relative) 
             mywidth=Diag_P1_P2/1000.;
	if (mywidth <0.1) mywidth=0.1;
	  PlotCmd_to_tmpfile(DEF_PW);
          Pen_Width_to_tmpfile(0,(int) (mywidth * 10.));
/*	 
	  fprintf(stderr,"PW: defaulting to 0.35 for all pens\n");
*/
	  break;
	}
      else
	{
	  mywidth = ftmp;	/* first or only parameter is width */
	  if (wu_relative) mywidth=Diag_P1_P2* ftmp /1000.;
	  if (mywidth < 0.1)
	    mywidth = 0.1;
	}

      if (read_float (&ftmp, hd))
	{			/* width only, applies to all pens */
	  PlotCmd_to_tmpfile(DEF_PW);
          Pen_Width_to_tmpfile(0,(int) (mywidth * 10.));
	  if (pg->maxpensize < mywidth * 10.)
	    pg->maxpensize = mywidth * 10.;
/*	 
          fprintf(stderr,"PW: defaulting to %d for all pens\n",(int) (mywidth*10.));
*/
	}
      else
	{			/* second parameter is pen */
	 PlotCmd_to_tmpfile(DEF_PW);
         Pen_Width_to_tmpfile(ftmp,(int) (mywidth * 10.));
	 if (ftmp <= pg->maxpens)
	    {
	      if (pg->maxpensize < mywidth * 10.)
		pg->maxpensize = mywidth * 10.;
	    }
/*
         fprintf(stderr,"pen%d, size now %d\n",(int) ftmp,(int) (mywidth * 10.));
*/
	}
      break;
    case TL:			/* Tick Length                  */
      if (read_float (&ftmp, hd))	/* No number found  */
	{
	  neg_ticklen = pos_ticklen = 0.005;
	  return;
	}
      else
	pos_ticklen = ftmp / 100.0;

      if (read_float (&ftmp, hd))	/* pos, but not neg */
	{
	  neg_ticklen = 0.0;
	  return;
	}
      else
	neg_ticklen = ftmp / 100.0;
      break;
    case WG:			/* Filled Wedge                 */
      fwedges (hd,pt.width[pen]/10.);
      break;
    case WU:			/* pen Width Unit is relative  */
      if (read_float (&ftmp, hd) || ftmp==0.)	/* Zero or no number  */
      wu_relative = FALSE ;
      else 
      wu_relative = TRUE ;
      break;
    case XT:			/* X Tick                       */
      ax_ticks (0);
      break;
    case YT:			/* Y Tick                       */
      ax_ticks (1);
      break;


    case IP:			/* Input reference Points P1,P2 */
      tp->width /= (P2.x - P1.x);
      tp->height /= (P2.y - P1.y);
      if (read_float (&p1.x, hd))	/* No number found  */
	{
	  P1.x = P1X_default;
	  P1.y = P1Y_default;
	  P2.x = P2X_default;
	  P2.y = P2Y_default;
	  goto IP_Exit;
	}
      if (read_float (&p1.y, hd))	/* x without y! */
	par_err_exit (2, cmd);

      if (read_float (&p2.x, hd))	/* No number found  */
	{
	  P2.x += p1.x - P1.x;
	  P2.y += p1.y - P1.y;
	  P1 = p1;
	  goto IP_Exit;
	}
      if (read_float (&p2.y, hd))	/* x without y! */
	par_err_exit (4, cmd);

      P1 = p1;
      P2 = p2;


    IP_Exit:
      Q.x = (P2.x - P1.x) / (S2.x - S1.x);
      Q.y = (P2.y - P1.y) / (S2.y - S1.y);
      Diag_P1_P2 = HYPOT (P2.x - P1.x, P2.y - P1.y);
      CurrentLinePatLen = 0.04 * Diag_P1_P2;
      tp->width *= (P2.x - P1.x);
      tp->height *= (P2.y - P1.y);
      adjust_text_par ();
      return;

    case IW:
      iwflag = 1;
      if (read_float (&C1.x, hd))	/* No number found  */
	{
	 if (scale_flag){
		if (rotate_flag){
		  C1.x = S1.y;
		  C1.y = S1.x;
		  C2.x = S2.y;
		  C2.y = S2.x;
		}else{
		  C1.x = S1.x;
		  C1.y = S1.y;
		  C2.x = S2.x;
		  C2.y = S2.y;
		}
	  }else{
	  C1.x = P1.x;
	  C1.y = P1.y;
	  C2.x = P2.x;
	  C2.y = P2.y;
fprintf (stderr," clip limits (%f,%f)(%f,%f)\n",C1.x,C1.y,C2.x,C2.y);
	  }
	}
      else
	{
	  if (read_float (&C1.y, hd))	/* x without y! */
	    par_err_exit (2, cmd);
	  if (read_float (&C2.x, hd))	/* No number found  */
	    par_err_exit (3, cmd);
	  if (read_float (&C2.y, hd))	/* x without y! */
	    par_err_exit (4, cmd);
      }
      if (scale_flag) {
                    User_to_Plotter_coord(&C1,&C1);
                    User_to_Plotter_coord(&C2,&C2);
	}
	
      break;

    case OP:			/* Output reference Points P1,P2 */
      if (!silent_mode)
	{
	  Eprintf ("\nP1 = (%g, %g)\n", P1.x, P1.y);
	  Eprintf ("P2 = (%g, %g)\n", P2.x, P2.y);
	}
      break;

    case AF:
    case AH:
    case PG:			/* new PaGe                     */
      /* record ON happens only once! */
      page_number++;
      record_off =(short)( (first_page > page_number)
	|| ((last_page < page_number) && (last_page > 0)));
      break;

    case EA:			/* Edge Rectangle absolute */
      rect (plot_rel = FALSE, 0, pt.width[pen]/10., hd);
      tp->CR_point = HP_pos;
      break;

    case ER:			/* Edge Rectangle relative */
      rect (TRUE, 0, 0., hd);
      tp->CR_point = HP_pos;
      break;

    case RA:			/* Fill Rectangle absolute */
      rect (plot_rel = FALSE, 1,  pt.width[pen]/10., hd);
      tp->CR_point = HP_pos;
      break;

    case RR:			/* Fill Rectangle relative */
      rect (plot_rel = TRUE, 1, pt.width[pen]/10., hd);
      tp->CR_point = HP_pos;
      break;

    case RT:			/* Relative arc, through Three points */
      tarcs (TRUE, hd);
      break;

    case LT:			/* Line Type:                   */
      if (read_float (&p1.x, hd))	/* just LT;     */
	CurrentLineType = LT_solid;
      else {
	 if((((int) p1.x) >= LT_MIN) && (((int) p1.x) < LT_ZERO) )
            CurrentLineType = LT_adaptive;
         else if(((int) p1.x) == LT_ZERO) 
	    CurrentLineType = LT_plot_at;
	 else if((((int) p1.x) > LT_ZERO) && (((int) p1.x) <= LT_MAX) )
	    CurrentLineType = LT_fixed;
         else {
	    Eprintf ("Illegal line type:\t%d\n", (int) p1.x);
	    CurrentLineType = LT_solid;                         /* set to something sane */
         }
         CurrentLinePattern = p1.x;

	 if (!read_float (&p1.y, hd)) { 	/* optional pattern length?     */
	    if (p1.y <= 0.0)
	       Eprintf ("Illegal pattern length:\t%g\n", p1.y);
	    else {
               Diag_P1_P2 = HYPOT (P2.x - P1.x, P2.y - P1.y);
     
               if(!read_float(&ftmp, hd)) {
                  if(ftmp == 1.0) {
                     CurrentLinePatLen = p1.y * 40;                 /* absolute */ 
                  } else {
	             CurrentLinePatLen = Diag_P1_P2 * p1.y / 100.0; /* relative */
                  }
               } else {
	          CurrentLinePatLen = Diag_P1_P2 * p1.y / 100.0;    /* relative */
               }
            }
	 }
      }

      break;

    case SC:			/* Input Scale Points S1,S2     */
      User_to_Plotter_coord (&p_last, &p_last);
      if (read_float (&S1.x, hd))	/* No number found  */
	{
	  S1.x = P1X_default;
	  S1.y = P1Y_default;
	  S2.x = P2X_default;
	  S2.y = P2Y_default;
	  scale_flag = FALSE;
	  Q.x = Q.y = 1.0;
	  return;
	}
      if (read_float (&S2.x, hd))	/* x without y! */
	par_err_exit (2, cmd);
      if (read_float (&S1.y, hd))	/* No number found  */
	par_err_exit (3, cmd);
      if (read_float (&S2.y, hd))	/* x without y! */
	par_err_exit (4, cmd);

      if (read_float (&ftmp,hd)) ftmp=0; /*scaling defaults to type 0*/
      
      switch ( (int)ftmp)
      {
      case 0: /* anisotropic scaling */
      Q.x = (P2.x - P1.x) / (S2.x - S1.x);
      Q.y = (P2.y - P1.y) / (S2.y - S1.y);
      break;
      
      case 1: /* isotropic scaling */
       if (read_float (&ftmp,hd)) /* percentage of unused space on the left */
        ftmp=50.0;                /* of the isotropic area defaults to 50%  */
         Q.x = (P2.x - P1.x) / (S2.x - S1.x);
         Q.y = (P2.y - P1.y) / (S2.y - S1.y);
         if (Q.x<Q.y) {
          if (read_float (&ftmp,hd)) 
            ftmp=50.0;  /* percentage of unused space below the plot*/
          S1.y+=ftmp*((P2.y-P1.y)/Q.y-(P2.y-P1.y)/Q.x)/100.0;
          Q.y=Q.x;
	  S2.y=S1.y + (P2.y - P1.y)/Q.y;
         } else {
          S1.x+=ftmp*((P2.x-P1.x)/Q.x-(P2.x-P1.x)/Q.y)/100.0;
          read_float(&ftmp,hd); /* mandatory 'bottom' value is unused */
          Q.x=Q.y;
          S2.x=S1.x + (P2.x - P1.x)/Q.x;
         }
         break;
      case 2: /* point factor scaling */
       Q.x=S2.x;
       Q.y=S2.y;
       S2.x=S1.x + (P2.x - P1.x)/Q.x;
       S2.y=S1.y + (P2.y - P1.y)/Q.y;
      break;
      default:
       par_err_exit(0,cmd);
     }
      scale_flag = TRUE;
      Plotter_to_User_coord (&p_last, &p_last);
      break;

    case SP:			/* Select pen: none/0, or 1...8 */
      old_pen = pen;
      thickness=0.; /* clear any PT setting (should we default to 0.3 here ??)*/
      if (read_float (&p1.x, hd))	/* just SP;     */
	pen = 0;
      else
	pen = (short) p1.x;

      if (pen < 0 || pen > pg->maxpens)
	{
	  Eprintf (
		    "\nIllegal pen number %d: replaced by %d\n", pen, pen % pg->maxpens);
	  n_unexpected++;
	  pen%= (short)pg->maxpens;
	}
      if (old_pen != pen)
	{
	  if ((fputc (SET_PEN, td) == EOF) ||
	      (fputc (pen, td) == EOF))
	    {
	      PError ("Writing to temporary file:");
	      Eprintf ("Error @ Cmd %ld\n", vec_cntr_w);
	      exit (ERROR);
	    }
	}
      if (pen)
	pens_in_use[pen] = 1;
/*              pens_in_use |= (1 << (pen-1)); */
      break;

    case DF:			/* Set to default               */
    case BP:			/* Begin Plot */
    case IN:			/* Initialize */
      reset_HPGL ();
      tp->CR_point = HP_pos;
      break;
    case RO:
      if (read_float (&ftmp, hd))	/* No number found  */
	{
	  break;
	}
      else
	{
	if (!silent_mode)
	  fprintf (stderr, "RO encountered, rotating P1,P2 by %f\n", ftmp);

	  rotate_flag = 1;
	  rot_ang += ftmp;

	  switch ((int) ftmp)
	    {
	    case 90:
	    case 270:
	      ftmp = M.x;
	      M.x = M.y;
	      M.y = ftmp;
	      break;
	    case 180:
	    default:
	      break;
	    }
	    if (!silent_mode)
	  fprintf (stderr, "cumulative rot_ang now %f\n", rot_ang);
	  rot_cos = cos (M_PI * rot_ang / 180.0);
	  rot_sin = sin (M_PI * rot_ang / 180.0);
	  rotate_flag = 1;

	  if (ps_flag)
	    {			/* transform extents from previous PS statement */

	      xmin = 1e10;
	      ymin = 1e10;
	      xmax = 1e-10;
	      ymax = 1e-10;

	      p1.x = 0;
	      p1.y = 0;
	      if (scale_flag)	/* Rescaling    */
		User_to_Plotter_coord (&p1, &p2);
	      else
		p2 = p1;	/* Local copy   */
	      HP_pos = p2;	/* Actual plotter pos. in plotter coord */
	      ftmp = rot_cos * p2.x - rot_sin * p2.y;
	      p2.y = rot_sin * p2.x + rot_cos * p2.y;
	      p2.x = ftmp;
	      xmin = MIN (p2.x, xmin);
	      ymin = MIN (p2.y, ymin);
	      xmax = MAX (p2.x, xmax);
	      ymax = MAX (p2.y, ymax);
	      p1.x = M.x;
	      p1.y = M.y;
	      if (scale_flag)	/* Rescaling    */
		User_to_Plotter_coord (&p1, &p2);
	      else
		p2 = p1;	/* Local copy   */
	      HP_pos = p2;	/* Actual plotter pos. in plotter coord */
	      ftmp = rot_cos * p2.x - rot_sin * p2.y;
	      p2.y = rot_sin * p2.x + rot_cos * p2.y;
	      p2.x = ftmp;
	      xmin = MIN (p2.x, xmin);
	      ymin = MIN (p2.y, ymin);
	      xmax = MAX (p2.x, xmax);
	      ymax = MAX (p2.y, ymax);
	    }
	}
      break;
    case BL:			/* Buffer label string          */
      read_string (strbuf, hd);
      break;
    case CP:			/* Char Plot (rather: move)     */
      if (read_float (&p1.x, hd))	/* No number found  */
	{
	  plot_string ("\n\r", LB_direct);
	  return;
	}
      else if (read_float (&p1.y, hd))
	par_err_exit (2, cmd);

      p2.x = p1.x * tp->chardiff.x - p1.y * tp->linediff.x + HP_pos.x;
      p2.y = p1.x * tp->chardiff.y - p1.y * tp->linediff.y + HP_pos.y;
      Pen_action_to_tmpfile (MOVE_TO, &p2, FALSE);
      break;
    case DI:			/* Char plot Dir (absolute)     */
      if (read_float (&p1.x, hd))	/* No number found  */
	{
	  tp->dir = 0.0;
	  tp->CR_point = HP_pos;
	  adjust_text_par ();
	  break;
	}
      if (read_float (&p1.y, hd))	/* x, but not y */
	par_err_exit (2, cmd);
      if ((p1.x == 0.0) && (p1.y == 0.0))
	par_err_exit (0, cmd);
      tp->dir = atan2 (p1.y, p1.x);
      tp->CR_point = HP_pos;
      adjust_text_par ();
      break;
    case DR:			/* Char plot Dir (rel P1,P2)    */
      if (read_float (&p1.x, hd))	/* No number found  */
	{
	  tp->dir = 0.0;
	  tp->CR_point = HP_pos;
	  adjust_text_par ();
	  break;
	}
      if (read_float (&p1.y, hd))
	par_err_exit (2, cmd);	/* x, but not y */
      if ((p1.x == 0.0) && (p1.y == 0.0))
	par_err_exit (0, cmd);
      tp->dir = atan2 (p1.y * (P2.y - P1.y), p1.x * (P2.x - P1.x));
      tp->CR_point = HP_pos;
      adjust_text_par ();
      break;
    case DT:			/* Define string terminator     */
      StrTerm =(char) getc (hd);
      break;
    case DV:			/* Text direction vertical      */
      if (read_float (&ftmp, hd) || ftmp == 0)
	mode_vert = 0;
      else
	mode_vert = 1;
      break;
    case ES:			/* Extra Space                  */
      if (read_float (&tp->espace, hd))		/* No number found */
	{
	  tp->espace = 0.0;
	  tp->eline = 0.0;
	}
      else if (read_float (&tp->eline, hd))
	tp->eline = 0.0;	/* Supply default       */
      adjust_text_par ();
      break;
    case LB:			/* Label string                 */
      read_string (strbuf, hd);
      plot_string (strbuf, LB_direct);
      /*
       * Bug fix by W. Eric Norum:
       * Update the position so that subsequent `PR's will work.
       */
      if (scale_flag)
	Plotter_to_User_coord (&HP_pos, &p_last);
      else
	p_last = HP_pos;
      break;
    case LO:			/* Label Origin                 */
      if (read_float (&p1.x, hd))	/* No number found */
	tp->orig = 1;
      else
	{
	  tp->orig = (int) p1.x;
	  if (tp->orig < 1 || tp->orig == 10 || tp->orig > 19)
	    tp->orig = 1;	/* Error        */
	}
      adjust_text_par ();
      break;
    case PB:			/* Plot Buffered label string   */
      plot_string (strbuf, LB_buffered);
      break;
    case SI:			/* Char cell Sizes (absolute)   */
      if (read_float (&tp->width, hd))	/* No number found */
	{
	  tp->width = 0.187;	/* [cm], A4     */
	  tp->height = 0.269;	/* [cm], A4     */
	}
      else
	{
	  if (read_float (&tp->height, hd))
	    par_err_exit (2, cmd);
	  if ((tp->width == 0.0) || (tp->height == 0.0))
	    par_err_exit (0, cmd);
	}
      tp->width *= 400.0;	/* [cm] --> [plotter units]        */
      tp->height *= 400.0;	/* [cm] --> [plotter units]        */
      adjust_text_par ();
      break;
    case SL:			/* Char Slant                   */
      if (read_float (&tp->slant, hd))	/* No number found     */
	tp->slant = 0.0;
      adjust_text_par ();
      break;
    case SM:			/* Symbol Mode                  */
      read_symbol_char (hd);
      break;
    case SR:			/* Character  sizes (Rel P1,P2) */
      if (read_float (&tp->width, hd))	/* No number found */
	{
	  tp->width = 0.75;	/* % of (P2-P1)_x    */
	  tp->height = 1.5;	/* % of (P2-P1)_y    */
	}
      else
	{
	  if (read_float (&tp->height, hd))
	    par_err_exit (2, (short)cmd);
	  if ((tp->width == 0.0) || (tp->height == 0.0))
	    par_err_exit (0, (short)cmd);
	}
      tp->width *= (P2.x - P1.x) / 100.0;	/* --> [pl. units]     */
      tp->height *= (P2.y - P1.y) / 100.0;
      adjust_text_par ();
      break;
    case SA:			/* Select designated alternate charset */
      if (tp->altfont)
	tp->font = tp->altfont;
      else			/* Was never designated, default to 0 */
	tp->font = 0;
      break;
    case SS:			/* Select designated standard character set */
      if (tp->stdfont)
	tp->font = tp->stdfont;
      else			/* Was never designated, default to 0 */
	tp->font = 0;
      break;
    case UC:			/* User defined character       */
      plot_user_char (hd);
      break;
    case UL:			/* User defined line style      */
      set_line_style_by_UL(hd);
      break;
    case MG:
    case WD:			/* Write string to display      */
      read_string (strbuf, hd);
      if (!silent_mode)
	Eprintf ("\nLABEL: %s\n", strbuf);
      break;

    default:			/* Skip unknown HPGL command: */
      n_unknown++;
      if (!silent_mode)
	Eprintf ("  %c%c: ignored  ", cmd >> 8, cmd & 0xFF);
      if (cmd == EOF)
	{
	  n_unexpected++;
	  if (!silent_mode)
	    Eprintf ("\nUnexpected EOF!\t");
	}
      break;
    }
}


void read_HPGL (GEN_PAR * pg, const IN_PAR * pi) {
/**
 ** This routine is the high-level entry for HP-GL processing.
 ** It reads the input stream character-by-character, identifies
 ** ESC. commands (device controls) and HP-GL mnemonics, reads
 ** parameters (if expected), and initiates processing of these
 ** commands. It finally reports on this parsing process.
 **/
  int c;
  short cmd;

  init_HPGL (pg, pi);

  if (!pg->quiet)
    Eprintf ("\nReading HPGL file\n");

  /**
   ** MAIN parser LOOP!!
   **/
  while ((c = getc (pi->hd)) != EOF) {
   switch(c) {
#ifdef MUTOH_KLUGE
      case '\a':
	 Eprintf("Mutoh header found\n");
	 read_ESC_cmd (pi->hd,FALSE);  /* ESC sequence */
	 break;
#endif
      case ESC:
	 read_ESC_cmd (pi->hd,TRUE);   /* ESC sequence */
	 break;
      default:
	 if ((c<'A') || (c>'z') || ((c>'Z')&&(c<'a'))) break;
	 cmd = (short)(c<<8);
	 if ((c = getc(pi->hd)) == EOF)
	     return;
	 if ((c<'A') || (c>'z') || ((c>'Z')&&(c<'a'))) {
	     ungetc(c,pi->hd);
	     break;
	 }
	 cmd |= (short)(c & 0xFF);
	 read_HPGL_cmd (pg, cmd, pi->hd);
      }
    }

  if (!pg->quiet)
    {
      Eprintf ("\nHPGL command(s) ignored: %d\n", n_unknown);
      Eprintf ("Unexpected event(s):  %d\n", n_unexpected);
      Eprintf ("Internal command(s):  %ld\n", vec_cntr_w);
      Eprintf ("Pens used: ");
/*      for (c=0; c < NUMPENS; c++, pens_in_use >>= 1)
   if (pens_in_use & 1)
 */
      for (c = 0; c < NUMPENS; c++)
	if (pens_in_use[c] == 1)
	  Eprintf ("%d ", c);
/*                      Eprintf ("%d ", c+1); */
      Eprintf ("\nMax. number of pages: %d\n", page_number);
    }
}




void
adjust_input_transform (const GEN_PAR * pg, const IN_PAR * pi, OUT_PAR * po)
{
/**
 ** The temporary input data of the temp. file may be re-used multiple
 ** times by calling this function with varying parameters,
 ** mainly in pi.
 **
 ** Some conversion factors for transformation from HP-GL coordinates
 ** (as given in the temp. file) into mm or pel numbers are set here.
 ** There are both global parameters and elemts of po set here.
 ** DPI-related factors only apply if the current mode is a raster mode.
 **
 ** # points (dots) in any direction = range [mm] * 1in/25.4mm * #dots/in
 **/

  double dot_ratio, Dx, Dy, tmp_w, tmp_h;
  char *dir_str;

  Dx = xmax - xmin;
  Dy = ymax - ymin;
  dot_ratio = (double) po->dpi_y / (double) po->dpi_x;
  po->width = pi->width;
  po->height = pi->height;
  po->xoff = pi->xoff;
  po->yoff = pi->yoff;

  /* Width  assuming given height:      */
  tmp_w = pi->height * Dx / Dy * pi->aspectfactor;
/*  tmp_w     = pi->height * Dx / Dx / pi->aspectfactor; */
  /* Height assuming given width:       */
  tmp_h = pi->width * Dy / Dx / pi->aspectfactor;

  /**
   ** EITHER width OR height MUST be the correct limit. The other will
   ** be adapted. Adaptation of both is inconsistent, except in truesize mode.
   **/

  if (pi->truesize)
    {
      po->width = Dx / 40.0;	/* Ignore -w, take natural HP-GL range  */
      po->height = Dy / 40.0;	/* Ignore -h, take natural HP-GL range  */
      po->HP_to_xdots = (float) (po->dpi_x / 1016.0);	/* dots per HP unit */
      po->HP_to_ydots = (float) (po->dpi_y / 1016.0);	/*  (1/40 mm)       */
      dir_str = "true sizes";
      if (pi->center_mode)
	{
	  fprintf (stderr, "trying to center image\n");
	  fprintf (stderr, "po->width ?<? tmp_w: %f %f\n", po->width, tmp_w);
	  fprintf (stderr, "po->height ?<? tmp_h: %f %f\n", po->height, tmp_h);
	  if (po->width < tmp_w)
	    po->xoff += (tmp_w - po->width) / 2.0;
	  if (po->height < tmp_h)
	    po->yoff += (tmp_h - po->height) / 2.0;
	}

    }
  else
    {
/*    if (po->width > tmp_w) */
      if (Dy > Dx)
	{
	  po->HP_to_ydots = (float) (po->dpi_y * po->height) / Dy / 25.4;
	  po->HP_to_xdots = po->HP_to_ydots * pi->aspectfactor / dot_ratio;
	  if (pi->center_mode)
	    po->xoff += (po->width - tmp_w) / 2.0;	/* by L. Lowe   */
	  po->width = tmp_w;
	  dir_str = "width adapted";	/* Height fits, adjust width    */
	}
      else
	{
	  po->HP_to_xdots = (float) (po->dpi_x * po->width) / Dx / 25.4;
	  po->HP_to_ydots = po->HP_to_xdots * dot_ratio / pi->aspectfactor;
	  if (pi->center_mode)
	    po->yoff += (po->height - tmp_h) / 2.0;	/* by L. Lowe   */
	  po->height = tmp_h;
	  dir_str = "height adapted";	/* Width  fits, adjust height   */
	}
    }

  if (!pg->quiet)
    {
      Eprintf ("\nWidth  x  height: %5.2f x %5.2f mm, %s\n",
	       po->width, po->height, dir_str);
      Eprintf ("Coordinate range: (%g, %g) ... (%g, %g)\n",
	       xmin, ymin, xmax, ymax);
    }

  po->xmin = xmin;
  po->xmax = xmax;
  po->ymin = ymin;
  po->ymax = ymax;
}



PlotCmd PlotCmd_from_tmpfile(void) {
 int cmd;

 if (!silent_mode) ShowPercent(vec_cntr_r++,vec_cntr_w);

 switch (cmd = fgetc (td)) {
  case NOP:
  case MOVE_TO:
  case DRAW_TO:
  case PLOT_AT:
  case SET_PEN:
  case DEF_PW:
  case DEF_PC:
  return cmd;

  case EOF:
  default:
  return CMD_EOF;
 }
}

void HPGL_Pt_from_tmpfile (HPGL_Pt * pf) {
 if (fread ((VOID *) pf, sizeof (*pf), 1, td) != 1) {
  PError ("HPGL_Pt_from_tmpfile");
  Eprintf ("Error @ Cmd %ld\n", vec_cntr_r);
  exit (ERROR);
 }
 if (pf->x < xmin || pf->x > xmax)
   Eprintf ("HPGL_Pt_from_tmpfile: x out of range (%g not in [%g, %g])\n",
   pf->x, xmin, xmax);
 if (pf->y < ymin || pf->y > ymax)
   Eprintf ("HPGL_Pt_from_tmpfile: y out of range (%g not in [%g, %g])\n",
   pf->y, ymin, ymax);
}
Detected encoding: ASCII (7 bit)2