ftp.nice.ch/pub/next/science/mathematics/hippoplotamus.2.0.s.tar.gz#/hippo2.0/h3D.c

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

#include <stdlib.h>
#include <math.h>
#include <float.h>
#include <string.h>

#include "h3D.h"
#include "hutil.h"

#define MARGINSIZE 0.035

#define PI 3.1415926536
#define TWOPI (2.0*PI)
#define HALFPI (PI/2.0)
#define QUARTERPI (HALFPI/2.0)
#define THREEHALFPI (PI + HALFPI)
#define THREEQUARTERPI (HALFPI+QUARTERPI)
#define RAD_TO_DEG 180.0/PI
#define DEG_TO_RAD PI/180.0

/*
 * Internal C Functions 
 */
static void h3D_genLegoPoints(display disp);
static void h3D_resetUserSpace(display disp);
static int h3D_setupTicks(display disp, binding_t axis);

/*
 * Allocate and initialize a threeD struct 
 */
int
h3D_init3D(display disp)
{
    threeD_t	       *threeD;  	  
    int                 i;
 /* allocate a threeD workarea */
    if ((disp->threeDWorkArea = (void *)calloc(sizeof(threeD_t),1)) == NULL) {
	printf("threeD - memory exceeded ");
	return -1;
    }
    threeD = disp->threeDWorkArea;	/* set local pointer */

    threeD->cubeResults[0] = threeD->cubeU;
    threeD->cubeResults[1] = threeD->cubeV;

    threeD->xTickResults[0] = threeD->xTickU;
    threeD->xTickResults[1] = threeD->xTickV;
    threeD->yTickResults[0] = threeD->yTickU;
    threeD->yTickResults[1] = threeD->yTickV;
    threeD->zTickResults[0] = threeD->zTickU;
    threeD->zTickResults[1] = threeD->zTickV;

 /* bounding box used by DPSDoUserPath */
    threeD->boundingBox[0] = -1.0;
    threeD->boundingBox[1] = -1.0;
    threeD->boundingBox[2] = 2.0;
    threeD->boundingBox[3] = 2.0;

 /* set arbitrary initial 'user space' for stand-alone cube */
    for (i = 0; i < 3; i++) {
	threeD->minval[i] = -1.0;
 	threeD->maxval[i] = 1.0;
    }
    h3D_resetUserSpace(disp);
    
    return 0;
}

/*
 * We have to reset the 'near face', every time theta changes
 */
void h3D_setNearFace(display disp)
{
    threeD_t	       *threeD;    	  

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

    if (disp->theta < -THREEQUARTERPI) {
	threeD->preferredFace = 2;
    } else if (disp->theta < -HALFPI) {
	threeD->preferredFace = 1;
    } else if (disp->theta < -QUARTERPI) {
	threeD->preferredFace = 1;
    } else if (disp->theta < 0.0) {
	threeD->preferredFace = 0;
    } else if (disp->theta < QUARTERPI) {
	threeD->preferredFace = 0;
    } else if (disp->theta < HALFPI) {
	threeD->preferredFace = 3;
    } else if (disp->theta < THREEQUARTERPI) {
	threeD->preferredFace = 3;
    } else {
	threeD->preferredFace = 2;
    }
    return;
}

/*
 * Re-calculation is needed before display whenever angles, dist etc change
 */
void h3D_setDirty(display disp)
{
    threeD_t	       *threeD;    	  

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

    threeD->reCalculateCube = 1;
    threeD->reCalculateLegoPoints2D = 1;
    threeD->reCalculateLegoPoints3D = 1;
    threeD->reCalculateScatterPoints = 1;
    threeD->reCalculateFill = 1;
    return;
}

/*
 * Go back to our initial rotation values
 */
void h3D_resetAngles(display disp)
{
    threeD_t	       *threeD;    	  

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

    disp->theta = 0.0;
    disp->phi = 0.0;
    disp->dist = 2.0;

    h3D_newTheta(disp);
    h3D_newPhi(disp);
    h3D_newDist(disp);
    return;
}

/*
 * Allocate space for lego plots If size hasn't changed, we just return. If
 * space is allocated, we also generate the lego corner points from bins 
 */
