DataMuseum.dk

Presents historical artifacts from the history of:

DKUUG/EUUG Conference tapes

This is an automatic "excavation" of a thematic subset of
artifacts from Datamuseum.dk's BitArchive.

See our Wiki for more about DKUUG/EUUG Conference tapes

Excavated with: AutoArchaeologist - Free & Open Source Software.


top - metrics - download
Index: T f

⟦add32e57d⟧ TextFile

    Length: 26888 (0x6908)
    Types: TextFile
    Names: »fig2ps.p«

Derivation

└─⟦060c9c824⟧ Bits:30007080 DKUUG TeX 2/12/89
    └─⟦this⟧ »./tex82/TeXgraphics/transfig/fig2ps/fig2ps.p« 

TextFile

program fig2ps (input, output);
{      Author: 	Igor Metz <metz@iam.unibe.ch> }
{     Created:	Thu Jan  7 16:11:38 1988 }
{    Filename:	/usr/u-gina/metz/work/fig2ps/fig2ps.p }

{ This program translates files, that were created with FIG 1.3.1, to 
  PostScript. The PostScript code generated can be incorporated into TeX 
  with psfig. 
 
 Current version: 1.13
  Revision History: 
    Feb., 09. 88: (Igor Metz)
      - in procedure read_object the linewidth and lineheight were read in
        reversed order (for arcs). Same error below!!
      - Reported by Andreas Ueltschi: the procedure calc_tangent calculated 
        wrong coordinates!
    Feb., 08. 88: (Igor Metz)
      - in procedure read_object the linewidth and lineheight were read in
        reverse order (for lines and splines)!
    Feb., 03. 88: (Igor Metz)
      - the procedure write_string now prefixes '(' and ')' with a backslash
        to prevent troubles, when strings to be printed contain '(' or ')'.
    Jan., 27. 88: (Igor Metz)
      - support for spline has been added.
    Jan., 27. 88: (Igor Metz)
      - the adaptation of linewidths for ellipses was a bit strange. The new
        method is to save the CTM before scaling, and to restore be CTM before
	stroking.
      - the drawing had to be shifted to the left on the page, since printers
        can't print on the entire page.
    Jan., 26. 88: (Igor Metz)
      - for dashed lines and arcs the arrow head was also dashed: bug is 
        fixed.
      - the position of the drawing on the page has been corrected.
      - the linewidth for ellipses and circles had to be adapted, since
        we scale the coordinate system when we print them.
    Feb. 18 88: (Micah Beck)
      - increased resolution of spline rendering for 300 BPI printing.
	the code taken from Fig assumes 80 BPI.
      - fixed a bug in closed splines: there was no initial moveto command
    Feb. 23 88: (Micah Beck)
      - scale the figure by 72/pixels_per_inch to get correct size
      - translate lower left corner of figure to PS origin
}
const
  { the following generic object codes are taken from fig/object.h }
  ELLIPSE  = 1;
  POLYLINE = 2;
  SPLINE   = 3;
  TEXT     = 4;
  ARC      = 5;
  COMPOUND = 6;
  END_COMPOUND = -COMPOUND;

  { the following definitions are taken from fig/choices.h. They define }
  { the values the object component 'typ' can have. }
  DRAW_ELLIPSE_BY_RAD 	= 1;
  DRAW_ELLIPSE_BY_DIA 	= 2;
  DRAW_CIRCLE_BY_RAD 	= 3;
  DRAW_CIRCLE_BY_DIA 	= 4;
  DRAW_CIRCULAR_ARC	= 5;
  DRAW_POLYLINE		= 6;
  DRAW_BOX		= 7;
  DRAW_POLYGON		= 8;
  DRAW_TEXT		= 9;
  DRAW_SPLINE		= 10;
  DRAW_CLOSEDSPLINE	= 11;
  DRAW_COMPOUND		= 13;

  SOLID_LINE	= 0;
  DASH_LINE	= 1;
  DOTTED_LINE	= 2;  { not use by FIG 1.3.1 }

  MaxTextLength = 256;  { max. length of texts in Fig-file (assumed!) }
  pi = 3.141592654;
  TOP_LEFT_Y = 820; { used for coordinate transformation FIG <-> PostScript }
  TOP_LEFT_X =  10;

