 /*
  * Khoros: $Id: postscript.c,v 1.3 1991/12/18 09:09:20 dkhoros Exp $
  */

#if !defined(lint) && !defined(SABER)
static char rcsid[] = "Khoros: $Id: postscript.c,v 1.3 1991/12/18 09:09:20 dkhoros Exp $";
#endif

 /*
  * $Log: postscript.c,v $
 * Revision 1.3  1991/12/18  09:09:20  dkhoros
 * HellPatch3
 *
  */ 


/*
 *----------------------------------------------------------------------
 *
 * Copyright 1990, University of New Mexico.  All rights reserved.
 *
 * Permission to copy and modify this software and its documen-
 * tation only for internal use in your organization is hereby
 * granted, provided that this notice is retained thereon and
 * on all copies.  UNM makes no representations as too the sui-
 * tability and operability of this software for any purpose.
 * It is provided "as is" without express or implied warranty.
 * 
 * UNM DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE,
 * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FIT-
 * NESS.  IN NO EVENT SHALL UNM BE LIABLE FOR ANY SPECIAL,
 * INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY OTHER DAMAGES WHAT-
 * SOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS
 * ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PER-
 * FORMANCE OF THIS SOFTWARE.
 * 
 * No other rights, including for example, the right to redis-
 * tribute this software and its documentation or the right to
 * prepare derivative works, are granted unless specifically
 * provided in a separate license agreement.
 *---------------------------------------------------------------------
 */

#include "unmcopyright.h"	 /* Copyright 1990 by UNM */
#include "X3D.h"


/* >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
   >>>>                                                       <<<<
   >>>>	    file name: postscript.c
   >>>>               
   >>>>   description: Postscript Utilities
   >>>>              
   >>>>      routines:
   >>>>			X3D_set_postscript()		      <<<<
   >>>>                                                       <<<<
   >>>>			Postscript_DrawLine()		      <<<<
   >>>>			Postscript_DrawLines()		      <<<<
   >>>>			Postscript_DrawSegments()	      <<<<
   >>>>			Postscript_DrawRectangle()	      <<<<
   >>>>			Postscript_DrawArc()		      <<<<
   >>>>			Postscript_FillPolygon()	      <<<<
   >>>>			Postscript_close_device()	      <<<<
   >>>>			Postscript_set_line_width()	      <<<<
   >>>>			Postscript_set_line_type()	      <<<<
   >>>>			Postscript_set_draw()    	      <<<<
   >>>>			Postscript_set_fill()		      <<<<
   >>>>			Postscript_DrawPolygon()	      <<<<
   >>>>			Postscript_DrawText()		      <<<<
   >>>>			Postscript_FillArc()		      <<<<
   >>>>			Postscript_FillRectangle()	      <<<<
   >>>>              
   >>>> modifications:
   >>>>                                                       <<<<
   >>>>>>>>>>>>>>>>>>>>>>>>>>>>> <<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< */

#define XFACTOR 1.0
#define YFACTOR 1.0

/************************************************************
*
*  MODULE NAME:  X3D_set_postscript
*
*      PURPOSE:  Output to postscript file
*
*        INPUT:  id - xvgraphics id
*		 file - ImPress file to be sent to ImPress printer 
*		 width - width of output (on paper)
*		 height - height of output (on paper)
*		 xoffset - X offset from upper left hand corner (of paper)
*		 yoffset - Y offset from upper left hand corner (of paper)
*		 overlay - Don't force page output 
*		 landscape - landscape mode (horizontal output)
*		 monochrome - monochrome or color output
*		 invert - invert output
*    CALLED BY:  application program
*
*   WRITTEN BY:  Mike Lang & Mark Young
*
*
*************************************************************/


int X3D_set_postscript(id, file, width, height, xoffset, yoffset, overlay,
		   landscape, monochrome, invert, bg)

