ftp.nice.ch/pub/next/science/mathematics/HippoDraw.2.0.s.tar.gz#/HippoDraw/Hippo.bproj/hippoplotamus/hplotPS.c

This is hplotPS.c in view mode; [Download] [Up]

/*
 * hippoplotPS.c - Postscript routines for displaying hippo ntuples.
 *
 * Copyright (C)  1991  The Board of Trustees of The Leland Stanford
 * Junior University.  All Rights Reserved.
 *
 * $Id: hplotPS.c,v 5.0 1993/08/17 21:55:51 rensing Exp $
 *
 * by Paul Rensing, Apr. 8, 1992
 */

#include <string.h>
#include <stdlib.h>
#include <math.h>
#include "hippo.h"
#include "h3D.h"
#include "hplotPS.h"
#include "hutil.h"

#define MIN(x, y)  (((x) > (y)) ? (y) : (x))
#define YPADDING(disp) ((disp)->drawRect.size.height*0.01)

/* various globals */

GLOB_QUAL const char hippoplotPS_c_rcsid[] = 
     "$Id: hplotPS.c,v 5.0 1993/08/17 21:55:51 rensing Exp $";

GLOB_QUAL const char hippoplotPS_h_rcsid[] = _HIPPOPLOTPS_H_RCSID_;

/*
 * other constants
 */
#define PI 3.1415926536
#define TWOPI (2.0*PI)
#define HALFPI (PI/2.0)

#define MAXNPTS_PRINT 500

static struct {
     float xScale;
     float yScale;
     float xMarg;
     float yMarg;
     float margWidth;
     float margHeight;
     float xOrig;
     float yOrig;
     float xMax;
     float yMax;
} data;
static float ctm_matrix[6] = {0.0,0.0,0.0,0.0,0.0,0.0};

static FILE *outfile = stdout;
static int inPage = 0;
static int nPages = 0;

/*
 * External C Functions 
 */
int drawText(char *s, float x, float y, float fontsize, float angle,
		    char xp, char yp );

/*
 * Internal C Functions 
 */
static void drawSides_PS(display disp, int inside);
static void drawWireFrame_PS(display disp);
static void drawMesh_PS(display disp);
static void drawTextVar(char *message, float x, float y, float fontSize,
    float rotation, float xAlignStep, float yAlignStep, char *fontName);

int initDrvr_PS( FILE *fl )
{
     outfile = fl;
     fprintf(outfile,"%%!PS-Adobe-2.0\n");
     fprintf(outfile,"%%%%Creator: hippoplotamus\n");
     fprintf(outfile,"%%%%Pages: (atend) 1\n");
     fprintf(outfile,"%%%%BoundingBox: (atend)\n");
     fprintf(outfile,"%%%%EndComments\n");
     fprintf(outfile,"\n\n");

     fprintf(outfile,"%% Add emulation of selectfont if needed\n");
     fprintf(outfile,"%%   taken from PS Lang. Ref. Manual, Appendix D.4\n");
     fprintf(outfile,"/*SF {\n");
     fprintf(outfile,"  exch findfont exch\n");
     fprintf(outfile,
	    "  dup type /arraytype eq {makefont}{scalefont} ifelse setfont\n");
     fprintf(outfile,"} bind def\n");
     fprintf(outfile,"\n");
     fprintf(outfile,"/languagelevel where\n");
     fprintf(outfile," {pop languagelevel} {1} ifelse\n");
     fprintf(outfile,
	     "2 lt {/SF /*SF load def}{/SF /selectfont load def} ifelse\n");
     
     return 0;
}

int endDrvr_PS( void )
{
     endPage_PS();
     fprintf(outfile,"%%%%Pages: %d %d\n",nPages,nPages);
     return 0;
}


int initPlot_PS( rectangle *draw, rectangle *margin, rectangle *user )
{
     data.xScale = margin->size.width/user->size.width;
     data.yScale = margin->size.height/user->size.height;
     data.xMarg = margin->origin.x;
     data.yMarg = margin->origin.y;
     data.margWidth = margin->size.width;
     data.margHeight = margin->size.height;
     data.xOrig = user->origin.x;
     data.yOrig = user->origin.y;
     data.xMax = user->origin.x + user->size.width;
     data.yMax = user->origin.y + user->size.height;
     
     ctm_matrix[0] = 1.0/data.xScale;
     ctm_matrix[3] = 1.0/data.yScale;

     inPage = 1;

     fprintf(outfile,"%%\n%%\n");

     return 0;
}

int endPage_PS( void )
{
     if (inPage)
     {
	  fprintf(outfile,"showpage\n");
	  fprintf(outfile,"%%\n%%\n");
     }
     inPage = 0;
     
     return 0;
}

int drawLine_PS(float *coords, int nCoords, linestyle_t linest)
{
     int i;
    
     int repeatCount;		/* this number + 32 must be < 255 */
     /* to display and < 127 for printing */
     /* to fit in 1 char */
     float *co;
     int count;
     
     fprintf(outfile,"%% drawLine_PS\n");

     repeatCount = 92;	/* work around apparent bug */
     fprintf(outfile,"gsave  ");

     /* get into user coords */
     fprintf(outfile,"%f %f translate  ",data.xMarg, data.yMarg);
     fprintf(outfile,"%f %f scale  ",data.xScale, data.yScale);
     fprintf(outfile,"%f %f translate\n", -data.xOrig, -data.yOrig);
     
     switch (linest)
     {
     default:
     case SOLID:
	  fprintf(outfile,"[] 0 setdash\n");
	  break;
     case DOT:
	  fprintf(outfile,"[3 5] 0 setdash\n");
	  break;
     case DASH:
	  fprintf(outfile,"[5 3] 0 setdash\n");
	  break;
     case DOTDASH:
	  fprintf(outfile,"[5 3 1 3] 0 setdash\n");
	  break;
     }
     
     co = coords;
     do
     {
	  if (nCoords > repeatCount) count = repeatCount;
	  else count = nCoords;
	  
	  fprintf(outfile,"gsave\nnewpath systemdict begin\n");
	  fprintf(outfile,"%f %f moveto\n",*co,*(co+1));
	  co += 2;
	  for (i=1; i<count; i++, co += 2)
	       fprintf(outfile,"%f %f lineto\n",*co, *(co+1));
	  fprintf(outfile,"end\n[%f %f %f %f %f %f] concat\n",
		  ctm_matrix[0],ctm_matrix[1],ctm_matrix[2],
		  ctm_matrix[3],ctm_matrix[4],ctm_matrix[5]);
	  fprintf(outfile,"stroke grestore\n");

	  co -= 2;		/* back up to connect segments */
	  nCoords -= (count - 1);
     }
     while (nCoords > 1);	/* 1 because we always back up 1 point */
                                /*  to connect the segments */
     
     fprintf(outfile,"grestore\n");
     return 0;
}



