[comp.sources.x] v03i074: xgraph -- graph points and functions, Part05/06

argv@island.uu.net (Dan Heller) (04/11/89)

Submitted-by: David Harrison <davidh@ic.berkeley.edu>
Posting-number: Volume 3, Issue 74
Archive-name: xgraph/part05

#!/bin/sh
# to extract, remove the header and type "sh filename"
if `test ! -d ./xgraph-11`
then
  mkdir ./xgraph-11
  echo "mkdir ./xgraph-11"
fi
if `test ! -s ./xgraph-11/dot.11`
then
echo "writing ./xgraph-11/dot.11"
cat > ./xgraph-11/dot.11 << '\End\Of\Shar\'
#define dot_width 8
#define dot_height 8
static char dot_bits[] = {
   0x00, 0x3c, 0x7e, 0x7e, 0x7e, 0x7e, 0x3c, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/dot.11"
fi
if `test ! -s ./xgraph-11/hard_devices.c`
then
echo "writing ./xgraph-11/hard_devices.c"
cat > ./xgraph-11/hard_devices.c << '\End\Of\Shar\'
/*
 * Hardcopy Devices
 *
 * This file contains the basic output device table.  The hardcopy
 * dialog is automatically constructed from this table.
 */

#include "copyright.h"
#include "hard_devices.h"

extern int hpglInit();
extern int psInit();

struct hard_dev hard_devices[] = {
    { "HPGL", hpglInit, "lpr -P%s", "xgraph.hpgl", "paper",
	27.5, "1", 14.0, "1", 12.0 },
    { "Postscript", psInit, "lpr -P%s", "xgraph.ps", "lps40",
	19.0, "Times-Bold", 18.0, "Times-Roman", 12.0 }
};

int hard_count = sizeof(hard_devices)/sizeof(struct hard_dev);
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/hard_devices.c"
fi
if `test ! -s ./xgraph-11/hard_devices.h`
then
echo "writing ./xgraph-11/hard_devices.h"
cat > ./xgraph-11/hard_devices.h << '\End\Of\Shar\'
/*
 * Hardcopy Device Header
 *
 * This file declares the types required for the hardcopy table
 * found in hard_devices.c.
 */

#define MFNAME	25

typedef struct hard_dev {
    char *dev_name;		/* Device name                */
    int (*dev_init)();		/* Initialization function    */
    char *dev_spec;		/* Default pipe program       */
    char dev_file[MFNAME];	/* Default file name          */
    char dev_printer[MFNAME];	/* Default printer name       */
    double dev_max_dim;		/* Default maximum dimension (cm)    */
    char dev_title_font[MFNAME];/* Default name of title font        */
    double dev_title_size;	/* Default size of title font (pnts) */
    char dev_axis_font[MFNAME];	/* Default name of axis font         */
    double dev_axis_size;	/* Default size of axis font (pnts)  */
};

extern int hard_count;
extern struct hard_dev hard_devices[];
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/hard_devices.h"
fi
if `test ! -s ./xgraph-11/hpgl.c`
then
echo "writing ./xgraph-11/hpgl.c"
cat > ./xgraph-11/hpgl.c << '\End\Of\Shar\'

#define MAPX(state,x) ( (x) + P1X + state->clipminX ) 
#define MAPY(state,y) ( MAXY - (y) + P1Y - state->clipminY)

#include "copyright.h"
#include "xgout.h"
#include "plotter.h"
#include <stdio.h>
#include <math.h>
#define MAX(a,b) ( ((a)>(b)) ? (a) : (b) )
#define MIN(a,b) ( ((a)<(b)) ? (a) : (b) )
char *malloc();

extern void exit();
extern void free();

static void hpglText();
static void hpglSeg();
static void hpglDot();
static void hpglEnd();

static xgOut hpglInfo = {
    D_COLOR,    /* device characteristics */
    MAXX,   /* width */
    MAXY,   /* height */
    200,    /* border padding */
    0,      /* extra space around axis labels */
    250,    /* tick length - approx 1/4 inch */
    50,	    /* spacing above legend lables */
    0,      /* axis font width */
    0,      /* axis font height */
    0,      /* title font width */
    0,      /* title font height */
	1000000,/* maximum number of segments */

    hpglText,   /* text output function */
    hpglSeg,    /* segment  drawing function */
    hpglDot,    /* dot/marker drawing function */
    hpglEnd,    /* end of plot function */

    NULL,   /* userInfo */
};

typedef struct {
	double axis_w;
	double axis_h;
	double title_w;
	double title_h;
	FILE *plotterFile;
	int clipminX;
	int clipminY;
	int clipmaxX;
	int clipmaxY;
} mydata;

int
hpglInit(stream,width,height,title_family, title_size,
		axis_family, axis_size, outInfo,errmsg)
    FILE *stream;	/* output stream */
	int width;		/* desired width of space in microns */
	int height;		/* desired height in microns */
	char *title_family;	/* name of font for titles */
	double title_size;	/* size of font for titles */
	char *axis_family;	/* name of font for axes */
	double axis_size;	/* size of font for axes */
    xgOut *outInfo;	/* my structure */
	char errmsg[ERRBUFSIZE];	/* a place to complain to */
{
    char *cmd;
	mydata *myInfo;

	myInfo = (mydata*)malloc(sizeof(mydata));
	if(myInfo == NULL) return(NULL);
    *outInfo = hpglInfo;
	outInfo->area_w = MIN(MAXX,width/25);
	outInfo->area_h = MIN(MAXY,height/25);
	/* magic formulas:  input sizes are in points = 1/72 inch */
	/* my sizes are in cm */
	/* plotter units are in units of .025mm ~= 1/1016 inch */
	/* have to warn of height 1.5 times larger or get bitten by
	   plotter's internal padding */
	/* widths are (arbitrarily) selected to be 2/3 of the height */
	/*     (cancels with width factor) */
	myInfo->axis_w = axis_size * .666 * 2.54/72.;
	myInfo->axis_h = axis_size * 2.54/72.;
	myInfo->title_w = title_size * .666 * 2.54/72.;
	myInfo->title_h = title_size * 2.54/72.;

    outInfo->axis_pad = axis_size*1016.*1.5/72.;
    outInfo->axis_width = axis_size*1016.*1.5/72.;
    outInfo->axis_height = axis_size*1016.*.666/72.;
    outInfo->title_width = title_size*1016.*1.5/72.;
    outInfo->title_height = title_size*1016.*.666/72.;
    outInfo->user_state = (char *)myInfo;
	myInfo->plotterFile = stream;
    myInfo->clipminX = 0;
    myInfo->clipminY = 0;
    myInfo->clipmaxX = MAXX;
    myInfo->clipmaxY = MAXY;
	fprintf(myInfo->plotterFile,"PG;IN;\n");
	fprintf(myInfo->plotterFile,"DI1,0;\n");
    fprintf(myInfo->plotterFile,"IW%d,%d,%d,%d;\n",MAPX(myInfo,0),
			MAPY(myInfo,myInfo->clipmaxY-myInfo->clipminY),
            MAPX(myInfo,myInfo->clipmaxX-myInfo->clipminX),
			MAPY(myInfo,0));
    return(1);
}

static void 
hpglClip(userState,ulx,uly,lrx,lry)
    mydata *userState;    /* my state information  */
    int ulx,uly,lrx,lry;    /* corners of plotting area */
{
    userState->clipminX = ulx;
    userState->clipminY = uly;
    userState->clipmaxX = lrx;
    userState->clipmaxY = lry;
    fprintf(userState->plotterFile,"IW%d,%d,%d,%d;\n",MAPX(userState,0),
			MAPY(userState,userState->clipmaxY-userState->clipminY),
            MAPX(userState,userState->clipmaxX-userState->clipminX),
			MAPY(userState,0));
    return;
}

static void 
hpglText(userState,x,y,text,just,style)
    mydata *userState;    /* my state information  */
    int x,y;    /* coords of text origin */
    char *text; /* what to put there */
    int just;   /* how to justify */
    /* where the origin is relative to where the text should go
     * as a function of the various values of just 

    T_UPPERLEFT     T_TOP       T_UPPERRIGHT
    T_LEFT          T_CENTER    T_RIGHT
    T_LOWERLEFT     T_BOTTOM    T_LOWERRIGHT

    */
    int style;  /* T_AXIS = axis font, T_TITLE = title font */

{
    fprintf(userState->plotterFile,"PU;SP%d;",TEXTCOLOR);
    fprintf(userState->plotterFile,"PA%d,%d;",MAPX(userState,x),MAPY(userState,y));
    switch(style) {
        case T_AXIS:
            fprintf(userState->plotterFile,"SI%f,%f;",userState->axis_w,userState->axis_h);
            break;
        case T_TITLE:
            fprintf(userState->plotterFile,"SI%f,%f;",userState->title_w,userState->title_h);
            break;
        default:
            printf("bad text style %d in hpglText\n",style);
            exit(1);
            break;
    }
    switch(just) {
        case T_UPPERLEFT:
            fprintf(userState->plotterFile,"LO3;\n");
            break;
        case T_TOP:
            fprintf(userState->plotterFile,"LO6;\n");
            break;
        case T_UPPERRIGHT:
            fprintf(userState->plotterFile,"LO9;\n");
            break;
        case T_LEFT:
            fprintf(userState->plotterFile,"LO2;\n");
            break;
        case T_CENTER:
            fprintf(userState->plotterFile,"LO5;\n");
            break;
        case T_RIGHT:
            fprintf(userState->plotterFile,"LO8;\n");
            break;
        case T_LOWERLEFT:
            fprintf(userState->plotterFile,"LO1;\n");
            break;
        case T_BOTTOM:
            fprintf(userState->plotterFile,"LO4;\n");
            break;
        case T_LOWERRIGHT:
            fprintf(userState->plotterFile,"LO7;\n");
            break;
        default:
            printf("bad justification type %d in hpglText\n",just);
            exit(1);
            break;
    }
    fprintf(userState->plotterFile,"LB%s\03;",text);
}



static int penselect[8] = { PEN1, PEN2, PEN3, PEN4, PEN5, PEN6, PEN7, PEN8};
static int lineselect[8] = { LINE1, LINE2, LINE3, LINE4, LINE5, LINE6, 
        LINE7, LINE8};



static void 
hpglSeg(userState,ns,segs,width,style,lappr,color)
    mydata *userState;    /* my state information (not used) */
    int ns;         /* number of segments */
    XSegment *segs; /* X array of segments */
    int width;      /* width of lines in pixels */
    int style;      /* L_VAR = dotted, L_AXIS = grid, L_ZERO = axis*/
    int lappr;      /* line style */
    int color;      /* line color */
{
    int i;

    if (style == L_ZERO) {
        fprintf(userState->plotterFile,"SP%d;",PENAXIS); /* select correct pen */
        fprintf(userState->plotterFile,"LT;"); /* solid line style */
    } else if (style == L_AXIS) {
        fprintf(userState->plotterFile,"SP%d;",PENGRID); /* select correct pen */
        fprintf(userState->plotterFile,"LT;"); /* solid line style */
    } else if (style == L_VAR) {
        if( (color < 0) || (color >7) ) {
            printf("out of range line color %d in hpglLine\n",color);
            exit(1);
        }
        fprintf(userState->plotterFile,"SP%d;",penselect[color]); /* select correct pen */
        if( (lappr < 0) || (lappr >7) ) {
            printf("out of range line style %d in hpglLine\n",lappr);
            exit(1);
        }
        if(lappr == 0) {
            fprintf(userState->plotterFile,"LT;");/*select solid line type*/
        } else {
            fprintf(userState->plotterFile,"LT%d;",lineselect[lappr]);/*select line type*/
        }
    } else {
        printf("unknown style %d in hpglLine\n",style);
        exit(1);
    }
    for(i=0;i<ns;i++) {
		if(!i || ( (segs[i].x1!=segs[i-1].x2) || (segs[i].y1!=segs[i-1].y2) ) ){
            /* MOVE */
            fprintf(userState->plotterFile,"PU;PA%d,%d;\n",MAPX(userState,segs[i].x1),
                    MAPY(userState,segs[i].y1));
        }
		/* DRAW */
		if(width <= 1) {
			fprintf(userState->plotterFile,"PD;PA%d,%d;\n",MAPX(userState,segs[i].x2),
					MAPY(userState,segs[i].y2));
		} else { /* ugly - wide lines -> rectangles */
			double frac;
			int lx,ly;
			int urx,ury,ulx,uly,llx,lly,lrx,lry;

			frac = (width/2)/sqrt((double)
					((segs[i].x1-segs[i].x2)*
					(segs[i].x1-segs[i].x2))+
					((segs[i].y1-segs[i].y2)*
					(segs[i].y1-segs[i].y2)) );
			lx = frac * (segs[i].y2 - segs[i].y1);
			ly = -frac * (segs[i].x2 - segs[i].x1);
			urx = segs[i].x2 +lx;
			ury = segs[i].y2 +ly;
			ulx = segs[i].x2 -lx;
			uly = segs[i].y2 -ly;
			llx = segs[i].x1 -lx;
			lly = segs[i].y1 -ly;
			lrx = segs[i].x1 +lx;
			lry = segs[i].y1 +ly;
			fprintf(userState->plotterFile,"PU;PA%d,%d;",MAPX(userState,llx),
					MAPY(userState,lly));
			fprintf(userState->plotterFile,"PM0;");
			fprintf(userState->plotterFile,"PD,PA%d,%D;PA%d,%D;PA%d,%d;\n",
				MAPX(userState,lrx),MAPY(userState,lry),
				MAPX(userState,urx),MAPY(userState,ury),
				MAPX(userState,ulx),MAPY(userState,uly) );
			fprintf(userState->plotterFile,"PM2;FP;EP;");
		}
    }
	fprintf(userState->plotterFile,"PU;");
}

static char *markselect[8] = { MARK1, MARK2, MARK3, MARK4, MARK5, MARK6, 
        MARK7, MARK8};

static void 
hpglDot(userState,x,y,style,type,color)
    mydata *userState;    /* my state information (not used) */
    int x,y;    /* coord of dot */
    int style;  /* type of dot */
    int type;   /* dot style variation */
    int color;  /* color of dot */
{
    /* move to given coord */
    fprintf(userState->plotterFile,"PU;PA%d,%d;\n",MAPX(userState,x), MAPY(userState,y));
    if( (color<0) || (color>7) ) {
        printf("unknown color %d in hpglDot\n",color);
        exit(1);
    }
    fprintf(userState->plotterFile,"SP%d;",penselect[color]);
    if(style == P_PIXEL) {
        fprintf(userState->plotterFile,"PD;PU;\n");
    } else if (style == P_DOT) {
        fprintf(userState->plotterFile,"LT;PM0;CI40;PM2;FT;EP;\n");
    } else if (style == P_MARK) {
        if( (type<0) || (type>7) ) {
            printf("unknown marker type %d in hpglDot\n",type);
            exit(1);
        }
        /*fprintf(userState->plotterFile,"LT;CA5;LO4;SI0.1;LB%s\03;\n",markselect[type]);*/
		fprintf(userState->plotterFile,"LT;CS5;LO4;SI0.15;SM%s;PR0,0;SM;CS;\n",markselect[type]);
    } else {
        printf("unknown marker style %d in hpglDot\n",style);
        exit(1);
    }
}

static void 
hpglEnd(userState)
    mydata *userState;    /* my state information (not used) */

{
	fprintf(userState->plotterFile,"SP;PG;IN;\n");
    fflush(userState->plotterFile);
    return;
}
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/hpgl.c"
fi
if `test ! -s ./xgraph-11/mark1.11`
then
echo "writing ./xgraph-11/mark1.11"
cat > ./xgraph-11/mark1.11 << '\End\Of\Shar\'
#define mark1_width 8
#define mark1_height 8
#define mark1_x_hot 3
#define mark1_y_hot 3
static char mark1_bits[] = {
   0x00, 0x00, 0x1c, 0x1c, 0x1c, 0x00, 0x00, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/mark1.11"
fi
if `test ! -s ./xgraph-11/mark2.11`
then
echo "writing ./xgraph-11/mark2.11"
cat > ./xgraph-11/mark2.11 << '\End\Of\Shar\'
#define mark2_width 8
#define mark2_height 8
#define mark2_x_hot 3
#define mark2_y_hot 3
static char mark2_bits[] = {
   0x00, 0x3e, 0x22, 0x22, 0x22, 0x3e, 0x00, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/mark2.11"
fi
if `test ! -s ./xgraph-11/mark3.11`
then
echo "writing ./xgraph-11/mark3.11"
cat > ./xgraph-11/mark3.11 << '\End\Of\Shar\'
#define mark3_width 8
#define mark3_height 8
#define mark3_x_hot 3
#define mark3_y_hot 3
static char mark3_bits[] = {
   0x00, 0x1c, 0x36, 0x22, 0x36, 0x1c, 0x00, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/mark3.11"
fi
if `test ! -s ./xgraph-11/mark4.11`
then
echo "writing ./xgraph-11/mark4.11"
cat > ./xgraph-11/mark4.11 << '\End\Of\Shar\'
#define mark4_width 8
#define mark4_height 8
#define mark4_x_hot 3
#define mark4_y_hot 3
static char mark4_bits[] = {
   0x00, 0x22, 0x14, 0x08, 0x14, 0x22, 0x00, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/mark4.11"
fi
if `test ! -s ./xgraph-11/mark5.11`
then
echo "writing ./xgraph-11/mark5.11"
cat > ./xgraph-11/mark5.11 << '\End\Of\Shar\'
#define mark5_width 8
#define mark5_height 8
#define mark5_x_hot 3
#define mark5_y_hot 3
static char mark5_bits[] = {
   0x00, 0x08, 0x14, 0x22, 0x14, 0x08, 0x00, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/mark5.11"
fi
if `test ! -s ./xgraph-11/mark6.11`
then
echo "writing ./xgraph-11/mark6.11"
cat > ./xgraph-11/mark6.11 << '\End\Of\Shar\'
#define mark6_width 8
#define mark6_height 8
#define mark6_x_hot 3
#define mark6_y_hot 3
static char mark6_bits[] = {
   0x00, 0x1c, 0x14, 0x1c, 0x14, 0x1c, 0x00, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/mark6.11"
fi
if `test ! -s ./xgraph-11/mark7.11`
then
echo "writing ./xgraph-11/mark7.11"
cat > ./xgraph-11/mark7.11 << '\End\Of\Shar\'
#define mark7_width 8
#define mark7_height 8
#define mark7_x_hot 3
#define mark7_y_hot 3
static char mark7_bits[] = {
   0x00, 0x1c, 0x2a, 0x36, 0x2a, 0x1c, 0x00, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/mark7.11"
fi
if `test ! -s ./xgraph-11/mark8.11`
then
echo "writing ./xgraph-11/mark8.11"
cat > ./xgraph-11/mark8.11 << '\End\Of\Shar\'
#define mark8_width 8
#define mark8_height 8
#define mark8_x_hot 3
#define mark8_y_hot 3
static char mark8_bits[] = {
   0x00, 0x3e, 0x1c, 0x08, 0x1c, 0x3e, 0x00, 0x00};
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/mark8.11"
fi
if `test ! -s ./xgraph-11/new_ps.c`
then
echo "writing ./xgraph-11/new_ps.c"
cat > ./xgraph-11/new_ps.c << '\End\Of\Shar\'
/*
 * Postscript output for xgraph
 *
 * Rick Spickelmier
 * David Harrison
 */

#include "copyright.h"
#include <stdio.h>
#include "xgout.h"

/*
 * Basic scaling parameters
 */

#define VDPI			1200.0
#define LDIM			11.0
#define SDIM			8.5
#define MICRONS_PER_INCH	2.54E+04
#define POINTS_PER_INCH		72.0
#define INCHES_PER_POINT	1.0/72.0

/*
 * Aesthetic parameters (inches)
 */

#define PS_BDR_PAD		0.075
#define PS_AXIS_PAD		0.1
#define PS_LEG_PAD		0.025
#define PS_TICK_LEN		0.125
#define BASE_DASH		(1.0/48.0)

#define BASE_WIDTH		(1.0/8.0)
#define PS_AXIS_WBASE		1
#define PS_ZERO_WBASE		4
#define PS_DATA_WBASE		7
#define PS_PIXEL		4
#define PS_DOT			12
#define PS_MARK			12

/*
 * Other constants
 */

#define FONT_WIDTH_EST		0.55
#define PS_MAX_SEGS		1000
#define PS_NO_TSTYLE		-1
#define PS_NO_DSTYLE		-1
#define PS_NO_WIDTH		-1
#define PS_NO_LSTYLE		-1

/*
 * Working macros
 */

#define OUT		(void) fprintf
#define PS(str)		OUT(psFile, str)
#define PSU(str)	OUT(ui->psFile, str)
#define IY(val)		(ui->height_devs - val)
#define MAX(a, b)	((a) > (b) ? (a) : (b))

/*
 * Globals
 */

static double PS_scale;		/* devs/micron */

/*
 * Externals and forwards
 */

extern char *malloc();
static void psScale(), psFonts(), psMarks(), psText(), psSeg(), psDot(), psEnd();


/*
 * Local structures
 */

struct userInfo {
    FILE *psFile;
    int currentTextStyle;
    int currentDashStyle;
    int currentWidth;
    int currentLStyle;
    int baseWidth;
    int height_devs;
    char *title_family;
    double title_size;
    char *axis_family;
    double axis_size;
};



int rd(dbl)
double dbl;
/* Short and sweet rounding function */
{
    if (dbl < 0.0) {
	return ((int) (dbl - 0.5));
    } else {
	return ((int) (dbl + 0.5));
    }
}

/*ARGSUSED*/
int psInit(psFile, width, height, tf, ts, af, as, outInfo, errmsg)
FILE *psFile;			/* Output file            */
int width, height;		/* In microns             */
char *tf, *af;			/* Title and axis font    */
double ts, as;			/* Title and axis size    */
xgOut *outInfo;			/* Returned device info   */
char errmsg[ERRBUFSIZE];	/* Returned error message */
/*
 * The basic coordinate system is points (roughly 1/72 inch).
 * However,  most laser printers can do much better than that.
 * We invent a coordinate system based on VDPI dots per inch.
 * This goes along the long side of the page.  The long side
 * of the page is LDIM inches in length,  the short side
 * SDIM inches in length.  We we call this unit a `dev'.
 * We map `width' and `height' into devs.
 */
{
    struct userInfo *ui;
    double font_size;

    ui = (struct userInfo *) malloc(sizeof(struct userInfo));
    ui->psFile = psFile;
    ui->currentTextStyle = PS_NO_TSTYLE;
    ui->currentDashStyle = PS_NO_DSTYLE;
    ui->currentWidth = PS_NO_WIDTH;
    ui->currentLStyle = PS_NO_LSTYLE;
    ui->title_family = tf;
    ui->title_size = ts;
    ui->axis_family = af;
    ui->axis_size = as;
    /* Roughly,  one-eighth a point in devs */
    ui->baseWidth = rd( VDPI / POINTS_PER_INCH * BASE_WIDTH );

    PS_scale = VDPI / MICRONS_PER_INCH;

    outInfo->dev_flags = 0;
    outInfo->area_w = rd( ((double) width) * PS_scale );
    outInfo->area_h = rd( ((double) height) * PS_scale );
    ui->height_devs = outInfo->area_h;
    outInfo->bdr_pad = rd( PS_BDR_PAD * VDPI );
    outInfo->axis_pad = rd( PS_AXIS_PAD * VDPI );
    outInfo->legend_pad = rd( PS_LEG_PAD * VDPI );
    outInfo->tick_len = rd( PS_TICK_LEN * VDPI );

    /* Font estimates */
    font_size = as * INCHES_PER_POINT * VDPI;
    outInfo->axis_height = rd( font_size );
    outInfo->axis_width = rd( font_size * FONT_WIDTH_EST );
    font_size = ts * INCHES_PER_POINT * VDPI;
    outInfo->title_height = rd( font_size );
    outInfo->title_width = rd( font_size * FONT_WIDTH_EST );

    outInfo->max_segs = PS_MAX_SEGS;

    outInfo->xg_text = psText;
    outInfo->xg_seg = psSeg;
    outInfo->xg_dot = psDot;
    outInfo->xg_end = psEnd;
    outInfo->user_state = (char *) ui;

    /* Header */
    PS("%%!\n");
    PS("%% Xgraph postscript output\n");
    PS("%% Rick Spickelmier and David Harrison\n");
    PS("%% University of California, Berkeley\n");
    PS("%%\n");

    /* Definitions */
    psScale(psFile, width, height);
    psFonts(psFile);
    psMarks(psFile);

    PS("%%\n%% Main body begins here\n%%\n");
    return 1;
}




static void psScale(psFile, width, height)
FILE *psFile;			/* Output stream */
int width;			/* Output width  */
int height;			/* Output height */
/*
 * This routine figures out how transform the basic postscript
 * transformation into one suitable for direct use by
 * the drawing primitives.  Two variables X-CENTER-PLOT
 * and Y-CENTER-PLOT determine whether the plot is centered
 * on the page.
 */
{
    double factor;
    double pnt_width, pnt_height;

    PS("%% Scaling information\n");
    PS("%%\n");
    PS("%% Change these if you would like to change the centering\n");
    PS("%% of the plot in either dimension\n");
    PS("/X-CENTER-PLOT 1 def\n");
    PS("/Y-CENTER-PLOT 1 def\n");
    PS("%%\n");

    /*
     * Determine page size
     */
    PS("%% Page size computation\n");
    PS("clippath pathbbox\n");
    PS("/page-height exch def\n");
    PS("/page-width exch def\n");
    PS("pop pop\n");

    /*
     * First: rotation.  If the width is greater than the short
     * dimension,  do the rotation.
     */
    pnt_width = ((double) width) / MICRONS_PER_INCH * POINTS_PER_INCH;
    pnt_height = ((double) height) / MICRONS_PER_INCH * POINTS_PER_INCH;
    PS("%% Determine whether rotation is required\n");
    OUT(psFile, "%lg page-width gt\n", pnt_width);
    PS("{ %% Rotation required\n");
    PS("   90 rotate\n");
    PS("   0 page-width neg translate\n");
    PS("   %% Handle centering\n");
    PS("   Y-CENTER-PLOT 1 eq { %% Center in y\n");
    OUT(psFile, "      page-height %lg sub 2 div\n", pnt_width);
    PS("   } { %% Don't center in y\n");
    PS("      0\n");
    PS("   } ifelse\n");
    PS("   X-CENTER-PLOT 1 eq { %% Center in x\n");
    OUT(psFile, "      page-width %lg sub 2 div\n", pnt_height);
    PS("   } { %% Don't center in x\n");
    PS("      0\n");
    PS("   } ifelse\n");
    PS("   translate\n");
    PS("} { %% No rotation - just handle centering\n");
    PS("   X-CENTER-PLOT 1 eq { %% Center in x\n");
    OUT(psFile, "      page-width %lg sub 2 div\n", pnt_width);
    PS("   } { %% Don't center in x\n");
    PS("      0\n");
    PS("   } ifelse\n");
    PS("   Y-CENTER-PLOT 1 eq { %% Center in y\n");
    OUT(psFile, "      page-height %lg sub 2 div\n", pnt_height);
    PS("   } { %% Don't center in y\n");
    PS("      0\n");
    PS("   } ifelse\n");
    PS("   translate\n");
    PS("} ifelse\n");

    /*
     * Now: scaling.  We have points.  We want devs.
     */
    factor = POINTS_PER_INCH / VDPI;
    PS("%% Set the scale\n");
    OUT(psFile, "%lg %lg scale\n", factor, factor);
}



static void psFonts(psFile)
FILE *psFile;			/* Output stream                */
/*
 * Downloads code for drawing title and axis labels
 */
{
    PS("%% Font Handling Functions\n");
    PS("%%\n");
    PS("%% Function giving y-offset to center of font\n");
    PS("%% Assumes font is set and uses numbers to gauge center\n");
    PS("%%\n");
    PS("/choose-font	%% stack: fontsize fontname => ---\n");
    PS("{\n");
    PS("   findfont \n");
    PS("   exch scalefont \n");
    PS("   setfont\n");
    PS("   newpath\n");
    PS("   0 0 moveto (0) true charpath flattenpath pathbbox\n");
    PS("   /top exch def pop\n");
    PS("   /bottom exch def pop\n");
    PS("   bottom top bottom top add 2 div\n");
    PS("   /center-font-val exch def \n");
    PS("   /upper-font-val exch def \n");
    PS("   /lower-font-val exch def\n");
    PS("} def\n");
    PS("%%\n");
    PS("%% Justfication offset routines\n");
    PS("%%\n");
    PS("/center-x-just	%% stack: (string) x y => (string) newx y\n");
    PS("{\n");
    PS("   exch 2 index stringwidth pop 2 div sub exch\n");
    PS("} def\n");
    PS("%%\n");
    PS("/left-x-just	%% stack: (string) x y => (string) newx y\n");
    PS("{ \n");
    PS("} def\n");
    PS("%%\n");
    PS("/right-x-just	%% stack: (string) x y => (string) newx y\n");
    PS("{\n");
    PS("   exch 2 index stringwidth pop sub exch\n");
    PS("} def\n");
    PS("%%\n");
    PS("/center-y-just	%% stack: (string) x y => (string) x newy\n");
    PS("{\n");
    PS("   center-font-val sub\n");
    PS("} def\n");
    PS("%%\n");
    PS("/lower-y-just	%% stack: (string) x y => (string) x newy\n");
    PS("{\n");
    PS("   lower-font-val sub\n");
    PS("} def\n");
    PS("%%\n");
    PS("/upper-y-just	%% stack: (string) x y => (string) x newy\n");
    PS("{\n");
    PS("   upper-font-val sub\n");
    PS("} def\n");
    PS("%%\n");
    PS("%% Shows a string on the page subject to justification\n");
    PS("%%   \n");
    PS("/just-string	%% stack: (string) x y just => ---\n");
    PS("{\n");
    PS("   dup 0 eq { pop center-x-just center-y-just 		} if\n");
    PS("   dup 1 eq { pop left-x-just center-y-just		} if\n");
    PS("   dup 2 eq { pop left-x-just upper-y-just	 	} if\n");
    PS("   dup 3 eq { pop center-x-just upper-y-just 		} if\n");
    PS("   dup 4 eq { pop right-x-just upper-y-just	 	} if\n");
    PS("   dup 5 eq { pop right-x-just center-y-just 		} if\n");
    PS("   dup 6 eq { pop right-x-just lower-y-just	 	} if\n");
    PS("   dup 7 eq { pop center-x-just lower-y-just  		} if\n");
    PS("   dup 8 eq { pop left-x-just lower-y-just	 	} if\n");
    PS("   moveto show\n");
    PS("} def\n");
    PS("%%\n");
}



static void psMarks(psFile)
FILE *psFile;
/*
 * Writes out marker definitions
 */
{
    PS("%% Marker definitions\n");
    PS("/mark0 {/size exch def /y exch def /x exch def\n");
    PS("newpath x size sub y size sub moveto\n");
    PS("size size add 0 rlineto 0 size size add rlineto\n");
    PS("0 size size add sub 0 rlineto closepath fill} def\n");
    
    PS("/mark1 {/size exch def /y exch def /x exch def\n");
    PS("newpath x size sub y size sub moveto\n");
    PS("size size add 0 rlineto 0 size size add rlineto\n");
    PS("0 size size add sub 0 rlineto closepath stroke} def\n");
    
    PS("/mark2 {/size exch def /y exch def /x exch def\n");
    PS("newpath x y moveto x y size 0 360 arc stroke} def\n");

    PS("/mark3 {/size exch def /y exch def /x exch def\n");
    PS("newpath x size sub y size sub moveto x size add y size add lineto\n");
    PS("x size sub y size add moveto x size add y size sub lineto stroke} def\n");

    PS("/mark4 {/size exch def /y exch def /x exch def\n");
    PS("newpath x size sub y moveto x y size add lineto\n");
    PS("x size add y lineto x y size sub lineto\n");
    PS("closepath stroke} def\n");
    
    PS("/mark5 {/size exch def /y exch def /x exch def\n");
    PS("x y size mark1\n");
    PS("newpath x size sub y moveto size size add 0 rlineto stroke} def\n");
    
    PS("/mark6 {/size exch def /y exch def /x exch def\n");
    PS("newpath x y moveto x y size 0 360 arc fill} def\n");

    PS("/mark7 {/size exch def /y exch def /x exch def\n");
    PS("newpath x y moveto x size sub y size sub lineto\n");
    PS("x size add y size sub lineto closepath fill\n");
    PS("newpath x y moveto x size add y size add lineto\n");
    PS("x size sub y size add lineto closepath fill} def\n");
}



static void psText(state, x, y, text, just, style)
char *state;			/* Really (struct userInfo *) */
int x, y;			/* Text position (devs)       */
char *text;			/* Text itself                */
int just;			/* Justification              */
int style;			/* Style                      */
/*
 * Draws text at the given location with the given justification
 * and style.
 */
{
    struct userInfo *ui = (struct userInfo *) state;

    if (style != ui->currentTextStyle) {
	switch (style) {
	case T_AXIS:
	    OUT(ui->psFile, "%lg /%s choose-font\n",
		ui->axis_size * INCHES_PER_POINT * VDPI, ui->axis_family);
	    break;
	case T_TITLE:
	    OUT(ui->psFile, "%lg /%s choose-font\n",
		ui->title_size * INCHES_PER_POINT * VDPI, ui->title_family);
	    break;
	}
	ui->currentTextStyle = style;
    }
    OUT(ui->psFile, "(%s) %d %d %d just-string\n", text, x, IY(y), just);
}



/*ARGSUSED*/
static void psSeg(state, ns, seglist, width, style, lappr, color)
char *state;			/* Really (struct userInfo *) */
int ns;				/* Number of segments         */
XSegment *seglist;		/* X array of segments        */
int width;			/* Width of lines (devcoords) */
int style;			/* L_AXIS, L_ZERO, L_VAR      */
int lappr;			/* Zero to seven              */
int color;			/* Zero to seven              */
/*
 * Draws a number of line segments.  Grid lines are drawn using
 * light lines.  Variable lines (L_VAR) are drawn wider.  This
 * version ignores the color argument.
 */
{
    struct userInfo *ui = (struct userInfo *) state;
    int newwidth, i;

    if ((style != ui->currentLStyle) || (width != ui->currentWidth)) {
	switch (style) {
	case L_AXIS:
	    newwidth = PS_AXIS_WBASE * ui->baseWidth;
	    PSU("[] 0 setdash\n");
	    break;
	case L_ZERO:
	    newwidth = PS_ZERO_WBASE * ui->baseWidth;
	    PSU("[] 0 setdash\n");
	    break;
	case L_VAR:
	    newwidth = PS_DATA_WBASE * ui->baseWidth;
	    break;
	}
	ui->currentWidth = MAX(newwidth, width);
	ui->currentLStyle = style;
	OUT(ui->psFile, "%d setlinewidth\n", ui->currentWidth);
    }
    if ((lappr != ui->currentDashStyle) && (style == L_VAR)) {
	if (lappr == 0) {
	    PSU("[] 0 setdash\n");
	} else {
	    OUT(ui->psFile, "[%lg] 0 setdash\n",
		((double) lappr) * BASE_DASH * VDPI);
	}
	ui->currentDashStyle = lappr;
    }
    PSU("newpath\n");
    OUT(ui->psFile, "  %d %d moveto\n", seglist[0].x1, IY(seglist[0].y1));
    OUT(ui->psFile, "  %d %d lineto\n", seglist[0].x2, IY(seglist[0].y2));
    for (i = 1;  i < ns;  i++) {
	if ((seglist[i].x1 != seglist[i-1].x2) ||
	    (seglist[i].y1 != seglist[i-1].y2)) {
	    OUT(ui->psFile, "  %d %d moveto\n", seglist[i].x1, IY(seglist[i].y1));
	}
	OUT(ui->psFile, "  %d %d lineto\n", seglist[i].x2, IY(seglist[i].y2));
    }
    PSU("stroke\n");
}



/*ARGSUSED*/
static void psDot(state, x, y, style, type, color)
char *state;    	/* state information */
int x,y;    		/* coord of dot */
int style;  		/* type of dot */
int type;   		/* dot style variation */
int color;  		/* color of dot */
/*
 * Prints out a dot at the given location
 */
{
    struct userInfo *ui = (struct userInfo *) state;

    if (ui->currentDashStyle != PS_NO_DSTYLE) {
	OUT(ui->psFile, "[] 0 setdash ");
	ui->currentDashStyle = PS_NO_DSTYLE;
    }
    if (ui->currentWidth != PS_ZERO_WBASE * ui->baseWidth) {
	ui->currentWidth = PS_ZERO_WBASE * ui->baseWidth;
	OUT(ui->psFile, "%d setlinewidth ", ui->currentWidth);
    }
    
    switch (style) {
    case P_PIXEL:
	OUT(ui->psFile, "newpath %d %d moveto %d %d %d 0 360 arc fill\n",
	    x, IY(y), x, IY(y), PS_PIXEL * ui->baseWidth);
	break;
    case P_DOT:
	OUT(ui->psFile, "newpath %d %d moveto %d %d %d 0 360 arc fill\n",
	    x, IY(y), x, IY(y), PS_DOT * ui->baseWidth);
	break;
    case P_MARK:
	OUT(ui->psFile, "%d %d %d mark%d\n",
	    x, IY(y), PS_MARK * ui->baseWidth, type);
	break;
    }
    return;
}


static void psEnd(userState)
char *userState;    /* state information */
{
    struct userInfo *ui = (struct userInfo *) userState;

    PSU("showpage\n");
}
\End\Of\Shar\
else
  echo "will not over write ../xgraph-11/new_ps.c"
fi
if `test ! -s ./xgraph-11/plotter.h`
then
echo "writing ./xgraph-11/plotter.h"
cat > ./xgraph-11/plotter.h << '\End\Of\Shar\'
    /* 
     * HP plotter definition - these are dependent on the
     * SPECIFIC MODEL of HP plotter used, and should always
     * be modified when going to a new plotter.
     * 
     * all dimensions are in plotter units.
     *
     * MINX and MINY are the smallest x and y values that
     * are inside the soft clip limits of the plotter
     * MAXX and MAXY are the largest x and y values that
     * are inside the soft clip limits of the plotter MINUS
     * MINX and MINY, so they give the dimension of the
     * soft clip area.
     *
     * PLOTTERTYPE is a character string which identifies the
     * plotter that should be used.  control information will
     * be read for ~cad/lib/technology/$TECHNOLOGY/$PLOTTERTYPE.map
     * and output will go to /usr/ucb/lpr -Pplt$PLOTTERTYPE
     *
     */
#define PLOTTERTYPE "7550"
#define P1X 80
#define P1Y 320
#define P2X 10080
#define P2Y 7520
#define MAXX 10000
#define MAXY 7200

#define PLOTTERNAME "paper"

#define PENGRID 1
#define PENAXIS 2
#define TEXTCOLOR 1
#define PEN1 3
#define PEN2 4
#define PEN3 5 
#define PEN4 6
#define PEN5 7
#define PEN6 8
#define PEN7 2
#define PEN8 1

#define LINE1 2
#define LINE2 4
#define LINE3 5 
#define LINE4 6
#define LINE5 2
#define LINE6 4
#define LINE7 5
#define LINE8 6

#define MARK1 "L"
#define MARK2 "K"
#define MARK3 "M"
#define MARK4 "O"
#define MARK5 "G"
#define MARK6 "F"
#define MARK7 "E"
#define MARK8 "A"

\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/plotter.h"
fi
if `test ! -s ./xgraph-11/plotter.try1.h`
then
echo "writing ./xgraph-11/plotter.try1.h"
cat > ./xgraph-11/plotter.try1.h << '\End\Of\Shar\'
    /* 
     * HP plotter definition - these are dependent on the
     * SPECIFIC MODEL of HP plotter used, and should always
     * be modified when going to a new plotter.
     * 
     * all dimensions are in plotter units.
     *
     * MINX and MINY are the smallest x and y values that
     * are inside the soft clip limits of the plotter
     * MAXX and MAXY are the largest x and y values that
     * are inside the soft clip limits of the plotter MINUS
     * MINX and MINY, so they give the dimension of the
     * soft clip area.
     *
     * PLOTTERTYPE is a character string which identifies the
     * plotter that should be used.  control information will
     * be read for ~cad/lib/technology/$TECHNOLOGY/$PLOTTERTYPE.map
     * and output will go to /usr/ucb/lpr -Pplt$PLOTTERTYPE
     *
     */
#define PLOTTERTYPE "7550"
#define P1X 80
#define P1Y 320
#define P2X 10080
#define P2Y 7520
#define MAXX 10000
#define MAXY 7200

#define AFW 0.15
#define AFH 0.225
#define TFW 0.3
#define TFH 0.45

#define MAPX(x) ( (x) + P1X + clipminX ) 
#define MAPY(y) ( MAXY - (y) + P1Y - clipminY)

#define PLOTTERNAME "paper"

#define PENGRID 1
#define PENAXIS 2
#define TEXTCOLOR 1
#define PEN1 3
#define PEN2 4
#define PEN3 5 
#define PEN4 6
#define PEN5 7
#define PEN6 8
#define PEN7 2
#define PEN8 1

#define LINE1 2
#define LINE2 4
#define LINE3 5 
#define LINE4 6
#define LINE5 2
#define LINE6 4
#define LINE7 5
#define LINE8 6

#define MARK1 "L"
#define MARK2 "K"
#define MARK3 "M"
#define MARK4 "O"
#define MARK5 "G"
#define MARK6 "F"
#define MARK7 "E"
#define MARK8 "A"

\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/plotter.try1.h"
fi
if `test ! -s ./xgraph-11/xgX.c`
then
echo "writing ./xgraph-11/xgX.c"
cat > ./xgraph-11/xgX.c << '\End\Of\Shar\'
/*
 * Generic Output Driver for X
 * X version 11
 *
 * This is the primary output driver used by the new X graph
 * to display output to the X server.  It has been factored
 * out of the original xgraph to allow mulitple hardcopy
 * output devices to share xgraph's capabilities.  Note:
 * xgraph is still heavily X oriented.  This is not intended
 * for porting to other window systems.
 */

#include "copyright.h"
#include "xgout.h"
#include "xgraph.h"

#define PADDING 	2
#define SPACE 		10
#define TICKLENGTH	5
#define MAXSEGS		1000

typedef struct x_state {
    Window win;			/* Primary window           */
};

void text_X();
void seg_X();
void dot_X();



void set_X(new_win, out_info)
Window new_win;			/* Newly created window */
xgOut *out_info;		/* Information to set   */
/* 
 * Sets some of the common parameters for the X output device.
 */
{
    struct x_state *new_state;

    out_info->dev_flags = ((depth > 3) ? D_COLOR : 0);
    out_info->area_w = out_info->area_h = 0; /* Set later */
    out_info->bdr_pad = PADDING;
    out_info->axis_pad = SPACE;
    out_info->legend_pad = 0;
    out_info->tick_len = TICKLENGTH;
#ifdef OLD
    out_info->axis_width =
      axisFont->max_bounds.rbearing - axisFont->max_bounds.lbearing;
#endif
    out_info->axis_width = XTextWidth(axisFont, "8", 1);
    out_info->axis_height =
      axisFont->max_bounds.ascent + axisFont->max_bounds.descent;
#ifdef OLD
    out_info->title_width =
      titleFont->max_bounds.rbearing - titleFont->max_bounds.lbearing;
#endif
    out_info->title_width = XTextWidth(titleFont, "8", 1);
    out_info->title_height =
      titleFont->max_bounds.ascent + titleFont->max_bounds.descent;
    out_info->max_segs = MAXSEGS;

    out_info->xg_text = text_X;
    out_info->xg_seg = seg_X;
    out_info->xg_dot = dot_X;
    out_info->xg_end = (void (*)()) 0;
    new_state = (struct x_state *) malloc(sizeof(struct x_state));
    new_state->win = new_win;
    out_info->user_state = (char *) new_state;
}



/*ARGSUSED*/
void init_X(user_state)
char *user_state;
/*
 * Initializes for an X drawing sequence.  Does nothing under X11.
 */
{
    /* Body left empty on purpose */
}

static GC textGC(t_win, t_font)
Window t_win;			/* Window for making GC */
XFontStruct *t_font;		/* Text font            */
/*
 * Sets the fields above in a global graphics context.  If
 * the graphics context does not exist,  it is created.
 */
{
    static GC text_gc = (GC) 0;
    XGCValues gcvals;
    unsigned long gcmask;

    gcvals.font = t_font->fid;
    gcmask = GCFont;
    if (text_gc == (GC) 0) {
	gcvals.foreground = normPixel;
	gcmask |= GCForeground;
	text_gc = XCreateGC(disp, t_win, gcmask, &gcvals);
    } else {
	XChangeGC(disp, text_gc, gcmask, &gcvals);
    }
    return text_gc;
}

static GC segGC(l_win, l_fg, l_style, l_width, l_chars, l_len)
Window l_win;			/* Window for making GC */
Pixel l_fg;			/* Foreground color */
int l_style;			/* Line style       */
int l_width;			/* Line width       */
char *l_chars;			/* Character spec   */
int l_len;			/* Length of spec   */
/*
 * Sets the fields above in a global graphics context.  If the
 * graphics context does not exist, it is created.
 */
{
    static GC segment_gc = (GC) 0;
    XGCValues gcvals;
    unsigned long gcmask;

    gcvals.foreground = l_fg;
    gcvals.line_style = l_style;
    gcvals.line_width = l_width;
    gcmask = GCForeground | GCLineStyle | GCLineWidth;
    if (segment_gc == (GC) 0) {
	segment_gc = XCreateGC(disp, l_win, gcmask, &gcvals);
    } else {
	XChangeGC(disp, segment_gc, gcmask, &gcvals);
    }
    if (l_len > 0) {
	XSetDashes(disp, segment_gc, 0, l_chars, l_len);
    }
    return segment_gc;
}

static GC dotGC(d_win, d_fg, d_clipmask, d_xorg, d_yorg)
Window d_win;			/* Window for making GC */
Pixel d_fg;			/* Foreground color */
Pixmap d_clipmask;		/* Clipmask         */
int d_xorg, d_yorg;		/* Clipmask origin  */
/*
 * Sets the fields above in a global graphics context.  If the
 * graphics context does not exist, it is created.
 */
{
    static GC dot_gc = (GC) 0;
    XGCValues gcvals;
    unsigned long gcmask;

    gcvals.foreground = d_fg;
    gcvals.clip_mask = d_clipmask;
    gcvals.clip_x_origin = d_xorg;
    gcvals.clip_y_origin = d_yorg;
    gcmask = GCForeground | GCClipMask | GCClipXOrigin | GCClipYOrigin;
    if (dot_gc == (GC) 0) {
	dot_gc = XCreateGC(disp, d_win, gcmask, &gcvals);
    } else {
	XChangeGC(disp, dot_gc, gcmask, &gcvals);
    }
    return dot_gc;
}



void text_X(user_state, x, y, text, just, style)
char *user_state;		/* Value set in xg_init   */
int x, y;			/* Text position (pixels) */
char *text;			/* Null terminated text   */
int just;			/* Justification (above)  */
int style;			/* Text style (above)     */
/*
 * This routine should draw text at the indicated position using
 * the indicated justification and style.  The justification refers
 * to the location of the point in reference to the text.  For example,
 * if just is T_LOWERLEFT,  (x,y) should be located at the lower left
 * edge of the text string.
 */
{
    struct x_state *st = (struct x_state *) user_state;
    XCharStruct bb;
    int rx, ry, len, height, width, dir;
    int ascent, descent;

    len = strlen(text);
    XTextExtents((style == T_TITLE) ? titleFont : axisFont, text, len,
		 &dir, &ascent, &descent, &bb);
    width = bb.rbearing - bb.lbearing;
    height = bb.ascent + bb.descent;
    
    switch (just) {
    case T_CENTER:
	rx = x - (width/2);
	ry = y - (height/2);
	break;
    case T_LEFT:
	rx = x;
	ry = y - (height/2);
	break;
    case T_UPPERLEFT:
	rx = x;
	ry = y;
	break;
    case T_TOP:
	rx = x - (width/2);
	ry = y;
	break;
    case T_UPPERRIGHT:
	rx = x - width;
	ry = y;
	break;
    case T_RIGHT:
	rx = x - width;
	ry = y - (height/2);
	break;
    case T_LOWERRIGHT:
	rx = x - width;
	ry = y - height;
	break;
    case T_BOTTOM:
	rx = x - (width/2);
	ry = y - height;
	break;
    case T_LOWERLEFT:
	rx = x;
	ry = y - height;
	break;
    }
    XDrawString(disp, st->win,
		textGC(st->win, ((style == T_TITLE) ? titleFont : axisFont)),
		rx, ry + bb.ascent, text, len);
}



void seg_X(user_state, ns, segs, width, style, lappr, color)
char *user_state;		/* Value set in xg_init */
int ns;				/* Number of segments   */
XSegment *segs;			/* X array of segments  */
int width;			/* Width of lines       */
int style;			/* See above            */
int lappr;			/* Line appearence      */
int color;			/* Line color (if any)  */
/*
 * This routine draws a number of line segments at the points
 * given in `seglist'.  Note that contiguous segments need not share
 * endpoints but often do.  All segments should be `width' devcoords wide
 * and drawn in style `style'.  If `style' is L_VAR,  the parameters
 * `color' and `lappr' should be used to draw the line.  Both
 * parameters vary from 0 to 7.  If the device is capable of
 * color,  `color' varies faster than `style'.  If the device 
 * has no color,  `style' will vary faster than `color' and
 * `color' can be safely ignored.  However,  if the
 * the device has more than 8 line appearences,  the two can
 * be combined to specify 64 line style variations.
 * Xgraph promises not to send more than the `max_segs' in the
 * xgOut structure passed back from xg_init().
 */
{
    struct x_state *st = (struct x_state *) user_state;
    GC gc;

    if (style == L_AXIS) {
	gc = segGC(st->win, normPixel, LineSolid, axisWidth, (char *) 0, 0);
    } else if (style == L_ZERO) {
	/* Set the color and line style */
	gc = segGC(st->win, zeroPixel, LineSolid, zeroWidth, (char *) 0, 0);
    } else {
	/* Color and line style vary */
	if (lappr == 0) {
	    gc = segGC(st->win, AllAttrs[color].pixelValue, LineSolid,
		       width, (char *) 0, 0);
	} else {
	    gc = segGC(st->win, AllAttrs[color].pixelValue, LineOnOffDash,
		       width, AllAttrs[lappr].lineStyle, AllAttrs[lappr].lineStyleLen);
	}
    }
    XDrawSegments(disp, st->win, gc, segs, ns);
}


#define LAST_CHECK

void dot_X(user_state, x, y, style, type, color)
char *user_state;		/* Value set in xg_init    */
int x, y;			/* Location in pixel units */
int style;			/* Dot style               */
int type;			/* Type of marker          */
int color;			/* Marker color (if any)   */
/*
 * This routine should draw a marker at location `x,y'.  If the
 * style is P_PIXEL,  the dot should be a single pixel.  If
 * the style is P_DOT,  the dot should be a reasonably large
 * dot.  If the style is P_MARK,  it should be a distinguished
 * mark which is specified by `type' (0-7).  If the output
 * device is capable of color,  the marker should be drawn in
 * `color' (0-7) which corresponds with the color for xg_line.
 */
{
    struct x_state *st = (struct x_state *) user_state;
    
    switch (style) {
    case P_PIXEL:
	XDrawPoint(disp, st->win,
		   dotGC(st->win, AllAttrs[color].pixelValue, (Pixmap) 0, 0, 0),
		   x, y);
	break;
    case P_DOT:
	XFillRectangle(disp, st->win,
		       dotGC(st->win, AllAttrs[color].pixelValue, dotMap,
			     (int) (x - (dot_w >> 1)),
			     (int) (y - (dot_h >> 1))),
		       (int) (x - (dot_w >> 1)), (int) (y - (dot_h >> 1)),
		       dot_w, dot_h);
	break;
    case P_MARK:
	XFillRectangle(disp, st->win,
		       dotGC(st->win, AllAttrs[color].pixelValue,
			     AllAttrs[type].markStyle,
			     (int) (x - mark_cx),
			     (int) (y - mark_cy)),
		       (int) (x - mark_cx), (int) (y - mark_cy),
		       mark_w, mark_h);
	break;
    }
}

\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/xgX.c"
fi
if `test ! -s ./xgraph-11/xgout.h`
then
echo "writing ./xgraph-11/xgout.h"
cat > ./xgraph-11/xgout.h << '\End\Of\Shar\'
/*
 * Output Device Information
 *
 * This file contains definitions for output device interfaces
 * to the graphing program xgraph.
 */

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/cursorfont.h>
#include "ux11/ux11.h"

#define D_COLOR		0x01

/* Text justifications */
#define T_CENTER	0
#define T_LEFT		1
#define T_UPPERLEFT	2
#define T_TOP		3
#define T_UPPERRIGHT	4
#define T_RIGHT		5
#define T_LOWERRIGHT	6
#define T_BOTTOM	7
#define T_LOWERLEFT	8

/* Text styles */
#define T_AXIS		0
#define T_TITLE		1

/* Line Styles */
#define L_AXIS		0
#define L_ZERO		1
#define L_VAR		2

/* Marker Styles */
#define P_PIXEL		0
#define P_DOT		1
#define P_MARK		2

/* Output device information returned by initialization routine */

typedef struct xg_out {
    int dev_flags;		/* Device characteristic flags           */
    int area_w, area_h;		/* Width and height in pixels            */
    int bdr_pad;		/* Padding from border                   */
    int axis_pad;		/* Extra space around axis labels        */
    int tick_len;		/* Length of tick mark on axis           */
    int legend_pad;		/* Top of legend text to legend line     */
    int axis_width;		/* Width of big character of axis font   */
    int axis_height;		/* Height of big character of axis font  */
    int title_width;		/* Width of big character of title font  */
    int title_height;		/* Height of big character of title font */
    int max_segs;		/* Maximum number of segments in group   */

    void (*xg_text)();		/* Draws text at a location              */
    void (*xg_seg)();		/* Draws a series of segments            */
    void (*xg_dot)();		/* Draws a dot or marker at a location   */
    void (*xg_end)();		/* Stops the drawing sequence            */

    char *user_state;		/* User supplied data                    */
} xgOut;

#define ERRBUFSIZE	2048
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/xgout.h"
fi
if `test ! -s ./xgraph-11/xgraph.1`
then
echo "writing ./xgraph-11/xgraph.1"
cat > ./xgraph-11/xgraph.1 << '\End\Of\Shar\'
.TH XGRAPH 1 "February 1, 1989"
.SH NAME
xgraph \- Draw a graph on an X11 Display
.SH SYNOPSIS
.B xgraph
[ options ] [ =WxH+X+Y ] [ -display host:display.screen ] [ file ... ]
.SH DESCRIPTION
The 
.I xgraph
program draws a graph on an X display given data read from either
data files or from standard input if no files are specified.
It can display up to 64 independent data sets using different colors
and/or line styles for each set.
It annotates the graph with a title,  axis labels,  grid lines or tick
marks, grid labels,  
and a legend.
There are options to control the appearance of most components of
the graph.
.PP
The input format is similar to
.I graph(1G)
but differs slightly.
The data consists of a number of
.I "data sets."
Data sets are separated by a blank line.
A new data set is also
assumed at the start of each input file.
A data set consists of an ordered list of points of the form "X Y".
Each point must appear on a separate line.  
The name of a data set can be specified by a line which begins
with a double quote followed by the set name.
An example input file with three data sets is shown below (note
set three is not named):
.sp 1
.nf
0.5 7.8
1.0 6.2
"set one
1.5 8.9

"set two
-3.4 1.4e-3
-2.0 1.9e-2
-0.65 2.2e-4

2.2 12.8
2.4 -3.3
2.6 -32.2
2.8 -10.3
.fi
.PP
After
.I xgraph
has read the data,  it will create a new window to graphically
display the data.
The interface used to specify the size and location of this window depends
on the window manager currently in use.
Refer to the reference manual of the window manager for details.
.PP
Once the window has been opened,  all of the data sets will be displayed
graphically (subject to the options explained below) with a legend in 
the upper right corner of the screen.
To zoom in on a portion of the graph,  depress a mouse button in
the window and sweep out a region.
.I xgraph
will then open a new window looking at just that portion of the graph.
.I xgraph
also presents two control buttons in the upper left corner of
each window:
.I Close
and
.I Hardcopy.
Windows are closed by depressing a mouse button while the mouse
cursor is inside the
.I Close
button.  Typing EOF (control-D) in a window also closes that window.
Depressing a mouse button while the mouse cursor is in
the
.I Harcopy
button causes a dialog to appear asking about hardcopy (printout)
options.  These options are described below:
.IP "Output Device"
Specifies the type of the output device (e.g. "HPGL", "Postscript", etc).
An output device is chosen by depressing the mouse inside its name.
The default values of other fields will change when you select a
different output device.
.IP "Disposition"
Specifies whether the output should go directly to a device
or to a file.  Again,  the default values of other fields will change
when you select a different disposition.
.IP "File or Device Name"
If the disposition is "To Device",  this field specifies the device
name.
A device name is the same as the name given for the -P command
of lpr(1).
If the disposition is "To File",  this field specifies the name
of the output file.
.IP "Maximum Dimension"
This specifies the maximum size of the plot on the hardcopy
device in centimeters.
.I xgraph
takes in account the aspect ratio of the plot on the screen
and will scale the plot so that the longer side of the plot
is no more than the value of this parameter.
If the device supports it,  the plot may also be rotated on the page
based on the value of the maximum dimension.
.IP "Title Font Family"
This field specifies the name of a font to use when drawing
the graph title.  Suitable defaults are initially chosen for
any given hardcopy device.
The value of this field is hardware specific -- refer to
the device reference manual for details.
.IP "Title Font Size"
This field specifies the desired size of the title fonts in points
(1/72 of an inch).  
If the device supports scalable fonts,  the
font will be scaled to this size.
.IP "Axis Font Family and Axis Font Size"
These fields are like
.I "Title Font Family"
and
.I "Title Font Size"
except they specify values for the font
.I xgraph
uses to draw axis labels, and legend descriptions.
.IP "Control Buttons"
After specifing the parameters for the plot,  the "Ok" button causes
.I xgraph
to produce a hardcopy.
Pressing the "Cancel" button will abort the hardcopy operation.
.PP
.I xgraph
accepts a large number of options most of which can be specified
either on the command line or in the user's ~/.Xdefaults file.
A list of these options is given below.  The command line
option is specified first with its X default name (if any) in parenthesis
afterward.
The format of the option in the X defaults file is "program.option: value"
where program is the program name (xgraph) and the option name is the
one specified below.  Note that the value of a flag in the X defaults
file must be "1".
.TP
.B  \-<digit> <name>
These options specify the data set name for the corresponding data set.
The digit should be in the range '0' to '63'.
This name will be used in the legend.
.TP
.B  \-b
Force
.I xgraph
to output the graph in black and white (even if the display is color).
This is useful for those using
.I xwd(1)
to produce hardcopies of the graph.
.TP
.B  \-bar
Specifies that vertical bars should be drawn from the data points to
a base point which can be specified with -brb.  Usually,  the -nl
flag is used with this option.  The point itself is located at
the center of the bar.
.TP
.B  \-bb (BoundBox)
Draw a bounding box around the data region.  This is very useful
if you prefer to see tick marks rather than grid lines (see -tk).
.TP
.B  \-bd <color> (Border)
This specifies the border color of the
.I xgraph
window.
.TP
.B  \-bg <color> (Background)
Background color of the
.I xgraph
window.
.TP
.B  \-brb <base>
This specifies the base for a bar graph.  By default,  the base is zero.
.TP
.B  \-brw <width>
This specifies the width of bars in a bar graph.  The amount is specified
in the user's units.  By default,  a bar one pixel wide is drawn.
.TP
.B  \-bw <size> (BorderSize)
Border width (in pixels) of the
.I xgraph
window.
.TP
.B  \-fg <color> (Foreground)
Foreground color.  This color is used to draw all text and the normal
grid lines in the window.
.TP
.B  \-lf <fontname> (LabelFont)
Label font.  All axis labels and grid labels are drawn using this
font.  It must be a fixed-width font.
.TP
.B  \-lnx
Specifies a logarithmic X axis.  Grid labels represent powers of ten.
.TP
.B  \-lny
Specifies a logarithmic Y axis.  Grid labels represent powers of ten.
.TP
.B  \-lw width
Specifies the width of the data lines in pixels.  The default is one.
.TP
.B  \-lx <xl,xh>
This option limits the range of the X axis to the specified
interval.  This (along with -ly) can be used to "zoom in" on a particularly
interesting portion of a larger graph.
.TP
.B  \-ly <yl,yh>
This option limits the range of the Y axis to the specified
interval.
.TP
.B  \-m (Markers)
Mark each data point with a distinctive marker.
There are eight distinctive markers used by xgraph.
These markers are assigned uniquely to each different line style on
black and white machines and varies with each color on color machines.
.TP
.B  \-M (StyleMarkers)
Similar to -m but markers are assigned uniquely to each eight consecutive
data sets (this corresponds to each different line style on color machines).
.TP
.B  \-nl (NoLines)
Turn off drawing lines.  When used with -m,  this can be used to
produce scatter plots.  When used with -bar,  it can be used to
produce standard bar graphs.
.TP
.B  \-p (PixelMarkers, SmallPixels)
Marks each data point with a small marker (pixel sized).  This is
usually used with the -nl option for scatter plots.
.TP
.B  \-P (LargePixels)
Similar to -p but marks each pixel with a large dot.
.TP
.B  \-rv (ReverseVideo)
Reverse video.  On black and white displays,  this will invert
the foreground and background colors.  It does nothing on color displays.
.TP
.B  \-s (Spline)
This option specifies the lines should be drawn as spline curves.
Currently,  this is implemented using the X spline option which
fits only three points at a time.  Thus,  the effect is not what
you might expect.
.TP
.B  \-t <string>
Title of the plot.  This string is centered at the top of the graph.
.TP
.B  \-tf <fontname> (TitleFont)
Title font.  This is the name of the font to use for the graph title.
It defaults to 9x15.
.TP
.B  \-tk (Ticks)
This option causes
.I xgraph
to draw tick marks rather than full grid lines.  The -bb option
is also useful when viewing graphs with tick marks only.
.TP
.B  \-x <unitname>
This is the unit name for the X axis.  Its default is "X".
.TP
.B  \-y <unitname>
This is the unit name for the Y axis.  Its default is "Y".
.TP
.B  \-zg <color> (ZeroColor)
This is the color used to draw the zero grid line.
.PP
Some options can only be specified in the X defaults file.  These
options are described below:
.TP
.B <digit>.Color
Specifies the color for a data set.  Eight independent colors can
be specified.  Thus,  the digit should be between '0' and '7'.
If there are more than eight data sets,  the colors
will repeat but with a new line style (see below).
.TP
.B <digit>.Style
Specifies the line style for a data set.  A sixteen-bit integer
specifies the sixteen-bit pattern used for the line style.
Eight independent line styles can be specified.  Thus,  the
digit should be between '0' and '7'.  If there are more
than eight data sets,  these styles will be reused.  On color
workstations,  one line style is used for each of eight colors.
Thus,  64 unique data sets can be displayed.
.TP
.B GridSize
Width,  in pixels,  of normal grid lines.
.TP
.B GridStyle
Line style pattern of normal grid lines.
.TP
.B ZeroSize
Width,  in pixels,  of the zero grid line.
.TP
.B ZeroStyle
Line style pattern of the zero grid line.
.SH AUTHOR
David Harrison
University of California
\End\Of\Shar\
else
  echo "will not over write ./xgraph-11/xgraph.1"
fi
echo "Finished archive 5 of 6"