This is hplotNxt.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.
*
* $Header: /nfs/ebnextk/LocalSources/hippoplotamus/hplotNxt.c,v 5.0 1993/08/17 21:55:37 rensing Exp $
*
* by jonas karlsson, at SLAC, August 1990
* split up by Paul Rensing, Feb 28,1991
* modified by M. Gravina, March 28, 1991
*/
#include <string.h>
#include <stdlib.h>
#include <math.h>
#import <appkit/graphics.h>
#include <dpsclient/dpsNeXT.h>
#include "hippo.h"
#include "h3D.h"
#include "hplotNxt.h"
#include "hutil.h"
GLOB_QUAL const char hplotNxt_c_rcsid[] =
"$Id: hplotNxt.c,v 5.0 1993/08/17 21:55:37 rensing Exp $";
GLOB_QUAL const char hplotNxt_h_rcsid[] = _HPLOTNXT_H_RCSID_;
/* find offset to matrix element */
#define INDEX(row, column, totcols) ((row) * (totcols) + (column))
#define MIN(x, y) (((x) > (y)) ? (y) : (x))
#define YPADDING(disp) ((disp)->drawRect.size.height*0.01)
/* following copied from <appkit/View.h> */
/* look out of changes in future releases */
extern short NXDrawingStatus;
/* NXDrawingStatus values */
#define NX_DRAWING 1 /* we're drawing */
#define NX_PRINTING 2 /* we're printing */
#define NX_COPYING 3 /* we're copying to the scrap */
/*
* maximum number of point to use in userpaths
*/
#define MAXNPTS_SCREEN 1000
#define MAXNPTS_PRINT 500
/*
* ditto for xyshow
*/
#define MAXXYSHOW_SCREEN 3000
#define MAXXYSHOW_PRINT 1500
/*
* other constants
*/
#define PI 3.1415926536
#define TWOPI (2.0*PI)
#define HALFPI (PI/2.0)
/* various globals */
static rectangle outerRect; /* Outer rectangle in device units */
static rectangle innerRect; /* inner (ie plotting area) rectangle in device units */
static rectangle userRect; /* ditto in user units */
static float bbox[4]; /* bounding box required by DPSDoUserPath */
static float xScale, yScale; /* used for getting into user coords from device coords */
/*
* 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_NeXT(display disp, int inside);
static void drawWireFrame_NeXT(display disp);
static void drawMesh_NeXT(display disp);
int initPlot_NeXT(rectangle *rect1, rectangle *rect2, rectangle *rect3)
{
/* Save rectangle pointers for global use */
memcpy((char *) &outerRect, (const char *)rect1, sizeof(rectangle) );
memcpy((char *) &innerRect, (const char *)rect2, sizeof(rectangle) );
memcpy((char *) &userRect, (const char *)rect3, sizeof(rectangle) );
xScale = innerRect.size.width / userRect.size.width;
yScale = innerRect.size.height / userRect.size.height;
/* specify bounding box (add a small margin for safety) */
bbox[0] = userRect.origin.x -
(innerRect.origin.x - outerRect.origin.x)/xScale;
bbox[1] = userRect.origin.y -
(innerRect.origin.y - outerRect.origin.y)/yScale;
bbox[2] = userRect.origin.x + userRect.size.width +
(outerRect.size.width+outerRect.origin.x -
(innerRect.origin.x+innerRect.size.width))/xScale;
bbox[3] = userRect.origin.y + userRect.size.height +
(outerRect.size.height+outerRect.origin.y -
(innerRect.origin.y+innerRect.size.height))/yScale;
return 0;
}
int drawLine_NeXT(float *coords, int nCoords, linestyle_t ls)
{
char ops[3] = { dps_moveto, 0, dps_lineto };
int repeatCount; /* this number + 32 must be < 255 */
/* to display and < 127 for printing */
/* to fit in 1 char */
float *co;
int count;
float solid[0];
float dash[]={5,3};
float dot[]={2,5};
float dotdash[]={5,3,1,3};
float ctm_matrix[6] = {1.0/xScale, 0.0, 0.0, 1.0/yScale, 0.0, 0.0 };
if ( NXDrawingStatus == NX_DRAWING )
repeatCount = 220;
else
repeatCount = 92; /* work around apparent bug */
PSgsave();
/* get into user coords */
PStranslate (innerRect.origin.x, innerRect.origin.y);
PSscale (xScale, yScale);
PStranslate (-userRect.origin.x, -userRect.origin.y);
/* set line style */
switch(ls) {
case SOLID: PSsetdash(solid,0,0); break;
case DOT: PSsetdash(dot,2,0); break;
case DASH: PSsetdash(dash,2,0); break;
case DOTDASH: PSsetdash(dotdash,4,0); break;
default: PSsetdash(solid,0,0); break;
}
/*
* the following rather messy code is needed because PostScript
* uses just 1 character for a repeat counter (specified as
* 'excess 32'). Using the repeat method means we don't have to
* malloc some variable length array for the ops, and then free
* it after use.
*/
co = coords;
do
{
if (nCoords > repeatCount) count = repeatCount;
else count = nCoords;
/*
* use DPSDoUserPathWithMatrix to take care of funny effect when
* you have unequal scaling.
*/
ops[1] = 32 + count - 1;
DPSDoUserPathWithMatrix(co, 2*count, dps_float, ops, 3,
bbox, dps_ustroke, ctm_matrix);
co += 2*(count - 1);
nCoords -= (count - 1);
}
while (nCoords > 1); /* 1 because we always back up 1 point */
/* to connect the segments */
PSgrestore();
return 0;
}
int drawPoints_NeXT(float *coords, int nCoords, plotsymbol_t symbol,
float symbolSize)
{
int ci, oi, i;
int filled=0;
int count;
int maxnpts;
float *cArray;
char *oArray;
float xPointSide, yPointSide;
float xHalfPointSide, yHalfPointSide;
float ctm_matrix[6] = {1.0/xScale, 0.0, 0.0, 1.0/yScale, 0.0, 0.0 };
if ( NXDrawingStatus == NX_DRAWING )
maxnpts = MAXNPTS_SCREEN;
else
maxnpts = MAXNPTS_PRINT;
if (symbol == SOLIDSQUARE)
filled = 1;
if (filled) maxnpts /= 5;
xPointSide = symbolSize / xScale;
yPointSide = symbolSize / yScale;
xHalfPointSide = xPointSide / 2.0;
yHalfPointSide = yPointSide / 2.0;
PSgsave();
/* get into user coords */
PStranslate (innerRect.origin.x, innerRect.origin.y);
PSscale (xScale, yScale);
PStranslate (-userRect.origin.x, -userRect.origin.y);
if (nCoords > maxnpts) i = maxnpts;
else i = nCoords;
if ((cArray = (float *) malloc( 8*i * sizeof(float) )) == NULL)
{
h_error("drawPoints_NeXT - memory exceeded ");
return -1;
}
if ((oArray = (char *) malloc( 5*i * sizeof(char) )) == NULL)
{
h_error("drawPoints_NeXT - memory exceeded ");
return -1;
}
do
{
if (nCoords > maxnpts) count = maxnpts;
else count = nCoords;
ci = oi = 0;
switch (symbol)
{
case SQUARE:
case SOLIDSQUARE:
for (i = 0; i < count; i++)
{
cArray[ci++] = *coords++ - xHalfPointSide;
cArray[ci++] = *coords++ - yHalfPointSide;
oArray[oi++] = dps_moveto;
cArray[ci++] = +xPointSide;
cArray[ci++] = +0.0;
oArray[oi++] = dps_rlineto;
cArray[ci++] = +0.0;
cArray[ci++] = +yPointSide;
oArray[oi++] = dps_rlineto;
cArray[ci++] = -xPointSide;
cArray[ci++] = +0.0;
oArray[oi++] = dps_rlineto;
oArray[oi++] = dps_closepath;
}
break;
case PLUS:
for (i = 0; i < count; i++)
{
cArray[ci++] = *coords++ - xHalfPointSide;
cArray[ci++] = *coords++;
oArray[oi++] = dps_moveto;
cArray[ci++] = +xPointSide;
cArray[ci++] = +0.0;
oArray[oi++] = dps_rlineto;
cArray[ci++] = -xHalfPointSide;
cArray[ci++] = +yHalfPointSide;
oArray[oi++] = dps_rmoveto;
cArray[ci++] = 0.0;
cArray[ci++] = -yPointSide;
oArray[oi++] = dps_rlineto;
}
break;
case TIMES:
for (i = 0; i < count; i++)
{
cArray[ci++] = *coords++ - xHalfPointSide;
cArray[ci++] = *coords++ - yHalfPointSide;
oArray[oi++] = dps_moveto;
cArray[ci++] = +xPointSide;
cArray[ci++] = +yPointSide;
oArray[oi++] = dps_rlineto;
cArray[ci++] = 0.0;
cArray[ci++] = -yPointSide;
oArray[oi++] = dps_rmoveto;
cArray[ci++] = -xPointSide;
cArray[ci++] = +yPointSide;
oArray[oi++] = dps_rlineto;
}
break;
default:
break;
}
/*
* use DPSDoUserPathWithMatrix to take care of funny effect when
* you have unequal scaling. Applies to line widths and patterns,
* so not useful for filled symbols.
*/
if (filled)
DPSDoUserPath(cArray, ci, dps_float, oArray, oi, bbox,
dps_ufill);
else
DPSDoUserPathWithMatrix(cArray, ci, dps_float, oArray, oi, bbox,
dps_ustroke,ctm_matrix);
nCoords -= count;
}
while (nCoords > 0);
free (cArray);
free (oArray);
PSgrestore();
return 0;
}
int drawPointsScat_NeXT(float *coords, int nCoords, plotsymbol_t symbol,
float symbolSize)
{
int maxXYShow, count, count2;
float *floatBuf, *to;
char *charBuf, plotChar[]="+";
/*
* Set plot character
*/
switch (symbol) {
case SQUARE:
plotChar[0] = 'O';
break;
case SOLIDSQUARE:
plotChar[0] = 'M'; /* tried a period but it ends up off-center */
break;
case PLUS:
plotChar[0] = '+';
break;
case TIMES:
plotChar[0] = 'X';
break;
}
/*
* Pick a suitable blocking size so as not to overflow the printer etc
*/
if ( NXDrawingStatus == NX_DRAWING )
maxXYShow = MAXXYSHOW_SCREEN;
else
maxXYShow = MAXXYSHOW_PRINT;
if (nCoords < maxXYShow) maxXYShow = nCoords;
/*
* Allocate space for scatter points. First pair of floats is the
* starting (X,Y) position, remainder are (dX,dY) increments. It is
* terminated by a (0.0, 0.0)
*/
if ((floatBuf = (float *)malloc((2*maxXYShow + 2) * sizeof(float)))
== NULL) {
h_error("drawPointsScat_NeXT - memory exceeded");
return -1;
}
/*
* Allocate space for plot char buffer, and fill it. This is just a
* long string of all the same character, terminated by a null.
*/
if ((charBuf = (char *)malloc((maxXYShow + 1) * sizeof(char)))
== NULL) {
h_error("drawPointsScat_NeXT - memory exceeded");
return -1;
}
memset(charBuf,plotChar[0],maxXYShow);
charBuf[maxXYShow] = 0;
/*
* Reformat coords into form required by xyshow. We have to use screen
* coordinates because if you do scaling to user coordinates, the letters
* in xyshow get scaled as well. Seems no way around this.
*/
do
{
if (nCoords > maxXYShow) count = maxXYShow;
else count = nCoords;
count2 = count; /* copy */
*(charBuf+count) = 0; /* null terminate the char buffer */
to = floatBuf;
/* save first XY pair */
*to++ = (*coords - userRect.origin.x) * xScale;
*to++ = (*(coords+1) - userRect.origin.y) * yScale;
count--;
coords += 2;
/* now save the increments from previous coord */
while (count--) {
*to++ = (*coords - *(coords-2)) * xScale;
*to++ = (*(coords+1) - *(coords-1)) * yScale;
coords += 2;
}
/* finish up with a pair of zeros*/
*to++ = 0.0;
*to++ = 0.0;
/*
* Draw scatter points, using xyshow
*/
PSgsave();
PStranslate (innerRect.origin.x, innerRect.origin.y);
PSWXYShow(*floatBuf, *(floatBuf+1), plotChar, charBuf, floatBuf+2,
count2*2, symbolSize);
PSgrestore();
/*
* check for more
*/
nCoords -= count2;
}
while (nCoords > 0);
/*
* Free the work buffers
*/
free (floatBuf);
free (charBuf);
return 0;
}
int drawYError_NeXT(float *coords, float *errorYs, int nCoords)
{
#define ERRORCAPSIZE 2.0
int ci, oi, i;
int count;
int maxnpts;
float *cArray;
char *oArray;
float halfErrorCap = ERRORCAPSIZE/xScale * 0.5;
float x, ylo, yhi;
float ctm_matrix[6] = {1.0/xScale, 0.0, 0.0, 1.0/yScale, 0.0, 0.0 };
if ( NXDrawingStatus == NX_DRAWING )
maxnpts = MAXNPTS_SCREEN;
else
maxnpts = MAXNPTS_PRINT;
if (nCoords > maxnpts) i = maxnpts;
else i = nCoords;
if ((cArray = (float *) malloc (12 * i * sizeof(float))) == NULL)
{
h_error("drawYError_NeXT - memory exceeded ");
return -1;
}
if ((oArray = (char *) malloc (6 * i * sizeof(char))) == NULL)
{
h_error("drawYError_NeXT - memory exceeded ");
return -1;
}
PSgsave();
/* get into user coords */
PStranslate (innerRect.origin.x, innerRect.origin.y);
PSscale (xScale, yScale);
PStranslate (-userRect.origin.x, -userRect.origin.y);
do
{
if (nCoords > maxnpts) count = maxnpts;
else count = nCoords;
ci = oi = 0;
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 */
cArray[ci++] = x;
cArray[ci++] = ylo;
oArray[oi++] = dps_moveto; /* move to mid bottom */
cArray[ci++] = x;
cArray[ci++] = yhi;
oArray[oi++] = dps_lineto; /* line to mid top */
cArray[ci++] = x - halfErrorCap;
cArray[ci++] = yhi;
oArray[oi++] = dps_moveto; /* move to top left */
cArray[ci++] = x + halfErrorCap;
cArray[ci++] = yhi;
oArray[oi++] = dps_lineto; /* line to top right */
cArray[ci++] = x - halfErrorCap;
cArray[ci++] = ylo;
oArray[oi++] = dps_moveto; /* move to bottom left */
cArray[ci++] = x + halfErrorCap;
cArray[ci++] = ylo;
oArray[oi++] = dps_lineto; /* line to bottom right */
}
DPSDoUserPathWithMatrix(cArray, ci, dps_float, oArray, oi, bbox,
dps_ustroke, ctm_matrix);
nCoords -= count;
}
while (nCoords > 0);
PSgrestore();
free (cArray);
free (oArray);
return 0;
}
int drawXError_NeXT(float *coords, float *errorXs, int nCoords)
{
int ci, oi, i;
int count;
int maxnpts;
float *cArray;
char *oArray;
float halfErrorCap = ERRORCAPSIZE/yScale * 0.5;
float y, xlo, xhi;
float ctm_matrix[6] = {1.0/xScale, 0.0, 0.0, 1.0/yScale, 0.0, 0.0 };
if ( NXDrawingStatus == NX_DRAWING )
maxnpts = MAXNPTS_SCREEN;
else
maxnpts = MAXNPTS_PRINT;
if (nCoords > maxnpts) i = maxnpts;
else i = nCoords;
if ((cArray = (float *) malloc (12 * i * sizeof(float))) == NULL)
{
h_error("drawXError_NeXT - memory exceeded ");
return -1;
}
if ((oArray = (char *) malloc (6 * i * sizeof(char))) == NULL)
{
h_error("drawXError_NeXT - memory exceeded ");
return -1;
}
PSgsave();
/* get into user coords */
PStranslate (innerRect.origin.x, innerRect.origin.y);
PSscale (xScale, yScale);
PStranslate (-userRect.origin.x, -userRect.origin.y);
do
{
if (nCoords > maxnpts) count = maxnpts;
else count = nCoords;
ci = oi = 0;
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 */
cArray[ci++] = xlo;
cArray[ci++] = y;
oArray[oi++] = dps_moveto; /* move to mid bottom */
cArray[ci++] = xhi;
cArray[ci++] = y;
oArray[oi++] = dps_lineto; /* line to mid top */
cArray[ci++] = xlo;
cArray[ci++] = y - halfErrorCap;
oArray[oi++] = dps_moveto; /* move to top left */
cArray[ci++] = xlo;
cArray[ci++] = y + halfErrorCap;
oArray[oi++] = dps_lineto; /* line to top right */
cArray[ci++] = xhi;
cArray[ci++] = y - halfErrorCap;
oArray[oi++] = dps_moveto; /* move to bottom left */
cArray[ci++] = xhi;
cArray[ci++] = y + halfErrorCap;
oArray[oi++] = dps_lineto; /* line to bottom right */
}
DPSDoUserPathWithMatrix(cArray, ci, dps_float, oArray, oi, bbox,
dps_ustroke, ctm_matrix);
nCoords -= count;
}
while (nCoords > 0);
PSgrestore();
free (cArray);
free (oArray);
return 0;
}
int drawYTicks_NeXT( float *y, int nt, float tickwidth, int side )
{
int ci, oi, i;
float *cArray;
char *oArray;
float start;
float ctm_matrix[6] = {1.0/xScale, 0.0, 0.0, 1.0/yScale, 0.0, 0.0 };
tickwidth /= xScale;
if (side == 0)
start = userRect.origin.x;
else
start = userRect.origin.x + userRect.size.width - tickwidth;
if ((cArray = (float *) malloc (4 * nt * sizeof(float))) == NULL)
{
h_error("drawYTicks_NeXT - memory exceeded ");
return -1;
}
if ((oArray = (char *) malloc (2 * nt * sizeof(char))) == NULL)
{
h_error("drawYTicks_NeXT - memory exceeded ");
return -1;
}
PSgsave();
/* get into user coords */
PStranslate (innerRect.origin.x, innerRect.origin.y);
PSscale (xScale, yScale);
PStranslate (-userRect.origin.x, -userRect.origin.y);
ci = oi = 0;
for (i = 0; i < nt; i++)
{
cArray[ci++] = start;
cArray[ci++] = y[i];
oArray[oi++] = dps_moveto;
cArray[ci++] = tickwidth;
cArray[ci++] = 0.0;
oArray[oi++] = dps_rlineto;
}
DPSDoUserPathWithMatrix(cArray, ci, dps_float, oArray, oi, bbox,
dps_ustroke, ctm_matrix);
PSgrestore();
free(cArray);
free(oArray);
return 0;
}
int drawXTicks_NeXT( float *y, int nt, float tickwidth, int side )
{
int ci, oi, i;
float *cArray;
float start;
char *oArray;
float ctm_matrix[6] = {1.0/xScale, 0.0, 0.0, 1.0/yScale, 0.0, 0.0 };
tickwidth /= yScale;
if (side == 0)
start = userRect.origin.y;
else
start = userRect.origin.y + userRect.size.height - tickwidth;
if ((cArray = (float *) malloc (4 * nt * sizeof(float))) == NULL)
{
h_error("drawYTicks_NeXT - memory exceeded ");
return -1;
}
if ((oArray = (char *) malloc (2 * nt * sizeof(char))) == NULL)
{
h_error("drawYTicks_NeXT - memory exceeded ");
return -1;
}
PSgsave();
/* get into user coords */
PStranslate (innerRect.origin.x, innerRect.origin.y);
PSscale (xScale, yScale);
PStranslate (-userRect.origin.x, -userRect.origin.y);
ci = oi = 0;
for (i = 0; i < nt; i++)
{
cArray[ci++] = y[i];
cArray[ci++] = start;
oArray[oi++] = dps_moveto;
cArray[ci++] = 0.0;
cArray[ci++] = tickwidth;
oArray[oi++] = dps_rlineto;
}
DPSDoUserPathWithMatrix(cArray, ci, dps_float, oArray, oi, bbox,
dps_ustroke, ctm_matrix);
PSgrestore();
free(cArray);
free(oArray);
return 0;
}
int drawMag_NeXT(float x, float y, int mag, float fontSize)
{
char str[10];
PSselectfont("Helvetica",fontSize);
PSmoveto( x, y );
PSshow("x10");
PSrmoveto( 0.0, 0.5*fontSize );
sprintf(str,"%d",mag);
PSshow(str);
return 0;
}
int drawText_NeXT(char *string, float x, float y, float fontSize,
float rotation, char xAlign, char yAlign)
{
float yStep = 0.0;
switch (yAlign)
{
case 'C':
case 'c':
yStep = 0.4;
break;
case 'T':
case 't':
yStep = 0.8;
break;
}
switch (xAlign)
{
case 'C':
case 'c':
drawTextPS( string, x, y, fontSize, rotation, 0.5, yStep,
"Helvetica" );
break;
case 'R':
case 'r':
drawTextPS( string, x, y, fontSize, rotation, 1.0, yStep,
"Helvetica" );
break;
case 'L':
case 'l':
default:
drawTextPS( string, x, y, fontSize, rotation, 0.0, yStep,
"Helvetica" );
break;
}
return 0;
}
int drawColor2D_NeXT(int nXBins, int nYBins, float binMin, float binMax,
float *data, int useColor )
{
int iBin, iYBin;
int totBins = nXBins * nYBins;
float xlo = innerRect.origin.x;
float xhi = xlo + innerRect.size.width;
float ylo = innerRect.origin.y;
float yhi = ylo + innerRect.size.height;
float deltaX = (xhi - xlo) / nXBins;
float deltaY = (yhi - ylo) / nYBins;
NXRect *rects;
int iRect, nRects;
int rectChunk = 30; /* >40 rects at a time seems to overflow PS */
float *grays;
float colorScale, blueHue, magHue, saturation, brightness;
float grayScale, nearWhite = 0.9;
float xCoord, yCoord;
int i;
NXColor myColor;
float myHue;
/*
* alloc space for every rect,
* even though we will only draw the non-zero ones
*/
if ((rects = (NXRect *) malloc (totBins * sizeof (NXRect))) == NULL)
{
h_error("drawColor2D_NeXT - memory exceeded ");
return -1;
}
if ((grays = (float *) malloc (totBins * sizeof (float))) == NULL)
{
h_error("drawColor2D_NeXT - memory exceeded ");
free(rects);
return -1;
}
/*
* this routine leaves color in unpredictable state,
* so we need a gsave/grestore
*/
PSgsave();
if (binMin == binMax)
grayScale = 1.0;
else
grayScale = nearWhite / (binMax - binMin);
xCoord = xlo;
yCoord = ylo;
iYBin = 0;
iRect = 0;
for (iBin = 0; iBin < totBins; iBin++)
{
/* bins are arranged as bins[x][y] with y changing fastest */
if ((data[iBin] != 0)
&& (data[iBin] > binMin)
&& (data[iBin] < binMax)) {
NXSetRect (&rects[iRect], xCoord, yCoord, deltaX, deltaY);
/*
* we set the grey value to the range:
* black (most) to nearWhite (least)
*/
grays[iRect] = (binMax - data[iBin]) * grayScale;
iRect ++;
}
yCoord += deltaY;
iYBin++;
if ( iYBin == nYBins)
{
iYBin = 0;
yCoord = ylo;
xCoord += deltaX;
}
}
if (! useColor)
{
/* do the greyscale version */
for (i = 0; i < iRect; i += rectChunk)
{
nRects = rectChunk;
if ((iRect - i) < rectChunk) nRects = (iRect - i);
NXRectFillListWithGrays (&rects[i], &grays[i], nRects);
}
}
else
{
/* do the color version */
/* set background to black */
NXSetColor (NX_COLORBLACK);
NXRectFill ((NXRect *) &innerRect);
/* establish the color scale */
NXConvertColorToHSB (NX_COLORBLUE, &blueHue,
&saturation, &brightness);
NXConvertColorToHSB (NX_COLORMAGENTA, &magHue,
&saturation, &brightness);
/*
* start at magenta (hot), increase to 1.0,
* then wraparound to 0.0 and up to blue (cold)
*/
colorScale = (1.0 - magHue + blueHue) / nearWhite;
for (i=0; i < iRect; i++)
{
myHue = magHue + (grays[i] * colorScale);
if (myHue > 1.0) myHue = myHue - 1.0;
myColor = NXConvertHSBToColor (myHue, 1.0, 1.0);
NXSetColor (myColor);
NXRectFill (&rects[i]);
}
}
free (rects);
free (grays);
/*
* color/gray is left unpredictable, so we need a gsave/grestore
*/
PSgrestore();
return 0;
}
int drawScatter3D_NeXT(display disp, float *coords, int nCoords)
{
threeD_t *threeD;
static int inside = 1, outside = 0;
char charBuf0[2], plotChar='+';
float x, y;
float fontSize;
char string[80];
if (disp->threeDWorkArea == NULL) h3D_init3D(disp);
threeD = disp->threeDWorkArea; /* set local pointer */
PSsetlinewidth(0.0);
/* 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
*/
PSgsave();
PStranslate (disp->drawRect.origin.x, disp->drawRect.origin.y);
PSscale (disp->drawRect.size.width/2.0, disp->drawRect.size.height/2.0);
PStranslate (1.0, 1.0);
/*
* Now do transformations, then the xyshow
*/
if (disp->doCube && disp->flags.drawAxes) {
h3D_transformCube(disp);
drawSides_NeXT(disp, inside);
}
if (disp->doScatter) {
if (threeD->reCalculateScatterPoints) {
h3D_checkAllocScatterResults(disp, nCoords);
h3D_renderXYShow(disp, coords);
threeD->reCalculateScatterPoints = 0;
}
/* did the plot character change? */
switch (disp->plotSymbol) {
case SQUARE:
plotChar = 'O';
break;
case SOLIDSQUARE:
plotChar = 'M';
break;
case PLUS:
plotChar = '+';
break;
case TIMES:
plotChar = 'X';
break;
}
if (plotChar != threeD->plotCharBuffer[0]) {
memset(threeD->plotCharBuffer,plotChar,threeD->nScatterPoints);
threeD->plotCharBuffer[threeD->nScatterPoints] = 0;
}
charBuf0[0] = threeD->plotCharBuffer[0];
charBuf0[1] = 0;
PSWXYShow(threeD->scatterResults[0], threeD->scatterResults[1],
charBuf0, threeD->plotCharBuffer, &threeD->scatterResults[2],
threeD->nScatterPoints*2,
disp->symbolSize*(2.0/disp->drawRect.size.width));
}
if (disp->doCube && disp->flags.drawAxes) {
drawSides_NeXT(disp, outside);
}
PSgrestore();
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_NeXT(display disp, int inside)
{
threeD_t *threeD;
int side, p, q, r, s;
int insideVisible, showFace;
static float pattern[2] = {0.005, 0.01};
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) {
PSsetgray(0.0);
PSmoveto(threeD->cubeU[p], threeD->cubeV[p]);
PSlineto(threeD->cubeU[q], threeD->cubeV[q]);
PSlineto(threeD->cubeU[r], threeD->cubeV[r]);
PSlineto(threeD->cubeU[s], threeD->cubeV[s]);
PSclosepath();
PSstroke();
/* now do the inside and outside tick marks */
if (!disp->doSpeedy) {
if (inside) {
if (threeD->nZTicks > 0) {
if (side == firstChoice)
doFirstChoice = 1;
PSgsave();
PSsetdash(pattern, 2, 0);
/* 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++) {
PSmoveto(tickU[i], tickV[i]);
PSlineto(tickU2[i], tickV2[i]);
}
PSstroke();
PSgrestore(); /* 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++) {
PSmoveto(tickU[i], tickV[i]);
PSrlineto(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));
}
drawTextPS(threeD->xLabels[i], tickU[i],
(tickV[i]-tickLength-0.04), tickFontSize,
0.0, strShift, 0.0, font);
}
PSstroke();
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++) {
PSmoveto(tickU[i], tickV[i]);
PSrlineto(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));
}
drawTextPS(threeD->yLabels[i], tickU[i],
(tickV[i]-tickLength-0.04), tickFontSize,
0.0, strShift, 0.0, font);
}
PSstroke();
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++) {
PSmoveto(tickU[i], tickV[i]);
PSrlineto(-tickLength, 0.0);
drawTextPS(threeD->zLabels[i], (tickU[i]-tickLength-0.01),
tickV[i], tickFontSize, 0.0, 1.0, 0.0, font);
}
PSstroke();
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;
}
int shade_NeXT(float xlow, float xhigh, float ylow, float yhigh )
{
NXRect myRect;
PSgsave();
PSsetgray(0.6);
NXSetRect(&myRect, xlow, ylow, (xhigh-xlow),(yhigh-ylow));
NXRectFill(&myRect);
PSgrestore();
return 0;
}
/*
* Draw a 'wire-frame' lego plot in the given drawing space
*/
static void drawWireFrame_NeXT(display disp)
{
threeD_t *threeD;
float *p, *q, *u, *v;
int i, ci, oi, nLines;
threeD = disp->threeDWorkArea; /* set local pointer */
ci = oi = nLines = 0;
u = threeD->legoResults[0];
v = threeD->legoResults[1];
for (i = 0; i < threeD->nLegoPoints; i += 8) {
p = &u[i];
q = &v[i];
threeD->cArray[ci++] = p[0];
threeD->cArray[ci++] = q[0];
threeD->oArray[oi++] = dps_moveto;
threeD->cArray[ci++] = p[1];
threeD->cArray[ci++] = q[1];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[2];
threeD->cArray[ci++] = q[2];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[3];
threeD->cArray[ci++] = q[3];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[0];
threeD->cArray[ci++] = q[0];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[4];
threeD->cArray[ci++] = q[4];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[5];
threeD->cArray[ci++] = q[5];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[6];
threeD->cArray[ci++] = q[6];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[7];
threeD->cArray[ci++] = q[7];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[4];
threeD->cArray[ci++] = q[4];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[1];
threeD->cArray[ci++] = q[1];
threeD->oArray[oi++] = dps_moveto;
threeD->cArray[ci++] = p[5];
threeD->cArray[ci++] = q[5];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[2];
threeD->cArray[ci++] = q[2];
threeD->oArray[oi++] = dps_moveto;
threeD->cArray[ci++] = p[6];
threeD->cArray[ci++] = q[6];
threeD->oArray[oi++] = dps_lineto;
threeD->cArray[ci++] = p[3];
threeD->cArray[ci++] = q[3];
threeD->oArray[oi++] = dps_moveto;
threeD->cArray[ci++] = p[7];
threeD->cArray[ci++] = q[7];
threeD->oArray[oi++] = dps_lineto;
nLines += 16;
if (nLines > (MAXPSLINES-16)) { /* printer limit 1500 lines??? */
DPSDoUserPath(threeD->cArray, ci, dps_float,
threeD->oArray, oi, threeD->boundingBox,
dps_ustroke);
ci = oi = nLines = 0;
}
}
if (nLines > 0) /* flush last buffer */
DPSDoUserPath(threeD->cArray, ci, dps_float,
threeD->oArray, oi, threeD->boundingBox,
dps_ustroke);
return;
}
/*
* Draw a mesh surface through the to centers of each 'lego'
*/
static void drawMesh_NeXT(display disp)
{
threeD_t *threeD;
float *p, *q, *u, *v;
int i, j, k, ci, oi, nLines;
threeD = disp->threeDWorkArea; /* set local pointer */
ci = oi = nLines = 0;
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];
threeD->cArray[ci++] = (p[4] + p[6]) / 2.0;
threeD->cArray[ci++] = (q[4] + q[6]) / 2.0;
threeD->oArray[oi++] = dps_moveto;
for (j = 1; j < disp->bins.yAxis.nBins; j++) {
p = &u[k + j * 8];
q = &v[k + j * 8];
threeD->cArray[ci++] = (p[4] + p[6]) / 2.0;
threeD->cArray[ci++] = (q[4] + q[6]) / 2.0;
threeD->oArray[oi++] = dps_lineto;
}
nLines += (disp->bins.yAxis.nBins - 1);
if (nLines > (MAXPSLINES-disp->bins.yAxis.nBins)) {
DPSDoUserPath(threeD->cArray, ci, dps_float,
threeD->oArray, oi, threeD->boundingBox,
dps_ustroke);
ci = oi = nLines = 0;
}
}
for (j = 0; j < disp->bins.yAxis.nBins; j++) {
k = j * 8;
p = &u[k];
q = &v[k];
threeD->cArray[ci++] = (p[4] + p[6]) / 2.0;
threeD->cArray[ci++] = (q[4] + q[6]) / 2.0;
threeD->oArray[oi++] = dps_moveto;
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];
threeD->cArray[ci++] = (p[4] + p[6]) / 2.0;
threeD->cArray[ci++] = (q[4] + q[6]) / 2.0;
threeD->oArray[oi++] = dps_lineto;
}
nLines += (disp->bins.yAxis.nBins - 1);
if (nLines > (MAXPSLINES-disp->bins.yAxis.nBins)) {
DPSDoUserPath(threeD->cArray, ci, dps_float,
threeD->oArray, oi, threeD->boundingBox,
dps_ustroke);
ci = oi = nLines = 0;
}
}
if (nLines > 0) /* flush last buffer */
DPSDoUserPath(threeD->cArray, ci, dps_float,
threeD->oArray, oi, threeD->boundingBox,
dps_ustroke);
return;
}
int drawLego2D_NeXT(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 */
PSsetlinewidth(0.0);
/* 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
*/
PSgsave();
PStranslate (disp->drawRect.origin.x, disp->drawRect.origin.y);
PSscale (disp->drawRect.size.width/2.0, disp->drawRect.size.height/2.0);
PStranslate (1.0, 1.0);
/*
* Now do transformations and drawing
*/
if (disp->doCube && disp->flags.drawAxes) {
h3D_transformCube(disp);
drawSides_NeXT(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];
}
PSmoveto(x[cornerIndex[0]],
y[cornerIndex[0]]);
PSlineto(x[cornerIndex[1]],
y[cornerIndex[1]]);
PSlineto(x[cornerIndex[2]],
y[cornerIndex[2]]);
PSlineto(x[cornerIndex[3]],
y[cornerIndex[3]]);
PSclosepath();
PSsetgray(disp->color[cornerIndex[0]]);
if (disp->doWireFrame) {
PSgsave();
PSfill();
PSgrestore();
PSsetgray(0.0);
PSstroke();
} else {
PSfill();
}
PSmoveto(x[cornerIndex[4]],
y[cornerIndex[4]]);
PSlineto(x[cornerIndex[5]],
y[cornerIndex[5]]);
PSlineto(x[cornerIndex[6]],
y[cornerIndex[6]]);
PSlineto(x[cornerIndex[7]],
y[cornerIndex[7]]);
PSclosepath();
PSsetgray(disp->color[cornerIndex[4]]);
if (disp->doWireFrame) {
PSgsave();
PSfill();
PSgrestore();
PSsetgray(0.0);
PSstroke();
} else {
PSfill();
}
}
/* determine if top is visible */
nearTopCorner = thisCorner + 4;
farTopCorner = nearTopCorner + 2;
if (farTopCorner > 7)
farTopCorner -= 4;
if (y[farTopCorner] > y[nearTopCorner]) {
PSmoveto(x[4], y[4]);
PSlineto(x[5], y[5]);
PSlineto(x[6], y[6]);
PSlineto(x[7], y[7]);
PSclosepath();
PSsetgray(disp->color[4]);
if (disp->doWireFrame) {
PSgsave();
PSfill();
PSgrestore();
PSsetgray(0.0);
PSstroke();
} else {
PSfill();
}
}
}
}
/* end of doFill */
else if (disp->doWireFrame || (disp->doFill && !disp->doSpeedy)) {
h3D_transformWireFrame(disp);
drawWireFrame_NeXT(disp);
}
if (disp->doMesh) {
h3D_transformMesh(disp);
drawMesh_NeXT(disp);
}
if (disp->doCube && disp->flags.drawAxes) {
drawSides_NeXT(disp, outside);
}
PSgrestore();
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;
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.