type
  objtype = (ellipse, polyline, spline, txt, arc, compound, end_compound);

  pPoint = ^tPoint;
  tPoint = record 
     	    x,y : integer;
     	    next: pPoint
     	  end; {record}

  tPosition = record x,y : integer end;

  tEllipse  = record
     	        typ, style : integer;
     	        thickness   : integer;
     	        dash_length : real;
     	        direction   : integer;
     	        center,
     	        radiuses,
     	        start,
     	        ending      : tPosition;
     	      end; {record}

  tPolyline = record
     	        typ, style : integer;
     	        thickness   : integer;
     	        dash_length : real;
     	        f_arrow     : integer;
     	        b_arrow     : integer;
     	        arrow_width,
     	        arrow_height: integer;
     	        start       : pPoint;
     	      end; {record}

tSpline  = record
     	        typ, style : integer;
     	        thickness   : integer;
     	        dash_length : real;
     	        f_arrow     : integer;
     	        b_arrow     : integer;
     	        arrow_width,
     	        arrow_height: integer;
     	        start       : pPoint;
     	      end; {record}

tText = record
     	  font,
     	  size,
     	  style   : integer;
	  height  : integer;
	  length  : integer;
     	  corner  : tPosition;
     	  chars   : packed array [1..MaxTextLength] of char;
     	end; {record}

tArc = record
     	  typ, style : integer;
     	  thickness   : integer;
     	  dash_length  : real;
     	  direction   : integer;
     	  f_arrow     : integer;
     	  b_arrow     : integer;
     	  arrow_width,
     	  arrow_height: integer;
     	  center_x,
     	  center_y    : real;
     	  pos         : array [1..3] of tPosition;
     	end; {record}

pObject = ^tObject;
tObject = record 
     	   next : pObject;
     	   case objname : objtype of
     	   ellipse  : (ell : tEllipse);
     	   polyline : (poly: tPolyline);
     	   spline   : (spl : tSpline);
     	   txt      : (tex : tText);
     	   arc      : (arq : tArc);
     	  end;