int drawPoints_PS(float *coords, int nCoords, plotsymbol_t symbol,
		   float symbolSize)
{
     
     int i;
     int filled=0;
     int count;
     int maxnpts;
     float xPointSide, yPointSide;
     float xHalfPointSide, yHalfPointSide;
     
     fprintf(outfile,"%% drawPoints_PS\n");
     
     maxnpts = MAXNPTS_PRINT;
     
     if (symbol == SOLIDSQUARE)
	  filled = 1;
     
     if (filled) maxnpts /= 5;
     
     xPointSide = symbolSize / data.xScale;
     yPointSide = symbolSize / data.yScale;
     xHalfPointSide = xPointSide / 2.0;
     yHalfPointSide = yPointSide / 2.0;
     
     fprintf(outfile,"gsave\n");
     
     /* get into user coords */
     fprintf(outfile,"%f %f translate  ", data.xMarg, data.yMarg);
     fprintf(outfile,"%f %f scale  ", data.xScale, data.yScale);
     fprintf(outfile,"%f %f translate\n", -data.xOrig, -data.yOrig);
     
     if (nCoords > maxnpts) i = maxnpts;
     else i = nCoords;
     do
     {
	  if (nCoords > maxnpts) count = maxnpts;
	  else count = nCoords;
	  
	  fprintf(outfile,"gsave\nnewpath systemdict begin\n");

	  switch (symbol)
	  {
	  case SQUARE:
	  case SOLIDSQUARE:
	       for (i = 0; i < count; i++)
	       {
		    fprintf(outfile,"%f %f moveto\n", 
			    *coords - xHalfPointSide,
			    *(coords+1) - yHalfPointSide);
		    coords += 2;
		    fprintf(outfile,"%f %f rlineto\n", xPointSide, 0.0);
		    fprintf(outfile,"%f %f rlineto\n", 0.0, yPointSide);
		    fprintf(outfile,"%f %f rlineto\n", -xPointSide, 0.0);
		    fprintf(outfile,"closepath\n");
	       }
	       break;
	       
	  case PLUS:
	       for (i = 0; i < count; i++)
	       {
		    fprintf(outfile,"%f %f moveto\n", 
			    *coords - xHalfPointSide,
			    *(coords+1));
		    coords += 2;
		    fprintf(outfile,"%f %f rlineto\n", xPointSide, 0.0);
		    fprintf(outfile,"%f %f rmoveto\n", -xHalfPointSide, 
			    yHalfPointSide);
		    fprintf(outfile,"%f %f rlineto\n", 0.0,	-yPointSide);
	       }
	       break;
	       
	  case TIMES:
	       for (i = 0; i < count; i++)
	       {
		    fprintf(outfile,"%f %f moveto\n", 
			    *coords - xHalfPointSide,
			    *(coords+1) - yHalfPointSide);
		    coords += 2;
		    fprintf(outfile,"%f %f rlineto\n", xPointSide, yPointSide);
		    fprintf(outfile,"%f %f rmoveto\n", 0.0, yPointSide);
		    fprintf(outfile,"%f %f rlineto\n", xPointSide, 
			    -yPointSide);
	       }
	       break;
	       
	  default:
	       break;
	  }
	  if (filled)
	  {
	       fprintf(outfile,"end\n");
	       fprintf(outfile,"fill grestore\n");
	  }
	  else
	  {
	       fprintf(outfile,"end\n[%f %f %f %f %f %f] concat\n",
		       ctm_matrix[0],ctm_matrix[1],ctm_matrix[2],
		       ctm_matrix[3],ctm_matrix[4],ctm_matrix[5]);
	       fprintf(outfile,"stroke grestore\n");
	  }
	  
	  nCoords -= count;
     }
     while (nCoords > 0);
     
     fprintf(outfile,"grestore\n");
     
     return 0;
}


int drawYError_PS(float *coords, float *errorYs, int nCoords)
{
#define ERRORCAPSIZE 2.0
     
     int i;
     int count;
     int maxnpts;
     float x, yhi, ylo;
     float halfErrorCap = ERRORCAPSIZE/data.xScale * 0.5;
     
     fprintf(outfile,"%% drawYError_PS\n");
     
     maxnpts = MAXNPTS_PRINT;
     
     if (nCoords > maxnpts) i = maxnpts;
     else i = nCoords;
     
     fprintf(outfile,"gsave\n");
     
     /* get into user coords */
     fprintf(outfile,"%f %f translate  ", data.xMarg, data.yMarg);
     fprintf(outfile,"%f %f scale  ", data.xScale, data.yScale);
     fprintf(outfile,"%f %f translate\n", -data.xOrig, -data.yOrig);
     
     do 
     {
	  if (nCoords > maxnpts) count = maxnpts;
	  else count = nCoords;
	  
	  fprintf(outfile,"gsave\nnewpath systemdict begin\n");
	  for (i = 0; i < count; i++)
	  {
	       x = *coords++;	/* x coord */
	       coords++;	/* skip over this y coord - not needed */
	       yhi = *errorYs++; /* y of high end of error bar */
	       ylo = *errorYs++; /* y of low end of error bar */
	       
	       fprintf(outfile,"%f %f moveto\n",x,ylo);
	       fprintf(outfile,"%f %f lineto\n",x,yhi);
	       fprintf(outfile,"%f %f moveto\n", x - halfErrorCap, yhi);
	       fprintf(outfile,"%f %f lineto\n", x + halfErrorCap, yhi);
	       fprintf(outfile,"%f %f moveto\n", x - halfErrorCap, ylo);
	       fprintf(outfile,"%f %f lineto\n", x + halfErrorCap, ylo);
	  }
	  
	  fprintf(outfile,"end\n[%f %f %f %f %f %f] concat\n",
		  ctm_matrix[0],ctm_matrix[1],ctm_matrix[2],
		  ctm_matrix[3],ctm_matrix[4],ctm_matrix[5]);
	  fprintf(outfile,"stroke grestore\n");
	  nCoords -= count;
     }
     while (nCoords > 0);
     
     fprintf(outfile,"grestore\n");
     
     return 0;
}


