/****************************************************************************/
/*                                                                          */
/*                                  PScript.h                               */
/*                                                                          */
/****************************************************************************/
/****************************************************************************/
/* This is a C language header file that defines some graphical routines    */
/* for generating an executable PostScript language program. This is a very */
/* reduced version of a much larger program and defines only those routines */
/* sufficient for plotting simple magnetograms.                             */
/* The unit of length in all routines is mm (millimeter). Font sizes are in */
/* units of points.                                                         */
/****************************************************************************/
/****************************************************************************/
/*                            Lasse Hakkinen                                */
/*                    Finnish Meteorological Institute                      */
/*                        Department of Geophysics                          */
/*                              P.O.Box 503                                 */
/*                      FIN-00101, Helsinki, Finland                        */
/*                      e-mail: Lasse.Hakkinen@fmi.fi                       */
/*                      phone : (+358)-9-19294634                           */
/*                      fax   : (+358)-9-19294634                           */
/*                                                                          */
/*                      version 1.0     13.11.1995                          */
/****************************************************************************/
/****************************************************************************/
/*  Version history:                                                        */
/*                                                                          */
/*  1.0  13.11.1995 First official release                                  */
/****************************************************************************/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>


/*--------------------------------------------------------------------------*/
/*  Pagewidth defines the width of page. The default value is for A4 paper  */
/*  size. If you are using US letter then change the value into 216.        */
/*--------------------------------------------------------------------------*/

#define PageWidth 210

/*--------------------------------------------------------------------------*/
/*                          Function prototypes                             */
/*--------------------------------------------------------------------------*/

void InitializePS(char *TitleStr, char *CreatorStr, char *CreationDateStr,
                  long xLeft, long yBottom, long xRight, long yTop);
void NewPagePS(long PageNumber);
void ClosePagePS(void);
void ClosePS(void);

void LandscapePS(void);
void TranslatePS(float x, float y);
void RotatePS(float angle);
void ZoomPS(float ZoomFactor);

void FontPS(char *Font,float size);
void TextPS(float x,float y,float angle,char mode,char *TextStr);

void SetGrayPS(float gray);
void SetColorPS(float red,float green,float blue);

void MoveToPS(float x,float y);
void ClosePathPS(void);

void LineWidthPS(float width);
static void Dash2(float LengthTot,long LengthVis,long LengthInvis);
void LineTypePS(long Linetype,float LengthTot);
void LineCapPS(long Param);
void LineJoinPS(long Param);
void LinePS(float x0,float y0,float x1,float y1);
void LineToPS(float x,float y);

void RectPS(float x,float y,float dx,float dy,float angle);
void FillRectPS(float x,float y,float dx,float dy,float angle,
                float gray,long Border);
void FillColorRectPS(float x,float y,float dx,float dy,float angle,
                     float red,float green,float blue,long Border);
void RectClipPS(float x,float y,float dx,float dy);
void InitClipPS();

void CirclePS(float x,float y,float rad);
void FillCirclePS(float x,float y,float rad,float gray,long Border);
void FillColorCirclePS(float x,float y,float rad,
                       float red,float green,float blue,long Border);

void CrossPS(float x,float y,float length);
void XCrossPS(float x,float y,float length);
void FMILogoPS(float x,float y,float size);


/*--------------------------------------------------------------------------*/
/* Write header information and several definitions into stdout. This must  */
/* be the first PS-command to be called from user's C program.              */
/* TitleStr, CreatorStr and CreationDateStr define some useful information  */
/* about the postscript file. They are not absolutely necessary but are     */
/* usually found in a proper Encapsulated Postscript File (EPS).            */
/* The parameters xLeft,yBottom,xRight and yTop define the BoundingBox      */
/* i.e. the rectangle which totally encloses the whole picture. BoundingBox */
/* is needed in an EPS-file.                                                */
/*--------------------------------------------------------------------------*/