int     id, overlay, landscape, monochrome, invert;
FILE	*file;
float	width, height, xoffset, yoffset;
XColor  *bg;
{
	X3DGraphics     *graphics;

	time_t		time(), clock;
	char		*ctime();
	Real		red, green, blue;
	int		llx, lly, urx,  ury, burx, bury;


	if (!(graphics = _X3D_get_graphics(id)))
	{
	   fprintf (stderr,"X3D_set_postscript:");
	   fprintf (stderr,"\t unknown graphics id %d\n",id);
	   return(FALSE);
	}

	graphics->device = POSTSCR;
	graphics->pfile   = file;
	graphics->POS_mono   = monochrome;
	graphics->POS_invert = invert;

	llx = (int) xoffset * 72.0;
	lly = (int) yoffset * 72.0;
	urx = (int) width * 72.0;
	ury = (int) height * 72.0;
	burx = urx + llx;
	bury = ury + lly;

	 /* 
	  * assume we have a 300dpi printer.
	  * so 72 * 4.167  = 300
 	  */

	X3D_set_window(id, 0, 0, 
			   (short) (urx * 4.167),
			   (short) (ury * 4.167));

	if(graphics->pfile != NULL)
	{
	   (void) time(&clock);
	   (void) fprintf(file,"\
%%!PS-Adobe-2.0 EPSF-1.2\n\
%%%%Creator: XPrism\n\
%%%%Title: XPrism Postscript Plot Document\n\
%%%%CreationDate: %s\
%%%%Pages: 1\n\
%%%%BoundingBox: %d %d %d %d\n\
%%%%EndComments\n\
save\n\
%%%%EndProlog\n\
%%%%Page: 1 1\n", ctime(&clock), llx, lly, burx, bury);


	   if (bg == NULL)
	   {
	      red =
	      green =
	      blue =  1.0;
	   }
	   else
	   {
	      red = ((Real) bg->red)/65535;
	      green = ((Real) bg->green)/65535;
	      blue = ((Real) bg->blue)/65535;
	   }

	   if (invert)
	   {
	      red = 1.0 - red;
	      green = 1.0 - green;
	      blue = 1.0 - blue;
	   }
	   (void) fprintf(file,"%0.3f %0.3f %0.3f setrgbcolor\n", (float) red,
			(float) green, (float) blue); 
	   (void) fprintf(file,"3 setlinewidth 1 setlinecap\n");
	   (void) fprintf(file,"1 setlinejoin\n");
	   (void) fprintf(file,"/l {lineto} def /r {rlineto} def /m {moveto} def /s {stroke} def \n");

	   if (landscape == 1) /* if it is zero then it is landscape */
           {
               (void) fprintf(file,"90 rotate\n");
               (void) fprintf(file,"0 -%d translate\n", ury);
	       (void) fprintf(file,"/plotpath {newpath 0 0 m 0 %d l %d %d l %d 0 l closepath } def\n", 
		  ury,urx,ury,urx);
	       (void) fprintf(file,"%d -%d translate\n", lly, llx);
	       (void) fprintf(file,"plotpath clip fill\n");
           }
	   else
           {
	       (void) fprintf(file,"/plotpath {newpath 0 0 m 0 %d l %d %d l %d 0 l closepath } def\n", 
		  ury,urx,ury,urx);
	       (void) fprintf(file,"%d %d translate\n", llx, lly);
	       (void) fprintf(file,"plotpath clip fill\n");
	   }

	   (void) fprintf(file,"0.24 0.24 scale\n");
	}
	else
	{
	   fprintf (stderr,"X3D_set_postscript:");
	   fprintf (stderr,"\t unknown graphics file pointer");
	   return(FALSE);
	}
	return(TRUE);
}



/************************************************************
*
*  MODULE NAME:  Postscript_DrawLine
*
*      PURPOSE: Draw a single line for an postscript device
*
*        INPUT:  graphics - graphics structure
*
*       OUTPUT: displays a line to postscript device
*
*    CALLED BY: graphics routines
*
*   WRITTEN BY: Mike Lang
*
*************************************************************/