int drawXError_PS(float *coords, float *errorXs, int nCoords)
{
     int i;
     int count;
     int maxnpts;
     float halfErrorCap = ERRORCAPSIZE/data.yScale * 0.5;
     float y, xlo, xhi; 
     
     fprintf(outfile,"%% drawXError_PS\n");
     
     maxnpts = MAXNPTS_PRINT;
     
     if (nCoords > maxnpts) i = maxnpts;
     else i = nCoords;
     
     fprintf(outfile,"gsave\n");
      
     /* get into user coords */
     fprintf(outfile,"%f %f translate  ", data.xMarg, data.yMarg);
     fprintf(outfile,"%f %f scale  ", data.xScale, data.yScale);
     fprintf(outfile,"%f %f translate\n", -data.xOrig, -data.yOrig);
     
     do 
     {
	  if (nCoords > maxnpts) count = maxnpts;
	  else count = nCoords;
	  
	  fprintf(outfile,"gsave\nnewpath systemdict begin\n");
	  for (i = 0; i < count; i++)
	  {
	       coords++;	/* skip over this x coord - not needed */
	       y = *coords++;	/* y coord */
	       xhi = *errorXs++; /* x of high end of error bar */
	       xlo = *errorXs++; /* x of low end of error bar */
	       
		fprintf(outfile,"%f %f moveto\n",xlo,y);
		fprintf(outfile,"%f %f lineto\n",xhi,y);
		fprintf(outfile,"%f %f moveto\n", xlo, y - halfErrorCap);
		fprintf(outfile,"%f %f lineto\n", xlo, y + halfErrorCap);
		fprintf(outfile,"%f %f moveto\n", xhi, y - halfErrorCap);
		fprintf(outfile,"%f %f lineto\n", xhi, y + halfErrorCap);
	  }
	  
		fprintf(outfile,"end\n[%f %f %f %f %f %f] concat\n",
				ctm_matrix[0],ctm_matrix[1],ctm_matrix[2],
				ctm_matrix[3],ctm_matrix[4],ctm_matrix[5]);
		fprintf(outfile,"stroke grestore\n");
	  nCoords -= count;
     }
     while (nCoords > 0);

     fprintf(outfile,"grestore\n");
     
     return 0;
}

int drawYTicks_PS( float *y, int nt, float tickwidth, int side )
{
     int i;
     float start;
     
     tickwidth /= data.xScale;
     
     fprintf(outfile,"%% drawYTicks_PS\n");

     if (side == 0)
	  start = data.xOrig;
     else
	  start = data.xMax - tickwidth;

     fprintf(outfile,"gsave\n");
     
     /* get into user coords */
     fprintf(outfile,"%f %f translate  ", data.xMarg, data.yMarg);
     fprintf(outfile,"%f %f scale  ", data.xScale, data.yScale);
     fprintf(outfile,"%f %f translate\n",-data.xOrig, -data.yOrig);
     
     fprintf(outfile,"newpath systemdict begin\n");
     for (i = 0; i < nt; i++)
     {
	  fprintf(outfile,"%f %f moveto  ", start, y[i] );
	  fprintf(outfile,"%f %f rlineto\n", tickwidth, 0.0 );
     }
     fprintf(outfile,"end\n[%f %f %f %f %f %f] concat\n",
	     ctm_matrix[0],ctm_matrix[1],ctm_matrix[2],
	     ctm_matrix[3],ctm_matrix[4],ctm_matrix[5]);
     fprintf(outfile,"stroke\n");
     
     fprintf(outfile,"grestore\n");
     
     return 0;
}

int drawXTicks_PS( float *y, int nt, float tickwidth, int side )
{
     int i;
     float start;
     
     tickwidth /= data.yScale;
     
     fprintf(outfile,"%% drawXTicks_PS\n");
     
     if (side == 0)
	  start = data.yOrig;
     else
	  start = data.yMax - tickwidth;

     fprintf(outfile,"gsave\n");
     
     /* get into user coords */
     fprintf(outfile,"%f %f translate  ", data.xMarg, data.yMarg);
     fprintf(outfile,"%f %f scale  ", data.xScale, data.yScale);
     fprintf(outfile,"%f %f translate\n", -data.xOrig, -data.yOrig);
     
     fprintf(outfile,"newpath systemdict begin\n");
     for (i = 0; i < nt; i++)
     {
	  fprintf(outfile,"%f %f moveto  ", y[i], start );
	  fprintf(outfile,"%f %f rlineto\n", 0.0, tickwidth );
     }
     fprintf(outfile,"end\n[%f %f %f %f %f %f] concat\n",
	     ctm_matrix[0],ctm_matrix[1],ctm_matrix[2],
	     ctm_matrix[3],ctm_matrix[4],ctm_matrix[5]);
     fprintf(outfile,"stroke\n");
     
     
     fprintf(outfile,"grestore\n");
     
     return 0;
}

int drawMag_PS(float x, float y, int mag, float fontSize)
{
     char str[10];
     
     fprintf(outfile,"%% drawMag_PS\n");
     
     fprintf(outfile,"(Helvetica) %f SF\n",fontSize);
     fprintf(outfile,"%f %f moveto\n", x, y );
     fprintf(outfile,"(x10) show");
     fprintf(outfile,"%f %f rmoveto\n", 0.0, 0.5*fontSize );
     sprintf(str,"%d",mag);
     fprintf(outfile,"(%s) show\n", str);
     
     return 0;
}