void InitializePS(char *TitleStr, char *CreatorStr, char *CreationDateStr,
                  long xLeft, long yBottom, long xRight, long yTop)
{
    /* ---------  Header --------- */
    printf("%%!PS-Adobe-2.0\n");
    printf("%%%%Creator: %s\n",CreatorStr);
    printf("%%%%Title: %s\n",TitleStr);
    printf("%%%%CreationDate: %s",CreationDateStr);
    printf("%%%%BoundingBox: %d %d %d %d\n",xLeft,yBottom,xRight,yTop);
    printf("%%%%EndProlog\n\n");

    /* ----- Some PostScript definitions (abbreviations) ----- */
    printf("/SW {setlinewidth} def\n");
    printf("/M  {moveto} def\n");
    printf("/RM {rmoveto} def\n");
    printf("/L  {lineto} def\n");
    printf("/RL {rlineto} def\n");
    printf("/N  {newpath} def\n");
    printf("/C  {closepath} def\n");
    printf("/CP {currentpoint} def\n");
    printf("/TR {translate} def\n");
    printf("/RO {rotate} def\n");
    printf("/GS {gsave} def\n");
    printf("/GR {grestore} def\n");
    printf("/S  {stroke} def\n");
    printf("/SG {setgray} def\n");
    printf("/LI {newpath moveto lineto stroke} def\n\n");

    /* ----- Text handling definitions ----- */
    printf("/T1 {GS TR RO} def\n");
    printf("/T2 {dup stringwidth pop} def\n");
    printf("/T3 {0 M show GR} def\n");
    printf("/LE {pop 0} def\n");
    printf("/CE {2 div neg} def\n");
    printf("/RI {neg} def\n");
    printf("/FF {findfont} def\n");
    printf("/SS {scalefont setfont} def\n\n");

    /* ----- Rectangle drawing definitions ----- */
    printf("/REC {GS TR RO N 0 0 M dup neg exch 0 exch RL\n");
    printf(" exch 0 RL 0 exch RL C} def\n");
    printf("/RE {REC S GR} def\n");
    printf("/RF {REC SG fill GR} def\n");
    printf("/RB {REC GS SG fill GR S GR} def\n");
    printf("/RFC {REC setrgbcolor fill GR} def\n");
    printf("/RBC {REC GS setrgbcolor fill GR S GR} def\n");
    printf("/RCLIP {N M dup neg exch 0 exch RL\n");
    printf("exch 0 RL 0 exch RL C clip} def\n\n");

    /* ----- Circle drawing definitions ----- */
    printf("/CIR {N 0 360 arc C} def\n");
    printf("/CI {CIR S} def\n");
    printf("/CF {CIR GS SG fill GR} def\n");
    printf("/CB {CIR GS SG fill GR S} def\n");
    printf("/CFC {CIR GS setrgbcolor fill GR} def\n");
    printf("/CBC {CIR GS setrgbcolor fill GR S} def\n\n");

    /* ----- Simple cross and X-cross ----- */
    printf("/CRO {N 0 0 N dup 2 div neg dup 0 RM exch dup 0\n");
    printf(" RL exch dup RM 0 exch RL S GR} def\n");
    printf("/CR {GS TR CRO} def\n");
    printf("/CX {GS TR 45 RO CRO} def\n\n");
    
    /* ----- FMI logo routines -----*/
    printf("/AR {N arc S} def\n");
    printf("/CIRS {-0.326 0 0.451 -80 80 AR\n");
    printf("-0.363 0 0.363 -85 85 AR\n");
    printf("-0.401 0 0.276 -95 95 AR\n");
    printf("-0.422 0 0.174 -110 110 AR\n");
    printf("-0.471 0 0.099 -110 110 AR} def\n");
    printf("/FMILOGO {GS TR dup scale 0.050 SW 0 0 0.5 0 360 AR\n");
    printf("0.044 SW -0.5 0 M 0.5 0 L S CIRS 180 RO CIRS GR} def\n\n");

    /* ----- Some final settings ----- */
    printf("GS\n");     /* save the graphics state */
    printf("%%%% Change units into millimeters\n");
    printf("2.835 2.835 scale\n");  /* Scale 1/72 inches to mm:s */
    printf("%%%% Set global origin\n");
    printf("0 0 TR\n\n");
    printf("%%%% ====== End of Header ====== %%%%\n\n");
}