int
h3D_checkAllocLego(display disp)
{
    threeD_t	       *threeD;    	  
    float              *mem;
    char               *charmem;
    struct block       *blockmem, **ptrmem;
    int                 sizeRequired, totBins, nPoints;
    int                	alloc = 0, reAlloc = 0;

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

    totBins = disp->bins.xAxis.nBins * disp->bins.yAxis.nBins;
    nPoints = totBins * 8;

    if (threeD->legoPoints[0] == NULL) {
	alloc = 1;
    } else {
	reAlloc = (threeD->nLegoPoints == nPoints) ? 0 : 1;
    }
    if (!alloc && !reAlloc) return 0;
    
    sizeRequired = 3 * nPoints * sizeof(float);

 /* alloc space for legoPoints */
    if (alloc) {
	if ((mem = (float *)malloc(sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->nLegoPoints = nPoints;
	threeD->legoPoints[0] = &mem[0 * nPoints];
	threeD->legoPoints[1] = &mem[1 * nPoints];
	threeD->legoPoints[2] = &mem[2 * nPoints];
    } else if (reAlloc) {
	mem = threeD->legoPoints[0];
	if ((mem = (float *)realloc(mem, sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->nLegoPoints = nPoints;
	threeD->legoPoints[0] = &mem[0 * nPoints];
	threeD->legoPoints[1] = &mem[1 * nPoints];
	threeD->legoPoints[2] = &mem[2 * nPoints];
    }

 /* ditto for legoResults */
    if (alloc) {
	if ((mem = (float *)malloc(sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	} 
	threeD->legoResults[0] = &mem[0 * nPoints];
	threeD->legoResults[1] = &mem[1 * nPoints];
	threeD->legoResults[2] = &mem[2 * nPoints];
    } else if (reAlloc) {
	mem = threeD->legoResults[0];
	if ((mem = (float *)realloc(mem, sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->legoResults[0] = &mem[0 * nPoints];
	threeD->legoResults[1] = &mem[1 * nPoints];
	threeD->legoResults[2] = &mem[2 * nPoints];
    }

 /* ditto for blockBank */
    sizeRequired = totBins * sizeof(struct block);
    if (alloc) {
	if ((blockmem = (struct block *)malloc(sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	} 
	threeD->blockBank = blockmem;
	threeD->numBlocks = totBins;
    } else if (reAlloc) {
	blockmem = threeD->blockBank;
	if ((blockmem = (struct block *)realloc(blockmem, sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->blockBank = blockmem;
	threeD->numBlocks = totBins;
    }
    
 /* and for block pointer array */
    sizeRequired = totBins * sizeof(int);
    if (alloc) {
	if ((ptrmem = (struct block **)malloc(sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	} 
	threeD->blockPointer = ptrmem;
    } else if (reAlloc) {
	ptrmem = threeD->blockPointer;
	if ((ptrmem = (struct block **)realloc(ptrmem, sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->blockPointer = ptrmem;
    }
    
 /* ditto for DPSDoUserPath cArray */
    sizeRequired = 2 * MAXPSLINES * sizeof(float);

    if (alloc) {
	if ((mem = (float *)malloc(sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->cArray = mem;
    }

 /* and for DPSDoUserPath oArray */
    sizeRequired = MAXPSLINES * sizeof(char);

    if (alloc) {
	if ((charmem = (char *)malloc(sizeRequired)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->oArray = charmem;
    }

    if (alloc || reAlloc) {
	h3D_genLegoPoints(disp);
    	h3D_setDirty(disp);
    }
    return 0;
}


/*
 * Allocate space for scatter results This is a series of (X,Y) pairs,
 * terminated by a (0.0, 0.0) If size hasn't changed, we just return 
 */
int
h3D_checkAllocScatterResults(display disp, int nCoords)
{
    threeD_t	       *threeD;    	  
    float              *mem;
    char	       *charmem, plotChar='+';
    int                 sizeRequired1, sizeRequired2;
    int			allocDone;
    
    threeD = disp->threeDWorkArea;	/* set local pointer */

    allocDone = 0;
    sizeRequired1 = (2 * nCoords + 2) * sizeof(float);
    sizeRequired2 = (nCoords + 1) * sizeof(char);

 /* alloc space for scatterResults and plotCharBuffer */
    if (threeD->scatterResults == NULL) {
	if ((mem = (float *)malloc(sizeRequired1)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	if ((charmem = (char *)malloc(sizeRequired2)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->scatterResults = mem;
	threeD->nScatterPoints = nCoords;
	threeD->plotCharBuffer = charmem;
	allocDone = 1;

    } else if (threeD->nScatterPoints != nCoords) {
	mem = threeD->scatterResults;
	if ((mem = (float *)realloc(mem, sizeRequired1)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	charmem = threeD->plotCharBuffer;
	if ((charmem = (char *)realloc(charmem, sizeRequired2)) == NULL) {
	    printf("threeD - memory exceeded ");
	    return -1;
	}
	threeD->scatterResults = mem;
	threeD->nScatterPoints = nCoords;
	threeD->plotCharBuffer = charmem;
	allocDone = 1;
    }

    if (allocDone) {		
    	switch (disp->plotSymbol) {
    	case SQUARE:
	    plotChar = 'O';
	    break;
    	case SOLIDSQUARE:
	    plotChar = 'M';	
	    break;
    	case PLUS:
	    plotChar = '+';
	    break;
    	case TIMES:
	    plotChar = 'X';
	    break;
    	}
    	memset(threeD->plotCharBuffer,plotChar,threeD->nScatterPoints);
    	threeD->plotCharBuffer[threeD->nScatterPoints] = 0;

    	h3D_setDirty(disp);	/* re-calculation will be neccessary */
    }
    
    return 0;
}


/*
 * Convert tuple data to 3-d points needed for lego plots.  Each 'lego' is
 * described by 8 points in space. 
 */
static void
h3D_genLegoPoints(display disp)
{
    threeD_t	       *threeD;    	  
    int                 iBin, iYBin;
    int                 totBins;
    float               xCoord, yCoord, xInit, yInit;
    float               deltaX, deltaY;
    int                 i;
    float              *ptsx, *ptsy, *ptsz;

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

    totBins = disp->bins.xAxis.nBins * disp->bins.yAxis.nBins;
    xInit = disp->xAxis.low;
    yInit = disp->yAxis.low;
    deltaX = (disp->xAxis.high - disp->xAxis.low) / disp->bins.xAxis.nBins;
    deltaY = (disp->yAxis.high - disp->yAxis.low) / disp->bins.yAxis.nBins;

 /* fill in the points */
    xCoord = xInit;
    yCoord = yInit;
    iYBin = 0;
    ptsx = threeD->legoPoints[0];
    ptsy = threeD->legoPoints[1];
    ptsz = threeD->legoPoints[2];

    for (iBin = 0; iBin < totBins; iBin++) {
    /* bins are arranged as bins[x][y] with y changing fastest */
	for (i = 0; i < 2; i++) {
	    *ptsx++ = xCoord;
	    *ptsx++ = xCoord + deltaX;
	    *ptsx++ = xCoord + deltaX;
	    *ptsx++ = xCoord;
	    *ptsy++ = yCoord;
	    *ptsy++ = yCoord;
	    *ptsy++ = yCoord + deltaY;
	    *ptsy++ = yCoord + deltaY;
	}
	for (i = 0; i < 4; i++) {
	    *ptsz++ = disp->bins.binMin;
	}
	for (i = 0; i < 4; i++) {
	    *ptsz++ = disp->bins.data[iBin];
	}
	yCoord += deltaY;
	iYBin++;
	if (iYBin == disp->bins.yAxis.nBins) {
	    iYBin = 0;
	    yCoord = yInit;
	    xCoord += deltaX;
	}
    }
    return;
}



/*
 * See if bin max and mins have changed. If so, reset the user space.
 */
void
h3D_checkBinScale(display disp)
{
    threeD_t	       *threeD;    	  

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

    if ((threeD->minval[0] != disp->xAxis.low)
    || (threeD->minval[1] != disp->yAxis.low)
    || (threeD->minval[2] != disp->bins.binMin)
    || (threeD->maxval[0] != disp->xAxis.high)
    || (threeD->maxval[1] != disp->yAxis.high)
    || (threeD->maxval[2] != disp->bins.binMax))
    {
    	threeD->minval[0] = disp->xAxis.low;
    	threeD->minval[1] = disp->yAxis.low;
    	threeD->minval[2] = disp->bins.binMin;
    	threeD->maxval[0] = disp->xAxis.high;
    	threeD->maxval[1] = disp->yAxis.high;
    	threeD->maxval[2] = disp->bins.binMax;

	disp->zAxis.low = disp->bins.binMin;
	disp->zAxis.high = disp->bins.binMax;

	h3D_checkAllocLego(disp);
	h3D_genLegoPoints(disp);

	h3D_resetUserSpace(disp);
    }
    return;
}

/*
 * See if point max and mins etc have changed. If so, reset the user space.
 */
void
h3D_checkPointScale(display disp, int nCoords)
{
    threeD_t	       *threeD;    	  

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

    if ((threeD->nScatterPoints != nCoords)
    || (threeD->tupleX != disp->binding.x)
    || (threeD->tupleY != disp->binding.y)
    || (threeD->tupleZ != disp->binding.z)
    || (threeD->minval[0] != disp->xAxis.low)
    || (threeD->minval[1] != disp->yAxis.low)
    || (threeD->minval[2] != disp->zAxis.low)
    || (threeD->maxval[0] != disp->xAxis.high)
    || (threeD->maxval[1] != disp->yAxis.high)
    || (threeD->maxval[2] != disp->zAxis.high))
    {
    	threeD->tupleX = disp->binding.x;
    	threeD->tupleY = disp->binding.y;
    	threeD->tupleZ = disp->binding.z;
    	threeD->minval[0] = disp->xAxis.low;
    	threeD->minval[1] = disp->yAxis.low;
    	threeD->minval[2] = disp->zAxis.low;
    	threeD->maxval[0] = disp->xAxis.high;
    	threeD->maxval[1] = disp->yAxis.high;
    	threeD->maxval[2] = disp->zAxis.high;

	h3D_resetUserSpace(disp);
    }

    return;
}
    


/*
 * Given max and min data values, add a margin around them.
 * Re-create the cube at outer limits.
 * Finally re-scale the transformation matrix.
 */
static void
h3D_resetUserSpace(display disp)
{
    threeD_t	       *threeD;    	  
    int                 i;
    static int          x_seq[] = {0, 3, 3, 0, 0, 3, 3, 0};
    static int          y_seq[] = {1, 1, 4, 4, 1, 1, 4, 4};
    static int          z_seq[] = {2, 2, 2, 2, 5, 5, 5, 5};

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

/* add a margin around the data space and call it 'limits' */
    for (i = 0; i < 3; i++) {
	if (threeD->minval[i] >= threeD->maxval[i])
	    threeD->minval[i] = threeD->maxval[i] - 1;
	threeD->limits[i] = threeD->minval[i] -
	  MARGINSIZE * (threeD->maxval[i] - threeD->minval[i]);
	threeD->limits[i + 3] = threeD->maxval[i] +
	  MARGINSIZE * (threeD->maxval[i] - threeD->minval[i]);
    }

 /* create cube */
    for (i = 0; i < 8; i++) {
	threeD->cube[0][i] = threeD->limits[x_seq[i]];
	threeD->cube[1][i] = threeD->limits[y_seq[i]];
	threeD->cube[2][i] = threeD->limits[z_seq[i]];
    }

 /* re-generate tick marks */
    h3D_setupTicks(disp, XAXIS);
    h3D_setupTicks(disp, YAXIS);
    h3D_setupTicks(disp, ZAXIS);
 
    h3D_reScaleMatrix(disp);

 /* impose previous rotations and distance */
    h3D_newTheta(disp);
    h3D_newPhi(disp);
    h3D_newDist(disp);

 /* Show that display re-calculation will be needed */
    h3D_setDirty(disp);

    return;
}


#define N__TICKS 20
static int h3D_setupTicks(display disp, binding_t axis)
{
    threeD_t	       *threeD;    	  
    int nticks = 0, maxticks = N__TICKS;
    int i;
     
    float ticks[N__TICKS];
    char labels[N__TICKS][10];
    float pmag;
     
    switch (axis)
    {
    case XAXIS:
	 genTicks(&disp->xAxis, maxticks, &nticks, ticks, labels, &pmag); 
	 break;
    case YAXIS:
	 genTicks(&disp->yAxis, maxticks, &nticks, ticks, labels, &pmag); 
	 break;
    case ZAXIS:
	 genTicks(&disp->zAxis, maxticks, &nticks, ticks, labels, &pmag); 
	 break;
    default:
	 return -1;
    }
        
    threeD = disp->threeDWorkArea;	/* set local workarea pointer */
	
    switch (axis)
    {
    	case XAXIS:
    	    threeD->nXTicks = nticks;
    	    for (i = 0; i < nticks; i++) {
		threeD->xTicks[0][i] = ticks[i];
		threeD->xTicks[1][i] = threeD->limits[1];
		threeD->xTicks[2][i] = threeD->limits[2];
		threeD->xTicks[0][i + nticks] = ticks[i];
		threeD->xTicks[1][i + nticks] = threeD->limits[4];
		threeD->xTicks[2][i + nticks] = threeD->limits[2];
    	    	
		strcpy(threeD->xLabels[i], labels[i]);
	    }
	    break;

	case YAXIS:
    	    threeD->nYTicks = nticks;
    	    for (i = 0; i < nticks; i++) {
		threeD->yTicks[0][i] = threeD->limits[3];
		threeD->yTicks[1][i] = ticks[i];
		threeD->yTicks[2][i] = threeD->limits[2];
		threeD->yTicks[0][i + threeD->nYTicks] = 	threeD->limits[0];
		threeD->yTicks[1][i + threeD->nYTicks] = ticks[i];
		threeD->yTicks[2][i + threeD->nYTicks] = threeD->limits[2];
    	        
		strcpy(threeD->yLabels[i], labels[i]);
	    }
	    break;

	case ZAXIS:
    	    threeD->nZTicks = nticks;
    	    for (i = 0; i < nticks; i++) {
		threeD->zTicks[0][i] = threeD->limits[0];
		threeD->zTicks[1][i] = threeD->limits[1];
		threeD->zTicks[2][i] = ticks[i];
		threeD->zTicks[0][i + threeD->nZTicks] = threeD->limits[3];
		threeD->zTicks[1][i + threeD->nZTicks] = threeD->limits[1];
		threeD->zTicks[2][i + threeD->nZTicks] = ticks[i];
		threeD->zTicks[0][i + 2 * threeD->nZTicks] =
threeD->limits[3];
		threeD->zTicks[1][i + 2 * threeD->nZTicks] =
threeD->limits[4];
		threeD->zTicks[2][i + 2 * threeD->nZTicks] = ticks[i];
		threeD->zTicks[0][i + 3 * threeD->nZTicks] =
threeD->limits[0];
		threeD->zTicks[1][i + 3 * threeD->nZTicks] =
threeD->limits[4];
		threeD->zTicks[2][i + 3 * threeD->nZTicks] = ticks[i];
    	        
		strcpy(threeD->zLabels[i], labels[i]);
	    }
	    break;

	default:
	    return -1;
    }
    return 0;
}	    
     
void h3D_transformCube(display disp) 
{
    threeD_t	       *threeD;    	  

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

    if (threeD->reCalculateCube) {
	h3D_render2D(disp, 8, threeD->cube[0],
	    threeD->cube[1], threeD->cube[2],
	    threeD->cubeResults);
	if (!disp->doSpeedy) {
	    h3D_render2D(disp, 2 * threeD->nXTicks,
		threeD->xTicks[0], threeD->xTicks[1],
		threeD->xTicks[2], threeD->xTickResults);
	    h3D_render2D(disp, 2 * threeD->nYTicks,
		threeD->yTicks[0], threeD->yTicks[1],
		threeD->yTicks[2], threeD->yTickResults);
	    h3D_render2D(disp, 4 * threeD->nZTicks,
		threeD->zTicks[0], threeD->zTicks[1],
		threeD->zTicks[2], threeD->zTickResults);
	}
	threeD->reCalculateCube = 0;
    }
    return;
}

int h3D_myCompare(const struct block ** ptr1, const struct block ** ptr2)
{
    /* if minZs are unequal, arrange in ascending order */
    if ((*ptr1)->minZ > (*ptr2)->minZ)
	return 1;

    /* if minZs are equal compare maxZs */
    else if ((*ptr1)->minZ == (*ptr2)->minZ) {
	if ((*ptr1)->maxZ > (*ptr2)->maxZ)
	    return 1;
    }
    return 0;
}


void h3D_transformLego(display disp)
{
    threeD_t	       *threeD;    	  
    int                 i, j;
    float              *u, *v, *w;
    float              *p, *q, *r;
    float               zDist, zEye2, zMax=0.0, zMin=0.0;
    int                 zMinCorner = 0;
    struct block       *thisBlock;
    int                 blockBankIndex;

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

    if (threeD->reCalculateLegoPoints3D) {
	h3D_checkAllocLego(disp);
	h3D_render3D(disp, threeD->nLegoPoints, threeD->legoPoints[0], 	
	    threeD->legoPoints[1], threeD->legoPoints[2],
	    threeD->legoResults);
	threeD->reCalculateLegoPoints3D = 0;
	threeD->reCalculateLegoPoints2D = 0;
    }
    if (threeD->reCalculateFill) {
	/* set up block bank */
	blockBankIndex = 0;
	thisBlock = threeD->blockBank;
	u = threeD->legoResults[0];
	v = threeD->legoResults[1];
	w = threeD->legoResults[2];
	for (i = 0; i < threeD->nLegoPoints; i += 8) {
	    p = &u[i];
	    q = &v[i];
	    r = &w[i];
	   /*
	    * find eye distances to base of each block, in x-z plane only 
	    */
	    zMax = -FLT_MAX;
	    zMin = FLT_MAX;
	    for (j = 0; j < 4; j++) {
		if (disp->dist < FLT_MAX) {
		    zDist = disp->dist * r[j];
		    zEye2 = zDist * zDist + p[j] * p[j];
		} else {	/* if dist infinite, just sort according to y
				 * height */
		    zEye2 = v[i];
		}
		if (zEye2 > zMax)
		    zMax = zEye2;
		if (zEye2 < zMin) {
		    zMin = zEye2;
		    zMinCorner = j;
		}
	    }
	    thisBlock->xData = p;
	    thisBlock->yData = q;
	    thisBlock->maxZ = zMax;
	    thisBlock->minZ = zMin;
	    thisBlock->minZ = zMin;
	    thisBlock->nearCorner = zMinCorner;
	    threeD->blockPointer[blockBankIndex++] = thisBlock;
	    thisBlock++;
	}
	threeD->numBlocks = threeD->nLegoPoints / 8;

       /*
	* now sort the block pointers in increasing min distance 
	*/
	qsort(threeD->blockPointer, threeD->numBlocks,
	    sizeof(struct block *), (int (*)
	    (const void *, const void *)) h3D_myCompare);

	threeD->reCalculateFill = 0;
    }
    return;
}


void h3D_transformWireFrame(display disp)
{
    threeD_t	       *threeD;    	  

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

    if (threeD->reCalculateLegoPoints2D) {
	h3D_checkAllocLego(disp);
	h3D_render2D(disp, threeD->nLegoPoints, threeD->legoPoints[0], 
	    threeD->legoPoints[1], threeD->legoPoints[2],
	    threeD->legoResults);
	threeD->reCalculateLegoPoints2D = 0;
    }
    return;
}    
    
    
void h3D_transformMesh(display disp)
{
    threeD_t	       *threeD;    	  

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

    if (threeD->reCalculateLegoPoints2D) {
	h3D_checkAllocLego(disp);
	h3D_render2D(disp, threeD->nLegoPoints, threeD->legoPoints[0], 
	    threeD->legoPoints[1], threeD->legoPoints[2],
	    threeD->legoResults);
	threeD->reCalculateLegoPoints2D = 0;
    }
    return;
}    
    
int h_set3DTheta( display disp, float angle)
{
    disp->theta = angle * DEG_TO_RAD;
    h3D_newTheta(disp);
    return 0;
}    

float h_get3DTheta( display disp)
{
    return disp->theta * RAD_TO_DEG;
}    

int h_set3DPhi(display disp, float angle)
{
    disp->phi = -angle * DEG_TO_RAD;
    h3D_newPhi(disp);
    return 0;
}    

float h_get3DPhi(display disp)
{
    return -disp->phi * RAD_TO_DEG;
}    

int h_set3DDist(display disp, float distance)
{
    disp->dist = distance;
    h3D_newDist(disp);
    return 0;
}    

float h_get3DDist(display disp)
{
    return disp->dist;
}    

/* 
 * Set/clear 3D plot type
 */
int h_set3DCube(display disp, int flag)
{
    threeD_t	       *threeD;    	  
    if ((threeD = disp->threeDWorkArea) == NULL) return 1;
    else {
    	disp->doCube = flag;
	return 0;
    }
}

int h_set3DWireFrame(display disp, int flag)
{
    threeD_t	       *threeD;    	  
    if ((threeD = disp->threeDWorkArea) == NULL) return 1;
    else {
    	disp->doWireFrame = flag;
	return 0;
    }
}

int h_set3DFill(display disp, int flag)
{
    threeD_t	       *threeD;    	  
    if ((threeD = disp->threeDWorkArea) == NULL) return 1;
    else {
    	disp->doFill = flag;
	return 0;
    }
}

int h_set3DMesh(display disp, int flag)
{
    threeD_t	       *threeD;    	  
    if ((threeD = disp->threeDWorkArea) == NULL) return 1;
    else {
    	disp->doMesh = flag;
	return 0;
    }
}


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