int drawText_PS(char *string, float x, float y, float fontSize, 
		 float rotation, char xAlign, char yAlign)
{
     float xStep = 0.0, yStep = 0.0;
     
     fprintf(outfile,"%% drawText_PS\n");
     
     switch (yAlign)
     {
     case 'C':
     case 'c':
	  yStep = 0.4;
	  break;
	  
     case 'T':
     case 't':
	  yStep = 0.8;
	  break;
     }
     
     switch (xAlign)
     {
     case 'C':
     case 'c':
	  xStep = 0.5;
	  break;
     case 'R':
     case 'r':
	  xStep = 1.0;
	  break;
     }
     
     fprintf(outfile,"gsave\n");
     fprintf(outfile,"(Helvetica) %f SF\n", fontSize);
     fprintf(outfile,"%f %f translate %f rotate\n",x,y,rotation);
     
     fprintf(outfile,"(%s) stringwidth pop\n", string);
     fprintf(outfile,"%f neg mul %f moveto\n",xStep,-fontSize*yStep);
     fprintf(outfile,"(%s) show\n",string);
     fprintf(outfile,"grestore\n");
     
     return 0;
}



int drawColor2D_PS(int nXBins, int nYBins, float binMin, float binMax, 
		     float *bins, int useColor )
{
     int  iYBin;
     int totBins = nXBins * nYBins;
     float deltaX = data.margWidth / nXBins;
     float deltaY = data.margHeight / nYBins;
     float grayScale, nearWhite = 0.9;
     float  xCoord, yCoord;
     int i, count;
     int maxnpts = 30;
     
     fprintf(outfile,"%% drawColor2D_PS\n");
     
     /* 
      * this routine leaves color in unpredictable state, 
      * so we need a gsave/grestore
      */ 
     fprintf(outfile,"gsave\n");    
     
     if (binMin == binMax)
	  grayScale = 1.0;
     else 
	  grayScale = nearWhite / (binMax - binMin);
     xCoord = data.xMarg;
     yCoord = data.yMarg;
     iYBin = 0;
     
     do 
     {
	  if (totBins > maxnpts) count = maxnpts;
	  else count = totBins;
	  
	  for (i = 0; i < count; i++)
	  {
	       /* bins are arranged as bins[x][y] with y changing fastest */

	       fprintf(outfile,"newpath systemdict begin\n");
	       fprintf(outfile,"%f setgray\n", (binMax - *bins)*grayScale);
	       fprintf(outfile,"%f %f moveto %f %f rlineto\n",
		       xCoord, yCoord, deltaX, 0.0 );
	       fprintf(outfile,"%f %f rlineto %f %f rlineto closepath\n",
		       0.0, deltaY, -deltaX, 0.0 );
	       fprintf(outfile,"end fill\n");
	       bins++;
	       yCoord += deltaY;
	       iYBin++;
	       if ( iYBin == nYBins) 
	       {
		    iYBin = 0;
		    yCoord = data.yMarg;
		    xCoord += deltaX;
		    
	       }
	  }
	  totBins -= count;
	  
     }
     while (totBins > 0);
     
     fprintf(outfile,"grestore\n");
     return 0;
}


int drawScatter3D_PS(display disp, float *coords, int nCoords)
{
    threeD_t	       *threeD;    	  
    static int          inside = 1, outside = 0;
    float 		x, y;
    float 		fontSize;
    char 		string[80];
    int 		i;
    int 		filled=0;
    int 		count;
    int 		maxnpts;
    float 		symSize;
    float	       *newCoords;
    float 		xPointSide, yPointSide;
    float 		xHalfPointSide, yHalfPointSide;
     
    if (disp->threeDWorkArea == NULL) h3D_init3D(disp);
    threeD = disp->threeDWorkArea;	/* set local pointer */

    fprintf(outfile,"%% drawScatter3D_PS\n");
     
    if (disp->plotSymbol == SOLIDSQUARE)
	filled = 1;
     
    maxnpts = MAXNPTS_PRINT;
    if (filled) maxnpts /= 5;
    
   /* Check that correct 'user space' is set */
    if (disp->doScatter) {
	h3D_checkPointScale(disp, nCoords);
    }     

 /*
  * Get into user plotting space, ie (-1,-1) to (+1,+1) 
  * This is the user 3D space after going through the transformation to 2D 
  */
    fprintf(outfile,"gsave\n");
    fprintf(outfile,"0.0 setlinewidth\n");
    fprintf(outfile,"%f %f translate\n", disp->drawRect.origin.x, 
    	disp->drawRect.origin.y);
    fprintf(outfile,"%f %f scale\n", disp->drawRect.size.width/2.0, 
    	disp->drawRect.size.height/2.0); 
    fprintf(outfile,"1.0 1.0 translate\n");

 /*
  * Now do transformations
  */
    if (disp->doCube && disp->flags.drawAxes) {
	h3D_transformCube(disp);
	drawSides_PS(disp, inside);
    }
    if (disp->doScatter) {
	if (threeD->reCalculateScatterPoints) {
	    h3D_checkAllocScatterResults(disp, nCoords);
	    h3D_renderXYPS(disp, coords);
	    threeD->reCalculateScatterPoints = 0;
	}
    newCoords = threeD->scatterResults;

    symSize = disp->symbolSize*(2.0/disp->drawRect.size.width); 
    xPointSide = symSize;
    yPointSide = symSize;
    xHalfPointSide = xPointSide / 2.0;
    yHalfPointSide = yPointSide / 2.0;
     
    if (nCoords > maxnpts) i = maxnpts;
    else i = nCoords;
    do
    {
	if (nCoords > maxnpts) count = maxnpts;
	else count = nCoords;
	  
	fprintf(outfile,"gsave\nnewpath systemdict begin\n");

	switch (disp->plotSymbol)
	{
	case SQUARE:
	case SOLIDSQUARE:
	    for (i = 0; i < count; i++)
	    {
		fprintf(outfile,"%f %f moveto\n", *newCoords - xHalfPointSide,
		    *(newCoords+1) - yHalfPointSide);
		newCoords += 2;
		fprintf(outfile,"%f %f rlineto\n", xPointSide, 0.0);
		fprintf(outfile,"%f %f rlineto\n", 0.0, yPointSide);
		fprintf(outfile,"%f %f rlineto\n", -xPointSide, 0.0);
		fprintf(outfile,"closepath\n");
	    }
	    break;
	       
	case PLUS:
	    for (i = 0; i < count; i++)
	    {
		fprintf(outfile,"%f %f moveto\n", *newCoords - xHalfPointSide,
		    *(newCoords+1));
		newCoords += 2;
		fprintf(outfile,"%f %f rlineto\n", xPointSide, 0.0);
		fprintf(outfile,"%f %f rmoveto\n", -xHalfPointSide, 
		    yHalfPointSide);
		fprintf(outfile,"%f %f rlineto\n", 0.0, -yPointSide);
	    }
	    break;
	       
	case TIMES:
	    for (i = 0; i < count; i++)
	    {
		fprintf(outfile,"%f %f moveto\n", *newCoords - xHalfPointSide,
		    *(newCoords+1) - yHalfPointSide);
		newCoords += 2;
		fprintf(outfile,"%f %f rlineto\n", xPointSide, yPointSide);
		fprintf(outfile,"%f %f rmoveto\n", 0.0, yPointSide);
		fprintf(outfile,"%f %f rlineto\n", xPointSide, -yPointSide);
	    }
	    break;
	       
	default:
	    break;
	}
	if (filled)
	{
	    fprintf(outfile,"end\n");
	    fprintf(outfile,"fill grestore\n");
	}
	else
	{
	    fprintf(outfile,"end\n[%f %f %f %f %f %f] concat\n",
		ctm_matrix[0],ctm_matrix[1],ctm_matrix[2],
		ctm_matrix[3],ctm_matrix[4],ctm_matrix[5]);
	    fprintf(outfile,"stroke grestore\n");
	}
	  
	nCoords -= count;
    }
    while (nCoords > 0);
     
    }
    if (disp->doCube && disp->flags.drawAxes) {
	drawSides_PS(disp, outside);
    }

    fprintf(outfile,"grestore\n");

    if (disp->flags.drawTitles) {
     	fontSize = disp->drawRect.size.width*0.05;
     	fontSize = MIN(fontSize, 
	    (disp->drawRect.size.height - 
	    disp->marginRect.size.height - 2*YPADDING(disp) -
	    (disp->marginRect.origin.y-disp->drawRect.origin.y)));
     	x = disp->marginRect.origin.x + 0.5 * disp->marginRect.size.width;
     	y = disp->drawRect.origin.y + disp->drawRect.size.height 
            - YPADDING(disp);
     	h_expandLabel(string,disp->title,80,disp);
     	if (fontSize > disp->marginRect.size.width/strlen(string)*2)
     	{
	    fontSize = disp->drawRect.size.width/strlen(string)*2;
	    x = disp->drawRect.origin.x + 0.5 * disp->drawRect.size.width;
     	}
     
     	drawText(string, x, y, fontSize, 0.0, 'c', 't');
    }

    return 0;
}