/*--------------------------------------------------------------------------*/
/* Define the page handling routines. NewPagePS and ClosePagePS must always */
/* appear as a pair in user's program. All drawing routines must be inside  */
/* NewPagePS and ClosePagePS. No PS-commands are allowed between previous   */
/* ClosePagePS and next NewPagePS commands. The user must keep track of the */
/* page number defined in NewPagePS.                                        */
/*--------------------------------------------------------------------------*/

void NewPagePS(long PageNumber)
{
    printf("%%%% Page %d\n\n",PageNumber);
    printf("GS\n");
}

void ClosePagePS(void)
{
    printf("showpage\n");
    printf("GR\n");
}

/*--------------------------------------------------------------------------*/
/* The last PS-command called from user's program must be ClosePS.          */
/*--------------------------------------------------------------------------*/

void ClosePS(void)
{
    printf("GR\n");         /* Restore the graphics state */
    printf("%%%%Trailer\n");
}


/*==========================================================================*/
/*                  Coordinate system manipulation commands                 */
/*==========================================================================*/

void LandscapePS(void)                  /* Turn page into landscape mode    */
    { printf("%d 0 TR 90 RO\n",PageWidth); }

void TranslatePS(float x, float y)      /* Change the origo                 */
    { printf("%.3f %.3f TR\n",x,y); }

void RotatePS(float angle)              /* Rotate the coordinate system     */
    { printf("%.3f RO\n",angle); }

void ZoomPS(float ZoomFactor)           /* Change the scale                 */
    { printf("%.3f %.3f scale\n",ZoomFactor,ZoomFactor); }


/*==========================================================================*/
/*                      Text manipulation routines                          */
/*==========================================================================*/

/*--------------------------------------------------------------------------*/
/*  Set the font size. Note that the unit of size parameter here is points. */
/*--------------------------------------------------------------------------*/

void FontPS(char *Font,float size)
    { printf("/%s FF %.3f SS\n",Font,0.353*size); }

/*--------------------------------------------------------------------------*/
/*  Write a text string into location (x,y) and rotate it by angle degrees. */
/*  Mode defines text alignment: L: left-aligned, C: centered, R:right-     */
/*  aligned.                                                                */
/*--------------------------------------------------------------------------*/

void TextPS(float x,float y,float angle,char mode,char *TextStr)
{
    printf("%.3f %.3f %.3f T1\n",angle,x,y);
    printf("(%s) T2 ",TextStr);
    switch (mode) {
        case 'l' : case 'L' : printf("LE T3\n"); break; /* left aligned  */
        case 'c' : case 'C' : printf("CE T3\n"); break; /* centered      */
        case 'r' : case 'R' : printf("RI T3\n"); break; /* right aligned */
    }
}

/*--------------------------------------------------------------------------*/
/*  Set the pencil color or grayscale. Here gray = 0 is black and gray = 1  */
/*  is white. Values of the colors red, green and blue must be between 0    */
/*  and 1. (0,0,0) is black and (1,1,1) is white.                           */
/*--------------------------------------------------------------------------*/

void SetGrayPS(float gray)
    { printf("%.3f SG\n",gray); }

void SetColorPS(float red,float green,float blue)
    { printf("%.3f %.3f %.3f setrgbcolor\n",red,green,blue); }


/*==========================================================================*/
/*  Some pencil operations. MoveToPS moves the pencil into given location   */
/*  without drawing anything. ClosePathPS causes the current path (= series */
/*  of line segments) to be drawn. Every line drawing (e.g. a magnetogram   */
/*  plot must be started with MoveToPS and ended with ClosePathPS.          */
/*==========================================================================*/

