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.