static void drawSides_PS(display disp, int inside)
{
    threeD_t	       *threeD;    	  
    int                 side, p, q, r, s;
    int	                insideVisible, showFace;
    int                 i;
    static int          corners[4][4] = {0, 1, 5, 4, 1, 2, 6, 5, 2, 3, 7, 6, 3, 
    			0, 4, 7};
    static int          leftmostChoices[4][2] = {3, 2, 0, 3, 1, 0, 2, 1};
    int                 firstChoice, secondChoice;
    int                 doFirstChoice;
    float              *tickU, *tickV, *tickU2, *tickV2;
    float               tickLength = 0.03;
    float		tickFontSize=0.05, strShift, labelFontSize=0.08;
    char	       *font = "Times-Roman";
    float		labelX, labelY, labelShift = 0.14, labelAngle;
    float		labelRotation;
    char 		string[80];
    
    threeD = disp->threeDWorkArea;	/* set local pointer */

 /* figure out whose left edge to put the tick marks on */
    firstChoice = leftmostChoices[threeD->preferredFace][0];
    secondChoice = leftmostChoices[threeD->preferredFace][1];
    doFirstChoice = 0;

    for (side = 0; side < 4; side++) {
	p = corners[side][0];
	q = corners[side][1];
	r = corners[side][2];
	s = corners[side][3];

	insideVisible = 0;
	if (threeD->cubeV[q] > threeD->cubeV[p]) {
	    if (threeD->cubeU[s] > (threeD->cubeU[p] + (threeD->cubeV[s] 			
		- threeD->cubeV[p]) * (threeD->cubeU[r]
		- threeD->cubeU[p]) / (threeD->cubeV[r] -
		threeD->cubeV[p]))) {
		insideVisible = 1;
	    }
	} else {
	    if (threeD->cubeU[p] > (threeD->cubeU[q] +
		(threeD->cubeV[p] - threeD->cubeV[q]) * (threeD->cubeU[s]
		- threeD->cubeU[q]) / (threeD->cubeV[s] -
		threeD->cubeV[q]))) {
		insideVisible = 1;
	    }
	}

	showFace = (inside) ? insideVisible : !insideVisible;

	if (showFace) {
    	    fprintf(outfile,"0.0 setgray\n"); 
    	    fprintf(outfile,"%f %f moveto\n", threeD->cubeU[p], 
	    	threeD->cubeV[p]); 
    	    fprintf(outfile,"%f %f lineto\n", threeD->cubeU[q], 
	    	threeD->cubeV[q]);
    	    fprintf(outfile,"%f %f lineto\n", threeD->cubeU[r], 
	    	threeD->cubeV[r]);
	    fprintf(outfile,"%f %f lineto\n", threeD->cubeU[s], 
	    	threeD->cubeV[s]); 
    	    fprintf(outfile,"closepath\n"); 
    	    fprintf(outfile,"stroke\n"); 

	    /* now do the inside and outside tick marks */
	    if (!disp->doSpeedy) {
	    	if (inside) {
		    if (threeD->nZTicks > 0) {
		    	if (side == firstChoice)
			    doFirstChoice = 1;
    	    		fprintf(outfile,"gsave\n"); 
    	    		fprintf(outfile,"[.005 .01] 0 setdash\n"); 

		    	/* point to correct ticks for these 2 verticals */
		    	tickU = &threeD->zTickU[p * threeD->nZTicks];
		    	tickV = &threeD->zTickV[p * threeD->nZTicks];
		    	tickU2 = &threeD->zTickU[q * threeD->nZTicks];
		    	tickV2 = &threeD->zTickV[q * threeD->nZTicks];

		    	for (i = 0; i < threeD->nZTicks; i++) {
    	    		    fprintf(outfile,"%f %f moveto\n", tickU[i], 
			    	tickV[i]);
    	    		    fprintf(outfile,"%f %f lineto\n", tickU2[i], 
			    	tickV2[i]);
		    	}
    	    		fprintf(outfile,"stroke\n"); 
    	    		fprintf(outfile,"grestore\n");	/* remove setdash */ 
		    }
	    	} else {
	            /* do base ticks for outside face */
		    p = corners[side][0];
		    if (p == 0 || p == 2) {
		    	if (threeD->nXTicks > 0) {	/* point to correct set
							 * of x ticks for this
							 * base line */
			    tickU = &threeD->xTickU[(p / 2) * threeD->nXTicks];
			    tickV = &threeD->xTickV[(p / 2) * threeD->nXTicks];
			    for (i = 0; i < threeD->nXTicks; i++) {
    	    		    	fprintf(outfile,"%f %f moveto\n", tickU[i], 
			    	    tickV[i]);
    	    		    	fprintf(outfile,"%f %f rlineto\n", 0.0, 
				    -tickLength);
				if (disp->theta < -HALFPI || 
			    	    disp->theta > HALFPI) {
			    	    strShift = 0.5 * (1.0 + sin(disp->theta));
			    	} else {
			    	    strShift = 0.5 * (1.0 - sin(disp->theta));
				}
	  	    		drawTextVar(threeD->xLabels[i], tickU[i],
				    (tickV[i]-tickLength-0.04), tickFontSize, 
				    0.0, strShift, 0.0, font);
			    }
    	    		    fprintf(outfile,"stroke\n"); 
		    	    if (disp->flags.drawTitles) {
			    labelAngle = 	
				atan2((tickV[threeD->nXTicks-1]-tickV[0]),
		    	    	(tickU[threeD->nXTicks-1]-tickU[0]));
			    if (disp->theta < -HALFPI || 
			    	disp->theta > HALFPI) labelAngle-=PI;
			    if (labelAngle < TWOPI) labelAngle+=TWOPI;
		    	    labelX = tickU[0] +
			    	(tickU[threeD->nXTicks-1]-tickU[0])/2.0
				+ labelShift*sin(labelAngle);
		    	    labelY = tickV[0] +
			    	(tickV[threeD->nXTicks-1]-tickV[0])/2.0
				 - labelShift*cos(labelAngle);
			    labelRotation = labelAngle *180.0/PI; 
			    h_expandLabel(string,disp->xAxis.label,80,disp);
    		    	    drawText(string, labelX, labelY, 
			    	labelFontSize, labelRotation, 'C', 'T');
			    }
		    	}
		    } else {
		    	if (threeD->nYTicks > 0) {  
		            /* point to correct y ticks for this base line */
			    tickU = &threeD->yTickU[(p / 2) * threeD->nYTicks];
			    tickV = &threeD->yTickV[(p / 2) * threeD->nYTicks];
			    for (i = 0; i < threeD->nYTicks; i++) {
    	    		    	fprintf(outfile,"%f %f moveto\n", tickU[i], 
			    	    tickV[i]);
    	    		    	fprintf(outfile,"%f %f rlineto\n", 0.0, 
				    -tickLength);
			    	if (disp->theta < 0.0) {
			    	    strShift = 0.5 * (1.0 - cos(disp->theta));
			        } else {
			    	    strShift = 0.5 * (1.0 + cos(disp->theta));
			    	}
	  	    		drawTextVar(threeD->yLabels[i], tickU[i],
				    (tickV[i]-tickLength-0.04), tickFontSize, 
				    0.0, strShift, 0.0, font);
			    }
    	    		    fprintf(outfile,"stroke\n"); 
		    	    if (disp->flags.drawTitles) {
		    	    labelAngle = 	
				atan2((tickV[threeD->nYTicks-1]-tickV[0]),
		    	    	(tickU[threeD->nYTicks-1]-tickU[0]));
			    if (disp->theta > 0.0) labelAngle-=PI; 
			    if (labelAngle < TWOPI) labelAngle+=TWOPI;
		    	    labelX = tickU[0] +
			    	(tickU[threeD->nYTicks-1]-tickU[0])/2.0
				+ labelShift*sin(labelAngle);
		    	    labelY = tickV[0] +
			    	(tickV[threeD->nYTicks-1]-tickV[0])/2.0
				 - labelShift*cos(labelAngle);
			    labelRotation = labelAngle *180.0/PI; 
			    h_expandLabel(string,disp->yAxis.label,80,disp);
    		    	    drawText(string, labelX, labelY, 
			    	labelFontSize, labelRotation, 'C', 'T');
			    }
		    	}
		    }
	    	}
	    }
	}
    }

 /* now the tick marks on the leftmost vertical */
    if (!disp->doSpeedy) {
    	if (threeD->nZTicks > 0) {
	    if (inside) {
	    	if (doFirstChoice) {
		    side = firstChoice;
	    	} else {
		    side = secondChoice;
	    	}
	    	q = corners[side][1];

		/* point to correct set of ticks for this vertical */
	    	tickU = &threeD->zTickU[q * threeD->nZTicks];
	    	tickV = &threeD->zTickV[q * threeD->nZTicks];
	    	for (i = 0; i < threeD->nZTicks; i++) {
    	    	    fprintf(outfile,"%f %f moveto\n", tickU[i], tickV[i]);
    	    	    fprintf(outfile,"%f %f rlineto\n", -tickLength, 0.0);
	  	    drawTextVar(threeD->zLabels[i], (tickU[i]-tickLength-0.01),
			tickV[i], tickFontSize, 0.0, 1.0, 0.0, font);
	    	}
    	    	fprintf(outfile,"stroke\n"); 
		if ((disp->graphtype == THREEDSCATTER) && 	
		    disp->flags.drawTitles) {
		    labelX = tickU[0] + 
		    	(tickU[threeD->nZTicks-1]-tickU[0])/2.0 - labelShift;
		    labelY = tickV[0] + 	
		        (tickV[threeD->nZTicks-1]-tickV[0])/2.0;
		    labelAngle = atan2((tickV[0]-tickV[threeD->nZTicks-1]),
		        (tickU[0]-tickU[threeD->nZTicks-1]))*180.0/PI;
		    h_expandLabel(string,disp->zAxis.label,80,disp);
    		    drawText(string, labelX, labelY, 
		        labelFontSize, labelAngle, 'C', 'T');
		}
	    }
	}
    }
    return;
}