void MoveToPS(float x,float y)
    { printf("N %.3f %.3f M\n",x,y); }

void ClosePathPS(void)
    { printf("S\n"); }


/*==========================================================================*/
/*  Routines that define how lines are drawn.                               */
/*==========================================================================*/

/*--------------------------------------------------------------------------*/
/*  LineWidthPS defines the drawing size of the pencil.                     */
/*--------------------------------------------------------------------------*/

void LineWidthPS(float width)
    { printf("%.3f SW\n",width); }

/*--------------------------------------------------------------------------*/
/*  LineTypePS routine defines the type of the line (continuous, dashed,    */
/*  dotted etc.) Here the line consists of two parts (visible and invisible)*/
/*  which appear periodically one after another. The parameter scale is the */
/*  length of one period. Parameter Linetype may be 0 (continuous line), 1  */
/*  (dashed line with equal lengths), 2 (dashed line with relative length   */
/*  13 and 7), ...                                                          */
/*--------------------------------------------------------------------------*/

static void Dash2(float LengthTot,long LengthVis,long LengthInvis)
{
    float aux;
    
    aux = LengthTot/(LengthVis+LengthInvis);
    printf("%.3f %.3f",LengthVis*aux,LengthInvis*aux);
}

void LineTypePS(long Linetype,float LengthTot)
{
    printf("[");
    switch (Linetype) {
        case 1 : Dash2(LengthTot,1,1);  break;
        case 2 : Dash2(LengthTot,13,7); break;
        case 3 : Dash2(LengthTot,3,1);  break;
        case 4 : Dash2(LengthTot,1,19); break;
        case 5 : Dash2(LengthTot,1,4);  break;
        case 6 : Dash2(LengthTot,1,3);  break;
    }
    printf("] 0 setdash\n");
}

/*--------------------------------------------------------------------------*/
/*  LineCapPS defines how line ends are handled. Param = 0 means that line  */
/*  ends exactly at the end point. Param = 1 means that half of the line    */
/*  width is appended at both ends of the line. Param = 2 means that the    */
/*  ends are rounded with semicircles with radius = width/2.                */
/*--------------------------------------------------------------------------*/

void LineCapPS(long Param)
    { printf("%d setlinecap\n",Param); }

/*--------------------------------------------------------------------------*/
/*  LineJoinPS tells how two lines are connected to each other. Param = 0   */
/*  implies a miter join (sharp corner). Param = 1 means a round join and   */
/*  Param = 2 implies a bevel join.                                         */
/*--------------------------------------------------------------------------*/

void LineJoinPS(long Param)
    { printf("%d setlinejoin\n",Param); }

/*--------------------------------------------------------------------------*/
/*  LinePS draws a straight line from (x0,y0) to (x1,y1).                   */
/*--------------------------------------------------------------------------*/

void LinePS(float x0,float y0,float x1,float y1)
{   /* printf("%.3f %.3f %.3f %.3f LI\n",x1,y1,x0,y0); */
    printf("%.3f %.3f ",x1,y1);
    printf("%.3f %.3f LI\n",x0,y0);
}

/*--------------------------------------------------------------------------*/
/*  LineToPS draws a straight line from current pencil location to (x,y).   */
/*--------------------------------------------------------------------------*/

void LineToPS(float x,float y)
    { printf("%.3f %.3f L\n",x,y); }



/*==========================================================================*/
/*                      Rectangle drawing routines                          */
/*==========================================================================*/

/*--------------------------------------------------------------------------*/
/*  RectPS draws a rectangle with lower left corner at (x,y) and lengths of */
/*  the sides as dx and dy, respectively. Parameter angle defines how much  */
/*  the rectangle is rotated counterclockwise around point (x,y).           */
/*--------------------------------------------------------------------------*/