var
  filename : packed array[1..128] of char;
  Objects : pObject;  { list of objects found in the Fig-file }

  { the following 4 variables are in the Fig-file's header. They have }
  { always the same values, so we could define them as constants. }
  pixels_per_inch : integer;  { always = 80 }
  origin : integer;           { always = ? }
  canvas_width, canvas_height : integer; { always = 600 and = 800 }

  { coordinates that determine the bounding box of a drawing }
  llx, lly, urx, ury : real;


 procedure read_string (var str : array [lb .. ub : integer] of char);
 { read all charcters from current position to end of line. Trailing }
 { blanks are also read, since they could be part of the string. }
 var
     i : integer;
     ch : char; 
 begin
     i:= lb;
     read(ch); { the first character is always blank! skip it }
     while not eoln(input) do begin
     	  read( str[i]);
	  i:= i+1;
     end {while};
     str[i]:= chr(0); { terminate string with null character }
 end { read_string };

 procedure write_string (str : array [lb .. ub : integer] of char);
 { write all characters in str }
 
 var
     i : integer;
 begin
     i:= lb;
     while str[i] <> chr(0) do begin
      	  if (str[i]='(') or (str[i]=')') then write('\');
     	  write(str[i]);
	  i:= i+1;
     end {while};
 end { write_string };

 function min (a, b : real) : real;
 begin
   if a < b then min:= a else min:= b;
 end { min };

 function max (a,b : real) : real;
 begin
   if a < b then max:= b else max:= a;
 end { max };

 procedure read_file( var Objects : pObject);
 { read in the Fig-file from input, and build up a list of all object in }
 { the file. While reading keep track of the bounding box. }
 var
   obj_code : integer;
   Object : pObject;

   procedure read_object (obj : objtype; var Object : pObject);
   { read in the object 'obj' and store it's data in 'Object' }
   
   var
     tmp : integer;

     procedure read_points (var point : pPoint);
     { read in all points (coordinate pairs). The end is marked by the }
     { (9999,9999). }
     
     var
     	  last : pPoint; { points to last point in the list }
	  aux  : pPoint; { auxiliary }
	  x_tmp, y_tmp : integer;
     begin
     	  last:= point;
	  while not eoln(input) do begin
	       read(x_tmp, y_tmp);
	       if (x_tmp <> 9999) and (y_tmp <> 9999) then begin
		  new(aux); { create new node }
		  with aux^ do begin
		       next:= nil;
		       x:= x_tmp; y:= y_tmp;
		  end {with};
		  if last=nil then begin
		       { the list is empty, aux becomes first node }
		       point:= aux;
		       last:= aux;
		  end
		  else begin
		       { append aux at end of list }
		       last^.next:= aux;
		       last:= aux;
		  end { if };
	       end { if };
	  end {while};
     end { read_points };

   begin
     new(Object); 
     with Object^ do begin
     	next:= nil;
	objname:= obj;
	case obj of
	     ellipse : with ell do begin
			      read(typ, style,thickness,dash_length,direction);
			      read(center.x, center.y);
			      read(radiuses.x , radiuses.y);
			      read(start.x, start.y);
			      read(ending.x, ending.y);
		       end {with};
	     polyline : with poly do begin
			      read(typ, style, thickness, dash_length);
			      read(f_arrow, b_arrow, arrow_height,arrow_width);
			      read_points(start);
			 end {with};
	     spline : with spl do begin
			      read(typ, style, thickness, dash_length);
			      read(f_arrow, b_arrow, arrow_height,arrow_width);
			      read_points(start);
		      end {with};
	     txt : with tex do begin
		    	 read(font, size, style, height, length);
			 read(corner.x, corner.y);
			 read_string(chars);
		    end {with};
	     arc : with arq do begin
		    	 read(typ, style, thickness, dash_length, direction);
			 read(f_arrow, b_arrow, arrow_height, arrow_width);
			 read(center_x, center_y);
			 read(pos[1].x, pos[1].y);
			 read(pos[2].x, pos[2].y);
			 read(pos[3].x, pos[3].y);
		    end {with};
	     compound : read(tmp, tmp, tmp, tmp); { we ignore this info }
	     end_compound : { do nothing }
	end {case};
	readln; { skip end-of-line character }
     end {with};

     if (obj=compound) or (obj=end_compound) then begin
     	  { since we ignore compounds, we can throw away this node }
	  dispose(Object);
	  Object:= nil;
     end { if };
   end { read_object };

   procedure insert_object (Object : pObject; var Objects : pObject);
   { insert the new 'Object' into the list of 'Objects'. The new object }
   { is inserted at the front of the list. }
   
   var
     aux : pObject;
   begin
     if Object <> nil then begin
     	  aux:= Objects;
	  Objects:= Object;
	  Object^.next:= aux;
     end { if };
   end { insert_object };

 begin
     Objects:= nil;
     { first read in the fileheader. }
     readln( pixels_per_inch, origin, canvas_width, canvas_height );

     while not eof(input) do begin
        read(obj_code);
	case obj_code of
	  ELLIPSE  : read_object(ellipse, Object);
	  POLYLINE : read_object(polyline, Object);
	  SPLINE   : read_object(spline, Object);
	  TEXT     : read_object(txt, Object);
	  ARC      : read_object(arc, Object);
	  COMPOUND : read_object(compound, Object);
	  END_COMPOUND : read_object(end_compound, Object);
	end {case};
	insert_object(Object, Objects);
     end; {while}
 end; {read_line}

 procedure compute_bbox (Objects : pObject; var llx, lly, urx, ury : real);
 { compute the bounding box that surrounds the objects. }
 { If we want to compute the bounding box, we must never forget the following }
 { facts: }
 { Fig's coordinate system is :  PostScript's (default) coordinate system is:}
 { (0,0) -------> (x,0)            (0,y) ---------> (x,y)}
 {   |              |                ^                ^  }
 {   V              V                |                |  }
 { (0,y) -------> (x,y)            (0,0) ---------> (x,0) }
 var
   p : pObject;
   lx, ly, ux, uy : real;
   tmp : real;
   
   procedure bbox (Object : pObject; var llx, lly, urx, ury : real);
   { compute the bounding box of a single object }
   var
     p : pPoint;
     delta : real;
   begin
     with Object^ do begin
	case objname of
	     ellipse : with ell do begin
	       	     	 llx:= center.x - radiuses.x;
			 lly:= center.y - radiuses.y;
	       	     	 urx:= center.x + radiuses.x;
			 ury:= center.y + radiuses.y;
	       	       end {with};
	     polyline : with poly do begin
	       	     	  llx:= maxint; lly:= maxint;
			  urx:= minint; ury:= minint;
			  p:= start;
			  while p <> nil do begin
			   llx:= min(llx, p^.x);   lly:= min(lly, p^.y);
			   urx:= max(urx, p^.x);   ury:= max(ury, p^.y);
			   p:= p^.next;
			  end {while};
			  
			  { do not forget the arrow heads !}
			  delta:= 0.5*arrow_width;
			  llx:= llx - delta;  lly:= lly - delta;
			  urx:= urx + delta;  ury:= ury + delta;
			end {with};
	     spline : with spl do begin
	       { the same as for polyline }
	       	     	  llx:= maxint; lly:= maxint;
			  urx:= minint; ury:= minint;
			  p:= start;
			  while p <> nil do begin
			   llx:= min(llx, p^.x);   lly:= min(lly, p^.y);
			   urx:= max(urx, p^.x);   ury:= max(ury, p^.y);
			   p:= p^.next;
			  end {while};
			  
			  { do not forget the arrow heads !}
			  delta:= 0.5*arrow_width;
			  llx:= llx - delta;  lly:= lly - delta;
			  urx:= urx + delta;  ury:= ury + delta;
		      end {with};
	     txt : with tex do begin
	       	     llx:= corner.x;
		     lly:= corner.y - height;
		     urx:= corner.x + length;
		     ury:= corner.y;
		   end {with};
	     arc : with arq do begin
	       	     delta:= 0.5*arrow_width;
		     llx:= min(min(pos[1].x, pos[2].x), pos[3].x) - delta;
		     lly:= min(min(pos[1].y, pos[2].y), pos[3].y) - delta;
	       	     urx:= max(max(pos[1].x, pos[2].x), pos[3].x) + delta;
		     ury:= max(max(pos[1].y, pos[2].y), pos[3].y) + delta;
                   end {with};
	     otherwise { do nothing }
	end {case};
     end {with};
   end { bbox };
   
 begin
   p:= Objects;
   llx:= maxint;  lly:= maxint; 
   urx:= minint;  ury:= minint;
   
   while p <> nil do begin
      bbox(p, lx, ly, ux, uy);
      llx:= min(llx, lx);      lly:= min(lly, ly);
      urx:= max(urx, ux);      ury:= max(ury, uy);
      p:= p^.next;
   end {while};

   { now we transform from FIG coordinates to PostScript (default) coordinates}
     tmp:= lly;
     llx:= llx + TOP_LEFT_X;
     lly:= TOP_LEFT_Y - ury;
     urx:= urx  + TOP_LEFT_X;
     ury:= TOP_LEFT_Y - tmp;
 end { compute_bbox };

 procedure generate_postscript (Objects : pObject;
      	       	     	        llx, lly, urx, ury : real);
 { Generate PostScript Code for the list of Objects. }
 
 var
   p : pObject; 
   current_dashlength : real;
   current_thickness  : integer;

   procedure header;
   { Write header. }
   begin
      writeln('%!');
      writeln('%%BoundingBox: 0 0 ',
		((urx-llx) * 72/pixels_per_inch):6:4, ' ',
		((ury-lly) * 72/pixels_per_inch):6:4);
      { the following text must be the same as in ./header.ps !!!! }
      writeln('gsave');
      writeln('/fig2psdict 20 dict def');
      writeln('fig2psdict begin');
      writeln('72 ', pixels_per_inch:6:0, ' div dup scale');
      writeln(TOP_LEFT_X,TOP_LEFT_Y, ' translate');
      writeln(-llx:6:0, -lly:6:0, ' translate');
      writeln('/mtrx matrix currentmatrix def');
      writeln('180 rotate');
      writeln('[-1 0 0 1 0 0] concat');
      writeln('/arrowhead');
      writeln(' { /headlength exch def');
      writeln(' /halfheadheight exch 2 div def');
      writeln(' /tipy exch def');
      writeln(' /tipx exch def');
      writeln(' /taily exch def');
      writeln(' /tailx exch def');
      writeln(' /angle tipy taily sub tipx tailx sub atan def');
      writeln(' /savematrix matrix currentmatrix def');
      writeln(' tipx tipy translate');
      writeln(' angle 90 add rotate');
      writeln(' halfheadheight headlength moveto');
      writeln(' 0 0 lineto');
      writeln(' halfheadheight neg headlength lineto');
      writeln(' savematrix setmatrix');
      writeln('} def');
      writeln('/printtext ');
      writeln(' { /txt exch def');
      writeln(' /width exch def');
      writeln(' /height exch def');
      writeln(' /y exch def');
      writeln(' /x exch def');
      writeln(' gsave');
      writeln(' /Courier findfont height scalefont setfont');
      writeln(' /Courier findfont ');
      writeln(' [ width txt stringwidth pop div height mul 0 0 height 0 0] makefont');
      writeln(' setfont');
      writeln(' x y moveto');
      writeln(' mtrx setmatrix');
      writeln(' txt show');
      writeln(' grestore');
      writeln('} def');
      
      writeln;
   end { header };

   procedure generate (Object : pObject);
   { Generate PostScript Code for a single Object. }
   
   var
      p,             { points to actual point }
      q,             { points to last point }
      r : pPoint;    { points to before last point }
      x0, y0 : integer; { point of contact of arc and tangent }
      x, y : real;   { point on tangent }
      radius : real; { of an arc }

      procedure calc_tangent (var x,y : real;    { point on tangent }
      	       	     	      x0, y0 : integer;  { point of contact }
			      xc, yc : real;     { center of arc }
			      x2, y2 : integer); { point on arc }
      { calculates a point (x,y) on the tangent which touches the arc in }
      { point (x0,y0). }
      var
      	 l : real;      { length of direction vector }
	 xn, yn : real; { components of direction vector }
	 s : real;      { scalar product }
	 dx, dy : real;

      begin
        dx:= (x0-xc);  dy:= - (y0-yc);
        l:= sqrt(dx*dx + dy*dy);
	xn:= dy / l;
	yn:= dx / l;
	s:= (x2-x0)*xn + (y2-y0)*yn;
	x:= s*xn + x0;
	y:= s*yn + y0;
      end { calc_tangent };

      procedure chaikin_spline (x1, y1, x2, y2, x3, y3, x4, y4 : real);
      {	The following spline drawing routine is from 

	"An Algorithm for High-Speed Curve Generation" 
	by George Merrill Chaikin,
	Computer Graphics and Image Processing, 3, Academic Press, 
	1974, 346-349.

	and

	"On Chaikin's Algorithm" by R. F. Riesenfeld,
	Computer Graphics and Image Processing, 4, Academic Press, 
	1975, 304-310.

        but I took it from fig/splsub.c 
	}
	var
	 xmid, ymid : real;
      begin
      	xmid := (x2 + x3) * 0.5;  ymid := (y2 + y3) * 0.5;
	if (abs(x1 - xmid) < 1) and (abs(y1 - ymid) < 1) then begin
	    writeln(xmid:6:4, ' ', ymid:6:4, ' lineto');
	end
      	else begin
	    chaikin_spline(x1, y1, ((x1 + x2) * 0.5),  ((y1 + y2) * 0.5),
			((3.0*x2 + x3) * 0.25), ((3.0*y2 + y3) * 0.25), 
			xmid, ymid);
        end; {if}
	if (abs(xmid - x4) < 1) and (abs(ymid - y4) < 1)  then begin
	   writeln(x4:6:4, ' ', y4:6:4, ' lineto');
	end
	else begin
	    chaikin_spline(xmid, ymid, 
			((x2 + 3*x3) / 4),  ((y2 + 3*y3) / 4),
			((x3 + x4) / 2),  ((y3 + y4) / 2), x4, y4);
	end { if };
      end { chaikin_spline };

      procedure draw_openspline (spl : tSpline);
      var
      	cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4 : real;
	x1, y1, x2, y2 : real;
	p : pPoint;
      begin
      	 with spl do begin
	    p:= start;
	    if current_thickness <> thickness then begin
	      writeln(thickness, ' setlinewidth');
	      current_thickness:= thickness;
	    end { if };

	    x1 := p^.x;  y1 := p^.y;
	    p := p^.next;
	    x2 := p^.x;  y2 := p^.y;
	    cx1 := (x1 + x2) * 0.5;      cy1 := (y1 + y2) * 0.5;
	    cx2 := (x1 + 3 * x2) * 0.25;  cy2 := (y1 + 3 * y2) * 0.25;
	    if b_arrow = 1 then begin
	       { generate backward arrow }
	       writeln('newpath');
	       writeln(x2:6:4, ' ', y2:6:4, ' ', x1:6:4, ' ', y1:6:4, ' ', 
		       arrow_width, arrow_height, ' arrowhead');
	       writeln('stroke');
	    end { if };

	    writeln('newpath');
	    if style <> SOLID_LINE then begin
	       writeln('[3] 0 setdash');
	    end { if };

	    writeln(x1:6:4, ' ', y1:6:4, ' moveto');
	    writeln(cx1:6:4, ' ', cy1:6:4, ' lineto');

	    p:= p^.next;
	    while p <> nil do begin
		x1 := x2;  y1 := y2;
		x2 := p^.x;  y2 := p^.y;
		cx3 := (3 * x1 + x2) * 0.25;  cy3 := (3 * y1 + y2) * 0.25;
		cx4 := (x1 + x2) * 0.5;      cy4 := (y1 + y2) * 0.5;
		chaikin_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
		cx1 := cx4;  cy1 := cy4;
		cx2 := (x1 + 3 * x2) * 0.25;  cy2 := (y1 + 3 * y2) * 0.25;
		p:= p^.next;
	    end {while};

	    writeln(cx1:6:4, ' ', cy1:6:4, ' moveto');
	    writeln(x2:6:4, ' ', y2:6:4, ' lineto');
	    writeln(' stroke');

	    if style <> SOLID_LINE then begin
	      writeln('[] 0 setdash');
	    end { if };

	    if f_arrow = 1 then begin
	       { forward arrow }
	       writeln('newpath');
	       writeln(x1:6:4, ' ', y1:6:4, ' ', x2:6:4, ' ', y2:6:4, ' ', 
		       arrow_width, arrow_height, ' arrowhead');
	       writeln('stroke');
	    end { if };
	 end {with};
      end { draw_openspline };

      procedure draw_closedspline (spl : tSpline);
      var
      	 cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4 : real;
	 x1, y1, x2, y2 : real;
	 p : pPoint;
      begin
      	 with spl do begin
	    writeln('newpath');
	    if style <> SOLID_LINE then begin
	       writeln('[3] 0 setdash');
	    end { if };

	    p:= start;
	    x1 := p^.x;  y1 := p^.y;
	    p := p^.next;
	    x2 := p^.x;  y2 := p^.y;
	    cx1 := (x1 + x2) * 0.5;      cy1 := (y1 + y2) * 0.5;
	    cx2 := (x1 + 3 * x2) * 0.25;  cy2 := (y1 + 3 * y2) * 0.25;

	    writeln(cx1:6:4, ' ', cy1:6:4, ' moveto');

	    p:= p^.next;
	    while p <> nil do begin
	       x1 := x2;  y1 := y2;
	       x2 := p^.x;  y2 := p^.y;
	       cx3 := (3 * x1 + x2) * 0.25;  cy3 := (3 * y1 + y2) * 0.25;
	       cx4 := (x1 + x2) * 0.5;      cy4 := (y1 + y2) * 0.5;
	       chaikin_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
	       cx1 := cx4;  cy1 := cy4;
	       cx2 := (x1 + 3 * x2) * 0.25;  cy2 := (y1 + 3 * y2) * 0.25;
	       p:= p^.next;
	    end {while};

	    x1 := x2;  y1 := y2;
	    p := start^.next;
	    x2 := p^.x;  y2 := p^.y;
	    cx3 := (3 * x1 + x2) * 0.25;  cy3 := (3 * y1 + y2) * 0.25;
	    cx4 := (x1 + x2) * 0.5;      cy4 := (y1 + y2) * 0.5;
	    chaikin_spline(cx1, cy1, cx2, cy2, cx3, cy3, cx4, cy4);
	    writeln(' stroke');

	    if style <> SOLID_LINE then begin
	      writeln('[] 0 setdash');
	    end { if };
	 end {with};
      end { draw_closedspline };

   begin
     with Object^ do begin
	case objname of
	     ellipse : with ell do begin
	       	     	 writeln('gsave');
			 if current_thickness <> thickness then begin
			   writeln(thickness, ' setlinewidth');
			   current_thickness:= thickness;
			 end { if };
			 if style <> SOLID_LINE then begin
			   writeln('[3] 0 setdash');
			 end { if };
			 
			 writeln('newpath');
			 writeln('/savematrix matrix currentmatrix def');
			 writeln(center.x, center.y,' translate');
			 writeln(radiuses.x, radiuses.y, ' scale');
			 writeln('0 0 1 0 360 arc');
			 writeln('savematrix setmatrix');
			 writeln('stroke');
			 writeln('grestore');
			 if style <> SOLID_LINE then begin
			   writeln('[] 0 setdash');
			 end { if };
	       	       end {with};
	     polyline : with poly do begin
			   if current_thickness <> thickness then begin
			     writeln(thickness, ' setlinewidth');
			     current_thickness:= thickness;
			   end { if };

			   p:= start;
			   q:= nil;
			   r:= nil;
			   if (b_arrow = 1) then begin
			      { generate backward arrow }
			      if p <> nil then begin
			         { at least 2 points available }
			      	 q:= p^.next;
				 writeln('newpath');
				 writeln(q^.x, q^.y, p^.x, p^.y, arrow_width,
				         arrow_height, ' arrowhead');
		     	      	 writeln('stroke');
			      end
			      else begin
			      	 { line consists of only 1 point ! }
				 message('warning: line with only 1 point!');
			      end { if };
			   end { if };

			   writeln('newpath');
			   if style <> SOLID_LINE then begin
			      writeln('[3] 0 setdash');
			   end { if };

			   writeln(p^.x, p^.y,' moveto');
			   q:= p;
			   p:= p^.next;
			   while p <> nil do begin
			      writeln(p^.x, p^.y,' lineto');
			      r:= q;
			      q:= p;
			      p:= p^.next;
			   end {while};

			   writeln('stroke');

			   if style <> SOLID_LINE then begin
			     writeln('[] 0 setdash');
			   end { if };

			   if f_arrow = 1 then begin
			      { forward arrow }
			      writeln('newpath');
			      writeln(r^.x, r^.y, q^.x, q^.y, arrow_width,
				         arrow_height, ' arrowhead');
			      writeln('stroke');
			   end { if };
			 end {with};
	     spline : begin
      	       	     	if spl.typ = DRAW_SPLINE then begin
			   draw_openspline(spl);
			end
			else begin
			   draw_closedspline(spl);
			end { if };
		      end {begin};
	     txt : with tex do begin
	       	     write(corner.x, corner.y, height, length, ' (');
		     write_string(chars);
		     writeln(') printtext');
		   end {with};
	     arc : with arq do begin
		      if current_thickness <> thickness then begin
			writeln(thickness, ' setlinewidth');
			current_thickness:= thickness;
		      end { if };
		      if style <> SOLID_LINE then begin
		      	writeln('[3] 0 setdash');
		      end { if };

		      writeln('newpath');
		      radius:= sqrt((pos[1].x -center_x)*(pos[1].x- center_x)+
		      	      	    (pos[1].y -center_y)*(pos[1].y- center_y));
		      if direction=0 then begin
		      	{clockwise}
		      	writeln(pos[1].x, pos[1].y, ' moveto');
		      	writeln(center_x:6:4, ' ', center_y:6:4, ' ', 
			      	radius:6:4, ' ',
				(pos[1].y - center_y):6:4, ' ',
				(pos[1].x - center_x):6:4, ' atan ',
				(pos[3].y - center_y):6:4, ' ',
				(pos[3].x - center_x):6:4, ' atan arc');
		      end
		      else begin
		      	{counter clockwise}
		      	writeln(pos[3].x, pos[3].y, ' moveto');
		      	writeln(center_x:6:4, ' ', center_y:6:4, ' ', 
			      	radius:6:4, ' ',
				(pos[3].y - center_y):6:4, ' ',
				(pos[3].x - center_x):6:4, ' atan ',
				(pos[1].y - center_y):6:4, ' ',
				(pos[1].x - center_x):6:4, ' atan arc');
		      end { if };

		      if style <> SOLID_LINE then begin
			writeln('[] 0 setdash');
		      end { if };
		      writeln('stroke');

		      if f_arrow=1 then begin
		      	if direction=0 then begin
			   {clockwise}
			   x0:= pos[3].x;
			   y0:= pos[3].y;
			end
			else begin
			   {counter clockwise}
			   x0:= pos[1].x;
			   y0:= pos[1].y;
			end { if };
			calc_tangent(x, y, x0, y0, center_x, center_y,
			      	     pos[2].x, pos[2].y);
			writeln('newpath');
			writeln(x:6:4, ' ', y:6:4, x0, y0, arrow_width, 
			      	 arrow_height, ' arrowhead');
		     	writeln('stroke');
		      end { if };

		      if b_arrow=1 then begin
		      	if direction=0 then begin
			   {clockwise}
			   x0:= pos[1].x;
			   y0:= pos[1].y;
			end
			else begin
			   {counter clockwise}
			   x0:= pos[3].x;
			   y0:= pos[3].y;
			end { if };
			calc_tangent(x, y, x0, y0, center_x, center_y,
			      	     pos[2].x, pos[2].y);
			writeln('newpath');
			writeln(x:6:4,' ', y:6:4, x0, y0, arrow_width, 
			      	 arrow_height, ' arrowhead');
		     	writeln('stroke');
		      end { if };
		   end {with};
	     otherwise { do nothing }
	end {case};
     end {with};
   end { generate };

   procedure trailer;
   { Write Trailer. }
   begin
    writeln('showpage');
    writeln('end % fig2psdict');
    writeln('grestore');
   end { trailer };

 begin
     p:= Objects;
     current_dashlength:= maxint;
     current_thickness:= maxint;
     header;
     while p <> nil do begin
     	  generate(p);
	  p:= p^.next;
     end {while};
     trailer;
 end { generate_postscript };

begin {fig2ps}
   if argc <> 2 then
      message('usage: fig2ps filename > filename')
   else begin
     { get the filename, and open the file for reading }
     argv(1,filename);
     reset(input, filename);
     read_file(Objects);
     compute_bbox(Objects, llx, lly, urx, ury);
     generate_postscript(Objects, llx, lly, urx, ury);
   end; {if}
end. {fig2ps}