/*
 * Draw a 'wire-frame' lego plot in the given drawing space 
 */
static void drawWireFrame_PS(display disp)
{
    threeD_t	       *threeD;    	  
    float               *p, *q, *u, *v;
    int                 i;

    threeD = disp->threeDWorkArea;	/* set local pointer */

    u = threeD->legoResults[0];
    v = threeD->legoResults[1];
    for (i = 0; i < threeD->nLegoPoints; i += 8) {
	p = &u[i];
	q = &v[i];
	fprintf(outfile,"%f %f moveto\n", p[0], q[0]);
	fprintf(outfile,"%f %f lineto\n", p[1], q[1]);
	fprintf(outfile,"%f %f lineto\n", p[2], q[2]);
	fprintf(outfile,"%f %f lineto\n", p[3], q[3]);
	fprintf(outfile,"%f %f lineto\n", p[0], q[0]);
	fprintf(outfile,"%f %f lineto\n", p[4], q[4]);
	fprintf(outfile,"%f %f lineto\n", p[5], q[5]);
	fprintf(outfile,"%f %f lineto\n", p[6], q[6]);
	fprintf(outfile,"%f %f lineto\n", p[7], q[7]);
	fprintf(outfile,"%f %f lineto\n", p[4], q[4]);
	fprintf(outfile,"%f %f moveto\n", p[1], q[1]);
	fprintf(outfile,"%f %f lineto\n", p[5], q[5]);
	fprintf(outfile,"%f %f moveto\n", p[2], q[2]);
	fprintf(outfile,"%f %f lineto\n", p[6], q[6]);
	fprintf(outfile,"%f %f moveto\n", p[3], q[3]);
	fprintf(outfile,"%f %f lineto\n", p[7], q[7]);
    }
    return;
}