void Postscript_DrawLine (graphics, p1x, p1y, p2x, p2y)

X3DGraphics *graphics;
short   p1x, p1y, p2x, p2y;
{
	fprintf(graphics->pfile,"%g %g m\n%g %g l\ns\n", 
			(float)p1x/XFACTOR, (float)p1y/YFACTOR, 
			(float)p2x/XFACTOR, (float)p2y/YFACTOR);
}



/************************************************************
*
*  MODULE NAME:  Postscript_DrawLines
*
*      PURPOSE:  Draw a series of lines for a postscript device
*
*        INPUT:  graphics - graphics structure
*
*       OUTPUT: displays a a set of lines to an postscript device
*
*    CALLED BY: graphics routines
*
*   WRITTEN BY: Mike Lang
*
*************************************************************/

void Postscript_DrawLines (graphics, points, size, coordmode)

X3DGraphics *graphics;
int     coordmode, size;
XPoint  *points;
{
	int	i;

	if(coordmode == CoordModeOrigin)
	{
	   fprintf(graphics->pfile,"%g %g m\n", 
			(float)points[0].x/XFACTOR, 
			(float)points[0].y/YFACTOR);
	   for(i = 1; i < size; i++)
	   {
	      fprintf(graphics->pfile,"%g %g l\n", 
			(float)points[i].x/XFACTOR, 
			(float)points[i].y/YFACTOR);
	      if(i%100 == 0)
	      {
	        fprintf(graphics->pfile,"s %g %g m\n",
			(float)points[i].x/XFACTOR, 
			(float)points[i].y/YFACTOR);
	      }
	   }
	}
	else if(coordmode == CoordModePrevious)
	{
	   fprintf(graphics->pfile,"%g %g m\n",
			(float)points[0].x/XFACTOR, 
			(float)points[0].y/YFACTOR);
	   for(i = 1; i < size; i++)
	   {
	      fprintf(graphics->pfile,"%g %g r\n",
			(float)points[i].x/XFACTOR, 
			(float)points[i].y/YFACTOR);
	      if(i%100 == 0) 
	      {
	        fprintf(graphics->pfile,"s %g %g m\n",
			(float)points[i].x/XFACTOR, 
			(float)points[i].y/YFACTOR);
	      }
	   }
	}
	fprintf(graphics->pfile,"s\n");
}



/************************************************************
*
*  MODULE NAME:  Postscript_DrawSegments
*
*      PURPOSE: Draw a series of disjoint segments for a postscript device
*
*        INPUT:  graphics - graphics structure
*
*       OUTPUT: displays a a set of segments to a postscript device
*
*    CALLED BY: graphics routines
*
*   WRITTEN BY: Mike Lang
*
*************************************************************/

void Postscript_DrawSegments (graphics, segments, seg_num)

X3DGraphics *graphics;
int	 seg_num;
XSegment *segments;
{
	int		i;

	for(i = 0; i < seg_num; i++)
	{
	   fprintf(graphics->pfile,"%g %g m\n%g %g l\n", 
			(float)segments[i].x1/XFACTOR, 
			(float)segments[i].y1/YFACTOR, 
			(float)segments[i].x2/XFACTOR, 
			(float)segments[i].y2/YFACTOR);
	   if(i%100 == 0) fprintf(graphics->pfile,"s\n");
	}
	fprintf(graphics->pfile,"s\n");
}



/************************************************************
*
*  MODULE NAME:  Postscript_DrawRectangle
*
*      PURPOSE: Draw a rectangle to a postscript device
*
*        INPUT:  graphics - graphics structure
*
*       OUTPUT: displays a rectangle to a postscript device
*
*    CALLED BY: graphics routines
*
*   WRITTEN BY: Mike Lang
*
*************************************************************/

void Postscript_DrawRectangle (graphics, x, y, w, h)