void RectPS(float x,float y,float dx,float dy,float angle)
{
    printf("%.3f %.3f %.3f %.3f %.3f RE\n",dx,dy,angle,x,y);
}

/*--------------------------------------------------------------------------*/
/*  FillRectPS draws a rectangle with lower left corner at (x,y) and side   */
/*  lengths dx and dy, respectively. Parameter angle defines how much the   */
/*  rectangle is rotated counter clockwise around point (x,y). Also the     */
/*  routine fills the rectangle with gray shade defined by the parameter    */
/*  gray (0 = black, 1 = white). Furthermore the parameter Border tells     */
/*  whether the border of the rectangle is drawn (1) or not (0).            */
/*--------------------------------------------------------------------------*/

void FillRectPS(float x,float y,float dx,float dy,float angle,
                float gray,long Border)
{
    printf("%.3f %.3f %.3f %.3f %.3f %.3f ",gray,dx,dy,angle,x,y);
    if (Border) printf("RB\n"); else printf("RF\n");
}

/*--------------------------------------------------------------------------*/
/*  Same as above but the rectangle is filled with color (red,green,blue)   */
/*  where red, green and blue are all between 0 and 1.                      */
/*--------------------------------------------------------------------------*/

void FillColorRectPS(float x,float y,float dx,float dy,float angle,
                     float red,float green,float blue,long Border)
{
    printf("%.3f %.3f %.3f %.3f %.3f %.3f %.3f %.3f ",
            red,green,blue,dx,dy,angle,x,y);
    if (Border) printf("RBC\n"); else printf("RFC\n");
}

/*--------------------------------------------------------------------------*/
/*  RectClipPS confines all drawing within the given rectangle. Nothing     */
/*  will be drawn outside the rectangle. To remove the clipping use the     */
/*  InitClipPS-routine.                                                     */
/*--------------------------------------------------------------------------*/

void RectClipPS(float x,float y,float dx,float dy)
{
    printf("%.3f %.3f %.3f %.3f RCLIP\n",dx,dy,x,y);
}

void InitClipPS()
    { printf("initclip\n"); }


/*==========================================================================*/
/*                          Circle drawing routines                         */
/*==========================================================================*/

/*--------------------------------------------------------------------------*/
/*  Draw a circle with center point (x,y) and radius rad.                   */
/*--------------------------------------------------------------------------*/

void CirclePS(float x,float y,float rad)
    { printf("%.3f %.3f %.3f CI\n",x,y,rad); }

/*--------------------------------------------------------------------------*/
/*  Draw a circle with center point (x,y) and radius rad. Also fill the     */
/*  circle with gray shade defined by parameter gray. Parameter Border      */
/*  defines whether the border is drawn (1) or not (0).                     */
/*--------------------------------------------------------------------------*/

void FillCirclePS(float x,float y,float rad,float gray,long Border)
{
    printf("%.3f %.3f %.3f %.3f ",gray,x,y,rad);
    if (Border) printf("CB\n"); else printf("CF\n");
}

/*--------------------------------------------------------------------------*/
/*  Same as above but the circle is filled with color (red,green,blue)      */
/*  where red, green and blue are all between 0 and 1.                      */
/*--------------------------------------------------------------------------*/

void FillColorCirclePS(float x,float y,float rad,
                       float red,float green,float blue,long Border)
{
    printf("%.3f %.3f %.3f %.3f %.3f %.3f ",red,green,blue,x,y,rad);
    if (Border) printf("CBC\n"); else printf("CFC\n");
}


/*==========================================================================*/
/*                      Plotting various marks                              */
/*==========================================================================*/

void CrossPS(float x,float y,float length)
    { printf("%.3f %.3f %.3f CR\n",length,x,y); }

void XCrossPS(float x,float y,float length)
    { printf("%.3f %.3f %.3f CX\n",length,x,y); }

void FMILogoPS(float x,float y,float size)
    { printf("%.3f %.3f %.3f FMILOGO\n",size,x,y); }