/*
 * Draw a mesh surface through the to centers of each 'lego' 
 */
static void drawMesh_PS(display disp)
{
    threeD_t	       *threeD;  	  
    float              *p, *q, *u, *v;
    int                 i, j, k;

    threeD = disp->threeDWorkArea;	/* set local pointer */

    u = threeD->legoResults[0];
    v = threeD->legoResults[1];
    for (i = 0; i < disp->bins.xAxis.nBins; i++) {
	k = i * 8 * disp->bins.yAxis.nBins;
	p = &u[k];
	q = &v[k];
	fprintf(outfile,"%f %f moveto\n",((p[4]+p[6])/2.0),((q[4]+q[6])/2.0));
	for (j = 1; j < disp->bins.yAxis.nBins; j++) {
	    p = &u[k + j * 8];
	    q = &v[k + j * 8];
	fprintf(outfile,"%f %f lineto\n",((p[4]+p[6])/2.0),((q[4]+q[6])/2.0));
	}
    }

    for (j = 0; j < disp->bins.yAxis.nBins; j++) {
	k = j * 8;
	p = &u[k];
	q = &v[k];
	fprintf(outfile,"%f %f moveto\n",((p[4]+p[6])/2.0),((q[4]+q[6])/2.0));
	for (i = 1; i < disp->bins.xAxis.nBins; i++) {
	    p = &u[k + i * 8 * disp->bins.yAxis.nBins];
	    q = &v[k + i * 8 * disp->bins.yAxis.nBins];
	fprintf(outfile,"%f %f lineto\n",((p[4]+p[6])/2.0),((q[4]+q[6])/2.0));
	}
    }
    return;
}