X3DGraphics *graphics;
int      x, y, w, h;
{
	fprintf(graphics->pfile,"%g %g m\n", 
			(float)x/YFACTOR, (float)y/YFACTOR); 
	fprintf(graphics->pfile,"%g 0  r\n", (float)w/XFACTOR); 
	fprintf(graphics->pfile,"0 %g r\n", (float)-h/YFACTOR); 
	fprintf(graphics->pfile,"%g 0 r\n", (float)-w/XFACTOR); 
	fprintf(graphics->pfile,"0 %g r\n", (float)h/YFACTOR); 
	fprintf(graphics->pfile,"s\n"); 
}



/************************************************************
*
*  MODULE NAME:  Postscript_DrawArc
*
*      PURPOSE:  Draw an arc (circle) for a postscript device
*		 x,y are the upper left corner of the bounding box
*		 of the circle ang1 & ang2 are the start and
*		 finish angles in degrees
*
*        INPUT:  graphics - graphics structure
*
*    CALLED BY: graphics routines
*
*   WRITTEN BY: Mike Lang
*
*************************************************************/

void Postscript_DrawArc (graphics, x, y, w, h, ang1, ang2) 

X3DGraphics *graphics;
int      x, y, ang1, ang2;
int     w, h;
{
	float		scale, rad, width, height;

	width = (float)w/XFACTOR; 
	height = (float)h/YFACTOR; 
	rad   =  width/2.0 + .5;
	scale = width/height;

	fprintf(graphics->pfile,"gsave\nnewpath\n1.0 %f scale\n",scale);
	fprintf(graphics->pfile,"%g %g %g %d %d arc\ns\ngrestore\n",
			(float) x, (float) y, rad, ang1, ang2);
}



/************************************************************
*
*  MODULE NAME:  Postscript_FillPolygon
*
*      PURPOSE:  Uses the proper graphics routines to draw an arc
*
*        INPUT:  graphics - graphics structure
*
*       OUTPUT: displays a line (or a set of lines) to graphics workstation
*
*    CALLED BY: graphics routines
*
*   WRITTEN BY: Mike Lang
*
*************************************************************/


void Postscript_FillPolygon (graphics, points, size, shape, coordmode)

X3DGraphics *graphics;
int     size, shape, coordmode;
XPoint  *points;
{
	int		i;

	fprintf(graphics->pfile,"newpath\n");
	if (coordmode == CoordModeOrigin)
	{
	   fprintf(graphics->pfile,"%g %g m\n",
			(float)points[0].x/XFACTOR,
			(float)points[0].y/YFACTOR);
	   for(i = 1; i < size; i++)
	      fprintf(graphics->pfile,"%g %g l\n",
			(float)points[i].x/XFACTOR, 
			(float)points[i].y/YFACTOR);
	}
	else if (coordmode == CoordModePrevious)
	{
	   fprintf(graphics->pfile,"%g %g m\n",
			(float)points[0].x/XFACTOR,
			(float)points[0].y/YFACTOR);
	   for(i = 1; i < size; i++)
	      fprintf(graphics->pfile,"%g %g r\n",
			(float)points[i].x/XFACTOR, 
			(float)points[i].y/YFACTOR);
	}
	fprintf(graphics->pfile,"closepath fill\n");
}



/************************************************************
*
*  MODULE NAME:  Postscript_close_device
*
*      PURPOSE:  
*
*        INPUT:  graphics - graphics structure
*
*    CALLED BY:  application program
*
*   WRITTEN BY:  Mike Lang & Mark Young
*
*
*************************************************************/


void Postscript_close_device(graphics)

X3DGraphics *graphics;
{
	fprintf(graphics->pfile,"showpage\nrestore\n");
	fprintf(graphics->pfile,"%%%%Trailers\n%%%%EOF\n");
}



/************************************************************
*
*  MODULE NAME:  Postscript_set_line_width
*
*      PURPOSE:  set the line width before drawing
*
*        INPUT: graphics - graphics context
* 		line_width - the line width as specified in xvgraphics.h
*
*    CALLED BY:  application program
*
*
*   WRITTEN BY:  Tom Sauer
*
*
*************************************************************/


