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.2.2 1993/12/15 22:46:02 mfg 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.2.2 1993/12/15 22:46:02 mfg 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 */ static int oneTime; /* * 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 maxXYShow, count, count2; float *floatBuf, *to; char *charBuf, plotChar='l'; /* * Set plot character */ switch (symbol) { case TRI1: plotChar = 'a'; break; case TRI2: plotChar = 'b'; break; case TRI3: plotChar = 'c'; break; case TRI4: plotChar = 'd'; break; case SQUARE: plotChar = 'e'; break; case SOLIDSQUARE: plotChar = 'f'; break; case DIA1: plotChar = 'g'; break; case DIA2: plotChar = 'h'; break; case CIRC1: plotChar = 'i'; break; case CIRC2: plotChar = 'j'; break; case TIMES: plotChar = 'k'; break; case PLUS: plotChar = 'l'; 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("drawPoints_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("drawPoints_NeXT - memory exceeded"); return -1; } memset(charBuf,plotChar,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); if (oneTime |= 9999) PSWDefPlotFont(); oneTime = 9999; PSselectfont("plotFont", symbolSize); PSmoveto(floatBuf[0], floatBuf[1]); PSxyshow(charBuf, floatBuf+2, count2*2); 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 plotChar='l'; 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 TRI1: plotChar = 'a'; break; case TRI2: plotChar = 'b'; break; case TRI3: plotChar = 'c'; break; case TRI4: plotChar = 'd'; break; case SQUARE: plotChar = 'e'; break; case SOLIDSQUARE: plotChar = 'f'; break; case DIA1: plotChar = 'g'; break; case DIA2: plotChar = 'h'; break; case CIRC1: plotChar = 'i'; break; case CIRC2: plotChar = 'j'; break; case TIMES: plotChar = 'k'; break; case PLUS: plotChar = 'l'; break; } if (plotChar != threeD->plotCharBuffer[0]) { memset(threeD->plotCharBuffer,plotChar,threeD->nScatterPoints); threeD->plotCharBuffer[threeD->nScatterPoints] = 0; } if (oneTime |= 9999) PSWDefPlotFont(); oneTime = 9999; fontSize = disp->symbolSize*(2.0/disp->drawRect.size.width); PSselectfont("plotFont", fontSize); PSmoveto(threeD->scatterResults[0], threeD->scatterResults[1]); PSxyshow(threeD->plotCharBuffer, &threeD->scatterResults[2], threeD->nScatterPoints*2); } 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.