int drawLego2D_PS(display disp)
{
    threeD_t	       *threeD;    	  
    int                 i;
    static int          corners0[4][8] = {3, 0, 4, 7, 0, 1, 5, 4,
					  0, 1, 5, 4, 1, 2, 6, 5,
					  1, 2, 6, 5, 2, 3, 7, 6,
					  2, 3, 7, 6, 3, 0, 4, 7};
    static int          corners1[4][8] = {0, 1, 5, 4, 3, 0, 4, 7,
					  1, 2, 6, 5, 0, 1, 5, 4,
					  2, 3, 7, 6, 1, 2, 6, 5,
					  3, 0, 4, 7, 2, 3, 7, 6};
    int                *cornerIndex;
    int                	thisCorner, nearTopCorner, farTopCorner;
    static int         	inside = 1, outside = 0;
    float              *x, *y;
    float 		titleX, titleY;
    float 		fontSize;
    char 		string[80];

    if (disp->threeDWorkArea == NULL) h3D_init3D(disp);

    threeD = disp->threeDWorkArea;	/* set local pointer */

    fprintf(outfile,"%% drawLego2D_PS\n");
    fprintf(outfile,"0.0 setlinewidth\n");
     
   /* Check that correct 'user space' is set */
    if (disp->doFill || disp->doWireFrame || disp->doMesh){
	h3D_checkBinScale(disp);
    } 

 /*
  * Get into user plotting space, ie (-1,-1) to (+1,+1) 
  * This is the user 3D space after going through the transformation to 2D 
  */
    fprintf(outfile,"gsave\n");
    fprintf(outfile,"%f %f translate\n", disp->drawRect.origin.x, 
    	disp->drawRect.origin.y);
    fprintf(outfile,"%f %f scale\n", disp->drawRect.size.width/2.0, 
    	disp->drawRect.size.height/2.0);
    fprintf(outfile,"1.0 1.0 translate\n");

 /*
  * Now do transformations and drawing
  */
    if (disp->doCube && disp->flags.drawAxes) {
	h3D_transformCube(disp);
	drawSides_PS(disp, inside);
    }

    if (disp->doFill && !disp->doSpeedy) { 
    	h3D_transformLego(disp);

	/* draw the blocks, starting from farthest */
	for (i = threeD->numBlocks - 1; i >= 0; i--) {
	    x = threeD->blockPointer[i]->xData;
	    y = threeD->blockPointer[i]->yData;
	    thisCorner = threeD->blockPointer[i]->nearCorner;
	    if (y[4] > y[0]) {	/* might as well skip drawing the zero bins */
		if (thisCorner == threeD->preferredFace) {
		    cornerIndex = &corners0[thisCorner][0];
		} else {
		    cornerIndex = &corners1[thisCorner][0];
		}
    		fprintf(outfile,"%f %f moveto\n", x[cornerIndex[0]],
		    y[cornerIndex[0]]);
    		fprintf(outfile,"%f %f lineto\n", x[cornerIndex[1]],
		    y[cornerIndex[1]]);
    		fprintf(outfile,"%f %f lineto\n", x[cornerIndex[2]],
		    y[cornerIndex[2]]);
    		fprintf(outfile,"%f %f lineto\n", x[cornerIndex[3]],
		    y[cornerIndex[3]]);
    		fprintf(outfile,"closepath\n");
    		fprintf(outfile,"%f setgray\n", disp->color[cornerIndex[0]]);
		if (disp->doWireFrame) {
    		    fprintf(outfile,"gsave fill grestore 0.0 setgray stroke\n");
		} else {
    		    fprintf(outfile,"fill\n");
		}
    		fprintf(outfile,"%f %f moveto\n", x[cornerIndex[4]],
		    y[cornerIndex[4]]);
    		fprintf(outfile,"%f %f lineto\n", x[cornerIndex[5]],
		    y[cornerIndex[5]]);
    		fprintf(outfile,"%f %f lineto\n", x[cornerIndex[6]],
		    y[cornerIndex[6]]);
    		fprintf(outfile,"%f %f lineto\n", x[cornerIndex[7]],
		    y[cornerIndex[7]]);
    		fprintf(outfile,"closepath\n");
    		fprintf(outfile,"%f setgray\n", disp->color[cornerIndex[4]]);
		if (disp->doWireFrame) {
    		    fprintf(outfile,"gsave fill grestore 0.0 setgray stroke\n");
		} else {
    		    fprintf(outfile,"fill\n");
		}
	    }
	    /* determine if top is visible */
	    nearTopCorner = thisCorner + 4;
	    farTopCorner = nearTopCorner + 2;
	    if (farTopCorner > 7)
		farTopCorner -= 4;
	    if (y[farTopCorner] > y[nearTopCorner]) {
    		fprintf(outfile,"%f %f moveto\n", x[4], y[4]);
    		fprintf(outfile,"%f %f lineto\n", x[5], y[5]);
    		fprintf(outfile,"%f %f lineto\n", x[6], y[6]);
    		fprintf(outfile,"%f %f lineto\n", x[7], y[7]);
    		fprintf(outfile,"closepath\n");
    		fprintf(outfile,"%f setgray\n", disp->color[4]);
		if (disp->doWireFrame) {
    		    fprintf(outfile,"gsave fill grestore 0.0 setgray stroke\n");
		} else {
    		    fprintf(outfile,"fill\n");
		}
	    }
	}
    }
    /* end of doFill */

    else if (disp->doWireFrame || (disp->doFill && !disp->doSpeedy)) {
	h3D_transformWireFrame(disp);
	drawWireFrame_PS(disp);
    }

    if (disp->doMesh) {
	h3D_transformMesh(disp);
	drawMesh_PS(disp);
    }

    if (disp->doCube && disp->flags.drawAxes) {
	drawSides_PS(disp, outside);
    }

    fprintf(outfile,"grestore\n");

    if (disp->flags.drawTitles) {
     	fontSize = disp->drawRect.size.width*0.05;
     	fontSize = MIN(fontSize, 
	    (disp->drawRect.size.height - 
	    disp->marginRect.size.height - 2*YPADDING(disp) -
	    (disp->marginRect.origin.y-disp->drawRect.origin.y)));
     	titleX = disp->marginRect.origin.x + 0.5 * disp->marginRect.size.width;
     	titleY = disp->drawRect.origin.y + disp->drawRect.size.height 
            - YPADDING(disp);
     	h_expandLabel(string,disp->title,80,disp);
     	if (fontSize > disp->marginRect.size.width/strlen(string)*2)
     	{
	    fontSize = disp->drawRect.size.width/strlen(string)*2;
	    titleX = disp->drawRect.origin.x + 0.5 * disp->drawRect.size.width;
     	}
     
     	drawText(string, titleX, titleY, fontSize, 0.0, 'c', 't');
    }

    return 0;
}


int shade_PS(float xlow, float xhigh, float ylow, float yhigh )
{
     fprintf(outfile,"%% shade_PS\n");
     
     fprintf(outfile,"gsave\n");
     /*     PSsetalpha(0.0);*/
     fprintf(outfile,"%f setgray\n", 0.6);	
     fprintf(outfile,"newpath systemdict begin\n");
     fprintf(outfile,"%f %f moveto %f %f rlineto\n",
	     xlow, ylow, xhigh-xlow, 0.0 );
     fprintf(outfile,"%f %f rlineto %f %f rlineto closepath\n",
	     0.0, yhigh-ylow, xlow-xhigh, 0.0 );
     fprintf(outfile,"end\n");
     fprintf(outfile,"fill grestore\n");
     
     return 0;
}

/*   
 *  drawTextVar - draw Text with specified rotation and positioning.
 */
static void drawTextVar(char *message, float x, float y, float fontSize,
    float rotation, float xAlignStep, float yAlignStep, char *fontName)
{
    fprintf(outfile,"gsave\n");
    fprintf(outfile,"(%s) %f selectfont\n", fontName, fontSize);
    fprintf(outfile,"%f %f translate\n", x, y);
    fprintf(outfile,"%f rotate\n", rotation);
    fprintf(outfile,"(%s) dup stringwidth pop\n", message);
    fprintf(outfile,"%f neg mul %f %f neg mul moveto show\n", xAlignStep, 
    	fontSize, yAlignStep);
    fprintf(outfile,"grestore\n");
    return;
}



These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.