void Postscript_set_line_width(graphics,line_width)

X3DGraphics *graphics;
int	    line_width;
{

	fprintf(graphics->pfile,"%f setlinewidth\n",
                                    line_widths[line_width][graphics->device]);

}

/************************************************************
*
*  MODULE NAME:  Postscript_set_line_type
*
*      PURPOSE:  set the line type before drawing
*
*        INPUT: graphics - graphics context
* 		line_type - the line type as specified in xvgraphics.h
*
*    CALLED BY:  application program
*
*
*   WRITTEN BY:  Tom Sauer
*
*
*************************************************************/


void Postscript_set_line_type(graphics,line_type)

X3DGraphics *graphics;
int	    line_type;
{

        /* Change the line type this is based on a user
	 * coordinate system in inches 
	 */

        graphics->line_type = line_type;

        fprintf(graphics->pfile,"[ ");
        switch (line_type) 
	{
                case Dotted:
                        fprintf(graphics->pfile," 2 6 2 6 2 6 2 6 ");
                        break;
                case DotDash:
                        fprintf(graphics->pfile," 18 6 2 6 ");
                        break;
                case ShortDash:
                        fprintf(graphics->pfile," 8 8 8 8 ");
                        break;
                case LongDash:
                        fprintf(graphics->pfile," 16 16 ");
                        break;
                case OddDash:
                        fprintf(graphics->pfile," 14 6 6 6 ");
                        break;
                case Grid_Dotted:
                        fprintf(graphics->pfile," 2 4 2 4 2 4 2 4 2 4 ");
                        break;
                case Solid:
                default:
                        break;
        }

        fprintf(graphics->pfile,"] 0 setdash\n");
}



/************************************************************
*
*  MODULE NAME:  Postscript_set_draw
*
*      PURPOSE:  Set the foreground draw color.
*
*        INPUT:  graphics - graphics context
*	         fg	  - foreground color
*		 override - whether the background color can
*			    be overriden.
*
*    CALLED BY:  application program
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

void Postscript_set_draw(graphics, fg, override)

X3DGraphics     *graphics;
XColor		*fg;
int		override;
{
	Real	red, green, blue;

	if (graphics->POS_mono && override == FALSE)
	{
	   red   =
	   green =
	   blue  = 1.0;
	}
	else
	{
	   red   = ((Real) fg->red)/65536;
	   green = ((Real) fg->green)/65536;
	   blue  = ((Real) fg->blue)/65536;
	}

	if (graphics->POS_invert)
	{
	   red   = 1.0 - red;
	   green = 1.0 - green;
	   blue  = 1.0 - blue;
	}
	fprintf(graphics->pfile,"%.3f %.3f %.3f setrgbcolor\n",
			(float) red, (float) green, (float) blue);
}



/************************************************************
*
*  MODULE NAME:  Postscript_set_fill
*
*      PURPOSE:  Set the background fill color.
*
*        INPUT:  graphics - graphics context
*	         bg	  - background color
*		 override - whether the background color can
*			    be overriden.
*
*    CALLED BY:  application program
*
*   WRITTEN BY:  Mark Young
*
*
*************************************************************/

void Postscript_set_fill(graphics, bg, override)

X3DGraphics     *graphics;
XColor		*bg;
int		override;
{
	Real	red, green, blue;

	if (graphics->POS_mono && override == FALSE)
	{
	   red   =
	   green =
	   blue  = 0.0;
	}
	else
	{
	   red   = ((Real) bg->red)/65536;
	   green = ((Real) bg->green)/65536;
	   blue  = ((Real) bg->blue)/65536;
	}

	if (graphics->POS_invert)
	{
	   red   = 1.0 - red;
	   green = 1.0 - green;
	   blue  = 1.0 - blue;
	}
	fprintf(graphics->pfile,"%.3f %.3f %.3f setrgbcolor\n",
			(float) red, (float) green, (float) blue);
}



/************************************************************
*
*  MODULE NAME:  Postscript_DrawPolygon
*
*      PURPOSE:  Draw a filled polygon.
*
*        INPUT:  graphics - graphics structure
*	         points   - points to be drawn
*	         size     - number of points
*
*   WRITTEN BY:
*
*
*************************************************************/

void Postscript_DrawPolygon(graphics, points, size)

X3DGraphics     *graphics;
XPoint		*points;
int		size;
{
}



/************************************************************
*
*  MODULE NAME:  Postscript_DrawText
*
*      PURPOSE:  Draw text at the given position.
*
*        INPUT:  graphics - graphics structure
*	         x	  - x position
*	         y	  - y position
*		 font	  - font to be used
*	         text	  - text to be printed
*	         size	  - size of text array
*
*   WRITTEN BY: Mike Lang & Mathew Yeates
*
*
*************************************************************/

void Postscript_DrawText(graphics, x, y, font, text, size)

X3DGraphics     *graphics;
char		*font;
char		*text;
int		x, y, size;
{
	static char *deffont="/Times-Roman";
	static char *symfont="/Symbol";

	char temp[LENGTH], *usefont = deffont;


	if (font != NULL)
	{
	   vlower_string(font, temp);
	   if (vstrstr(temp, "symbol") != NULL)
	      usefont = symfont;
	}

	fprintf(graphics->pfile,"%s findfont 60 scalefont setfont\n",usefont);
	fprintf(graphics->pfile,"%g %g m\n(%s)show\n",
			(float)x/XFACTOR,(float)y/YFACTOR,text);
}



/************************************************************
*
*  MODULE NAME:  Postscript_FillArc
*
*      PURPOSE: Draw a filled arc.
*
*        INPUT:  graphics - graphics structure
*	         x	  - of upper left corner
*	         y	  - of upper left corner
*	         w	  - width of Arc
*	         h	  - height of Arc
*	         arc1	  - start angle
*	         arc2	  - end angle
*
*   WRITTEN BY:
*
*
*************************************************************/

void Postscript_FillArc(graphics, x, y, w, h, ang1, ang2)

X3DGraphics	*graphics;
int		x, y, ang1, ang2;
unsigned int	w, h;
{
	float		rad,width, height, scale;
	

	width = (float)w/XFACTOR; 
	height = (float)h/YFACTOR; 
	rad   =  width/2.0 + .5;
	scale = width/height;

	fprintf(graphics->pfile,"gsave\nnewpath\n1.0 %f scale\n",scale);
	fprintf(graphics->pfile,"%g %g %g %d %d arc fill\n",
			(float) x, (float) y, rad, ang1, ang2);
	fprintf(graphics->pfile,"closepath\ngrestore\n");
}



/************************************************************
*
*  MODULE NAME:  Postscript_FillRectangle
*
*      PURPOSE:  Draw a filled rectangle.
*
*        INPUT:  graphics - graphics structure
*	         x	  - of upper left corner
*	         y	  - of upper left corner
*	         w	  - width of rectangle
*	         h	  - height of rectangle
*
*   WRITTEN BY:
*
*
*************************************************************/

void Postscript_FillRectangle(graphics, x, y, w, h)

X3DGraphics     *graphics;
int		x, y, w, h;
{
	fprintf(graphics->pfile,"newpath\n");
	fprintf(graphics->pfile,"%g %g m\n", (float)x/XFACTOR,(float)y/XFACTOR);
	fprintf(graphics->pfile,"%g 0  r\n", (float)w/XFACTOR); 
	fprintf(graphics->pfile,"0 %g r\n", (float)-h/YFACTOR); 
	fprintf(graphics->pfile,"%g 0 r\n", (float)-w/XFACTOR); 
	fprintf(graphics->pfile,"0 %g r\n", (float)h/YFACTOR); 
	fprintf(graphics->pfile,"closepath fill \n"); 
}
