int regFloat3d (struct rParam *regDataPtr) { struct fitRec fit, invFit; float *pyrHdl1[maxPyrLevels], *pyrHdl2[maxPyrLevels]; float *mskHdl1[maxPyrLevels], *mskHdl2[maxPyrLevels]; float *inPtr1, *inPtr2; float *outPtr; float *mskPtr1, *mskPtr2; float *mskPtr; float *u; double origin[3]; double epsilon[maxPyrLevels]; long nxRange[maxPyrLevels]; long nyRange[maxPyrLevels]; long nzRange[maxPyrLevels]; int ia[hessianSize]; double mse, snr; double lambda; double x1, y1, z1; double x2, y2, z2; double mean; int nx, ny, nz; int k, l; int x, y, z; switch (regDataPtr->directives.convergence) { case gravity: if (regDataPtr->directives.isoScaling || regDataPtr->directives.xRot || regDataPtr->directives.yRot || regDataPtr->directives.zRot || regDataPtr->directives.xSkew || regDataPtr->directives.ySkew || regDataPtr->directives.zSkew || regDataPtr->directives.matchGrey) { message("ERROR - Gravity center can only be translated"); return(ERROR); } else if ((regDataPtr->directives.importFit != 0) && (regDataPtr->directives.xTrans || regDataPtr->directives.yTrans || regDataPtr->directives.zTrans)) message("WARNING - Ignoring 'importFit' parameter"); break; case Marquardt: break; default: message("ERROR - Unknown convergence specification"); return(ERROR); } switch (regDataPtr->directives.interpolation) { case zero: if (regDataPtr->directives.convergence != gravity) { message("ERROR - Nearest neighbor interpolation valid only for gravity"); return(ERROR); } case one: case three: break; default: message("ERROR - Unknown interpolation specification"); return(ERROR); } if (regDataPtr->directives.zSqueeze && (regDataPtr->nz == 1)) { message("ERROR - Inconsistent parameters: unable to shrink Z-axis in 2-D"); return(ERROR); } if ((!regDataPtr->directives.zSqueeze) && (regDataPtr->nz != 1) && regDataPtr->directives.isoScaling) { message("ERROR - Inconsistent parameters: zSqueeze needed for isoScaling in 3-D"); return(ERROR); } if (regDataPtr->directives.isoScaling && (regDataPtr->directives.xSkew || regDataPtr->directives.ySkew || regDataPtr->directives.zSkew)) { message("ERROR - Inconsistent parameters: (x,y,z)Skew and isoScaling"); return(ERROR); } if ((regDataPtr->directives.xRot || regDataPtr->directives.yRot || regDataPtr->directives.zRot) && (regDataPtr->directives.xSkew || regDataPtr->directives.ySkew || regDataPtr->directives.zSkew)) { message("ERROR - Inconsistent parameters: (x,y,z)Rot and (x,y,z)Skew"); return(ERROR); } if (regDataPtr->directives.xRot && (!regDataPtr->directives.zSqueeze)) { message("ERROR - Inconsistent parameters: xRot needs zSqueeze"); return(ERROR); } if (regDataPtr->directives.yRot && (!regDataPtr->directives.zSqueeze)) { message("ERROR - Inconsistent parameters: yRot needs zSqueeze"); return(ERROR); } message("STATUS - Initializing..."); inPtr1 = regDataPtr->inPtr1; inPtr2 = regDataPtr->inPtr2; mskPtr1 = regDataPtr->inMsk1; mskPtr2 = regDataPtr->inMsk2; outPtr = regDataPtr->outPtr; mskPtr = regDataPtr->mskPtr; nx = regDataPtr->nx; ny = regDataPtr->ny; nz = regDataPtr->nz; initialEstimate(&fit, nx, ny, nz); if ((regDataPtr->directives.importFit != 0) && (regDataPtr->directives.convergence != gravity)) { if (importFit(&fit, regDataPtr->inFit) == ERROR) { message("ERROR - Importation of fit variables failed"); return(ERROR); } switch (regDataPtr->directives.importFit) { case -1: if (invertFit(&fit, &invFit) == ERROR) { message("ERROR - Unable to compute the backward transformation"); return(ERROR); } fit = invFit; break; case 1: break; default: message("ERROR - Unknown importFit specification"); return(ERROR); } } switch (regDataPtr->directives.testMask) { case blank: u = mskPtr1; for (z = 0; (z < nz); z++) for (y = 0; (y < ny); y++) for (x = 0; (x < nx); u++, x++) *u = 1.0F; break; case provided: break; case computed: if (maskFromData(inPtr1, mskPtr1, nx, ny, nz, regDataPtr->sx, regDataPtr->sy, regDataPtr->sz) == ERROR) { message("ERROR - Unable to extract mask from test data"); return(ERROR); } break; default: message("ERROR - Unknown test mask specification"); return(ERROR); } switch (regDataPtr->directives.referenceMask) { case blank: u = mskPtr2; for (z = 0; (z < nz); z++) for (y = 0; (y < ny); y++) for (x = 0; (x < nx); u++, x++) *u = 1.0F; break; case provided: break; case computed: if (maskFromData(inPtr2, mskPtr2, nx, ny, nz, regDataPtr->sx, regDataPtr->sy, regDataPtr->sz) == ERROR) { message("ERROR - Unable to extract mask from reference data"); return(ERROR); } break; default: message("ERROR - Unknown reference mask specification"); return(ERROR); } if (regDataPtr->directives.zapMean) { mean = averageMskData(inPtr1, mskPtr1, nx, ny, nz); zapMean(inPtr1, mean, nx, ny, nz); mean = averageMskData(inPtr2, mskPtr2, nx, ny, nz); zapMean(inPtr2, mean, nx, ny, nz); } if ((!regDataPtr->directives.isoScaling) && (!regDataPtr->directives.xTrans) && (!regDataPtr->directives.yTrans) && (!regDataPtr->directives.zTrans) && (!regDataPtr->directives.xRot) && (!regDataPtr->directives.yRot) && (!regDataPtr->directives.zRot) && (!regDataPtr->directives.xSkew) && (!regDataPtr->directives.ySkew) && (!regDataPtr->directives.zSkew) && (!regDataPtr->directives.matchGrey)) { message("WARNING - Nothing to optimize"); // We save the extracted transformation values to the ouptut structure used in the mex file. regDataPtr->fit.dx[0]=fit.dx[0]; regDataPtr->fit.dx[1]=fit.dx[1]; regDataPtr->fit.psi=fit.psi; regDataPtr->fit.skew[0][2]=fit.skew[0][2]; regDataPtr->fit.skew[1][2]=fit.skew[1][2]; regDataPtr->fit.skew[2][2]=fit.skew[2][2]; regDataPtr->fit.skew[0][1]=fit.skew[0][1]; regDataPtr->fit.skew[1][1]=fit.skew[1][1]; regDataPtr->fit.skew[2][1]=fit.skew[2][1]; regDataPtr->fit.skew[0][0]=fit.skew[0][0]; regDataPtr->fit.skew[1][0]=fit.skew[1][0]; regDataPtr->fit.skew[2][0]=fit.skew[2][0]; regDataPtr->fit.origin[0]=fit.origin[0]; regDataPtr->fit.origin[1]=fit.origin[1]; message("STATUS - Creating output..."); if (dirMskTransform(&fit, inPtr1, outPtr, mskPtr1, mskPtr, nx, ny, nz, regDataPtr->directives.greyRendering, regDataPtr->directives.interpolation) == ERROR) { message("ERROR - Final transformation of test image failed"); return(ERROR); } adornImage(outPtr, mskPtr, nx, ny, nz, nx, ny, nz, regDataPtr->directives.clipping, regDataPtr->backgrnd); computeMskSnr(&mse, &snr, inPtr2, outPtr, mskPtr2, mskPtr, regDataPtr->directives.maskCombine, nx, ny, nz); if (exportFit(&fit) == ERROR ) { message("ERROR - Assignment of transformation variables failed"); return(ERROR); } if (exportSummary(&fit, mse, snr) == ERROR ) { message("ERROR - Assignment of summary variables failed"); return(ERROR); } if (regDataPtr->directives.exportFit) if (fExportFit(&fit, regDataPtr->outFit) == ERROR ) { message("ERROR - Exportation of transformation variables failed"); return(ERROR); } return(!ERROR); } bilevelFormat(mskPtr1, nx, ny, nz); bilevelFormat(mskPtr2, nx, ny, nz); if (regDataPtr->directives.convergence == gravity) { logicalFormat(mskPtr1, nx, ny, nz); logicalFormat(mskPtr2, nx, ny, nz); message("STATUS - Aligning centers of gravity..."); if (getCenter(inPtr1, mskPtr1, nx, ny, nz, &x1, &y1, &z1) == ERROR) { message("ERROR - Unable to compute 1st center of gravity"); return(ERROR); } if (getCenter(inPtr2, mskPtr2, nx, ny, nz, &x2, &y2, &z2) == ERROR) { message("ERROR - Unable to compute 2nd center of gravity"); return(ERROR); } fit.dx[0] = x2 - x1; fit.dx[1] = y2 - y1; fit.dx[2] = z2 - z1; // We save the extracted transformation values to the ouptut structure used in the mex file. regDataPtr->fit.dx[0]=fit.dx[0]; regDataPtr->fit.dx[1]=fit.dx[1]; regDataPtr->fit.psi=fit.psi; regDataPtr->fit.skew[0][2]=fit.skew[0][2]; regDataPtr->fit.skew[1][2]=fit.skew[1][2]; regDataPtr->fit.skew[2][2]=fit.skew[2][2]; regDataPtr->fit.skew[0][1]=fit.skew[0][1]; regDataPtr->fit.skew[1][1]=fit.skew[1][1]; regDataPtr->fit.skew[2][1]=fit.skew[2][1]; regDataPtr->fit.skew[0][0]=fit.skew[0][0]; regDataPtr->fit.skew[1][0]=fit.skew[1][0]; regDataPtr->fit.skew[2][0]=fit.skew[2][0]; regDataPtr->fit.origin[0]=fit.origin[0]; regDataPtr->fit.origin[1]=fit.origin[1]; message("STATUS - Creating output..."); if (dirMskTransform(&fit, inPtr1, outPtr, mskPtr1, mskPtr, nx, ny, nz, regDataPtr->directives.greyRendering, regDataPtr->directives.interpolation) == ERROR) { message("ERROR - Final transformation of test image failed"); return(ERROR); } adornImage(outPtr, mskPtr, nx, ny, nz, nx, ny, nz, regDataPtr->directives.clipping, regDataPtr->backgrnd); computeMskSnr(&mse, &snr, inPtr2, outPtr, mskPtr2, mskPtr, regDataPtr->directives.maskCombine, nx, ny, nz); if (exportFit(&fit) == ERROR ) { message("ERROR - Assignment of transformation variables failed"); return(ERROR); } if (exportSummary(&fit, mse, snr) == ERROR ) { message("ERROR - Assignment of summary variables failed"); return(ERROR); } if (regDataPtr->directives.exportFit) if (fExportFit(&fit, regDataPtr->outFit) == ERROR ) { message("ERROR - Exportation of transformation variables failed"); return(ERROR); } return(!ERROR); } for (l = 0; (l < regDataPtr->levels); l++) { pyrHdl1[l] = (float *)NULL; pyrHdl2[l] = (float *)NULL; mskHdl1[l] = (float *)NULL; mskHdl2[l] = (float *)NULL; } if (pyramid(mskPtr1, regDataPtr->levels, mskHdl1, nxRange, nyRange, nzRange, nx, ny, nz, regDataPtr->directives.zSqueeze, regDataPtr->directives.interpolation) == ERROR) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Not enough memory for 1st mask pyramid computation"); return(ERROR); } if (pyramid(mskPtr2, regDataPtr->levels, mskHdl2, nxRange, nyRange, nzRange, nx, ny, nz, regDataPtr->directives.zSqueeze, regDataPtr->directives.interpolation) == ERROR) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Not enough memory for 2nd mask pyramid computation"); return(ERROR); } logicalFormat(mskPtr1, nx, ny, nz); logicalFormat(mskPtr2, nx, ny, nz); for (l = 0; (l < regDataPtr->levels); l++) { logicalFormat(mskHdl1[l], (int)nxRange[l], (int)nyRange[l], (int)nzRange[l]); logicalFormat(mskHdl2[l], (int)nxRange[l], (int)nyRange[l], (int)nzRange[l]); } if (pyramid(inPtr1, regDataPtr->levels, pyrHdl1, nxRange, nyRange, nzRange, nx, ny, nz, regDataPtr->directives.zSqueeze, regDataPtr->directives.interpolation) == ERROR) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Not enough memory for 1st pyramid computation"); return(ERROR); } if (pyramid(inPtr2, regDataPtr->levels, pyrHdl2, nxRange, nyRange, nzRange, nx, ny, nz, regDataPtr->directives.zSqueeze, regDataPtr->directives.interpolation) == ERROR ) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Not enough memory for 2nd pyramid computation"); return(ERROR); } epsilon[0] = regDataPtr->epsilon; switch (regDataPtr->directives.convergence) { case Marquardt: for (l = 1; (l < regDataPtr->levels); l++) epsilon[l] = epsilon[l - 1]; break; default: freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Unknown convergence"); return(ERROR); } message("STATUS - Optimizing..."); origin[0] = (double)((nxRange[0] - 1L) / 2L); origin[1] = (double)((nyRange[0] - 1L) / 2L); origin[2] = (double)((nzRange[0] - 1L) / 2L); convertOrigin(&fit, origin); for (l = 0; (l < (regDataPtr->levels - 1)); l++) downscaleFit(&fit, nxRange, nyRange, nzRange, l, regDataPtr->directives.zSqueeze); lambda = regDataPtr->firstLambda; for (l = regDataPtr->levels - 1; (l >= 0); l--) { if ((l == (regDataPtr->levels - 1)) || (l >= (regDataPtr->lastLevel - 1))) { ia[0] = regDataPtr->directives.xTrans; /* dx[0] */ ia[1] = regDataPtr->directives.yTrans && (nyRange[l] != 1L); /* dx[1] */ ia[2] = regDataPtr->directives.zTrans && (nzRange[l] != 1L); /* dx[2] */ for (k = 3; (k < 12); k++) ia[k] = FALSE; ia[12] = regDataPtr->directives.matchGrey; /* gamma */ if (regDataPtr->directives.xSkew) { ia[3] = TRUE; /* skew[0][0] */ ia[6] = (nyRange[l] != 1L); /* skew[1][0] */ ia[9] = (nzRange[l] != 1L); /* skew[2][0] */ } if (regDataPtr->directives.ySkew) { ia[4] = (nyRange[l] != 1L); /* skew[0][1] */ ia[7] = (nyRange[l] != 1L); /* skew[1][1] */ ia[10] = (nzRange[l] != 1L); /* skew[2][1] */ } if (regDataPtr->directives.zSkew) { ia[5] = (nzRange[l] != 1L); /* skew[0][2] */ ia[8] = (nzRange[l] != 1L); /* skew[1][2] */ ia[11] = (nzRange[l] != 1L); /* skew[2][2] */ } if (regDataPtr->directives.xRot || regDataPtr->directives.yRot || regDataPtr->directives.zRot || regDataPtr->directives.isoScaling) { ia[3] = regDataPtr->directives.xRot && (nyRange[l] != 1L); /* phi */ ia[4] = regDataPtr->directives.yRot && (nzRange[l] != 1L); /* theta */ ia[5] = regDataPtr->directives.zRot && (nyRange[l] != 1L); /* psi */ ia[6] = regDataPtr->directives.isoScaling; /* lambda */ ia[7] = regDataPtr->directives.matchGrey; /* gamma */ ia[8] = FALSE; ia[9] = FALSE; ia[10] = FALSE; ia[11] = FALSE; ia[12] = FALSE; } switch (regDataPtr->directives.convergence) { case Marquardt: if (optimize(&fit, &(regDataPtr->directives), ia, pyrHdl1[l], pyrHdl2[l], mskHdl1[l], mskHdl2[l], outPtr, mskPtr, &lambda, regDataPtr->firstLambda, regDataPtr->lambdaScale, epsilon[l], regDataPtr->minGain, (int)nxRange[l], (int)nyRange[l], (int)nzRange[l]) == ERROR) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Optimization failed (Marquardt)"); return(ERROR); } lambda = regDataPtr->firstLambda; break; default: freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Unknown convergence"); return(ERROR); } } if (l != 0) upscaleFit(&fit, nxRange, nyRange, nzRange, l, regDataPtr->directives.zSqueeze); } convertOrigin(&fit, origin); // We save the extracted transformation values to the ouptut structure used in the mex file. regDataPtr->fit.dx[0]=fit.dx[0]; regDataPtr->fit.dx[1]=fit.dx[1]; regDataPtr->fit.psi=fit.psi; regDataPtr->fit.skew[0][2]=fit.skew[0][2]; regDataPtr->fit.skew[1][2]=fit.skew[1][2]; regDataPtr->fit.skew[2][2]=fit.skew[2][2]; regDataPtr->fit.skew[0][1]=fit.skew[0][1]; regDataPtr->fit.skew[1][1]=fit.skew[1][1]; regDataPtr->fit.skew[2][1]=fit.skew[2][1]; regDataPtr->fit.skew[0][0]=fit.skew[0][0]; regDataPtr->fit.skew[1][0]=fit.skew[1][0]; regDataPtr->fit.skew[2][0]=fit.skew[2][0]; regDataPtr->fit.origin[0]=fit.origin[0]; regDataPtr->fit.origin[1]=fit.origin[1]; message("STATUS - Creating output..."); if (dirMskTransform(&fit, inPtr1, outPtr, mskPtr1, mskPtr, nx, ny, nz, regDataPtr->directives.greyRendering, regDataPtr->directives.interpolation) == ERROR) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Final transformation of test image failed"); return(ERROR); } adornImage(outPtr, mskPtr, nx, ny, nz, (int)nxRange[0], (int)nyRange[0], (int)nzRange[0], regDataPtr->directives.clipping, regDataPtr->backgrnd); computeMskSnr(&mse, &snr, inPtr2, outPtr, mskPtr2, mskPtr, regDataPtr->directives.maskCombine, nx, ny, nz); if (exportFit(&fit) == ERROR ) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Assignment of transformation variables failed"); return(ERROR); } if (exportSummary(&fit, mse, snr) == ERROR ) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Assignment of summary variables failed"); return(ERROR); } if (regDataPtr->directives.exportFit) if (fExportFit(&fit, regDataPtr->outFit) == ERROR ) { freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); message("ERROR - Exportation of transformation variables failed"); return(ERROR); } freePyramids(pyrHdl1, pyrHdl2, mskHdl1, mskHdl2, regDataPtr->levels); return(!ERROR); } /* End of regFloat3d */
int invTransform (struct fitRec *fit, float *inPtr, double *splinePtr, float *outPtr, float *inMsk, float *outMsk, int nx, int ny, int nz, enum iDegree interpolation) { double *wtx, *wty, *wtz; double *dpi, *dpj; float *fpi, *fpj; long *fdx, *fdy, *fdz; double weightX[5], weightY[5], weightZ[5]; long foldX[5], foldY[5], foldZ[5]; struct fitRec invFit; ptrdiff_t d; double xO, yO, zO; double xz, yz, zz; double xy, yy, zy; double xIn, yIn, zIn; double xOut, yOut, zOut; double q, qi, qj; long lnx = (long)nx, lny = (long)ny, lnz = (long)nz; long nxy = lnx * lny; long x, y, z; long i, j, k; if (invertFit(fit, &invFit) == ERROR) { message("ERROR - Unable to compute the backward transformation"); return(ERROR); } xO = invFit.origin[0]; yO = invFit.origin[1]; zO = invFit.origin[2]; switch (interpolation) { case one: for (zOut = -zO; (zOut < ((double)nz - zO)); zOut += 1.0) { xz = invFit.skew[0][2] * zOut - invFit.dx[0] + xO; yz = invFit.skew[1][2] * zOut - invFit.dx[1] + yO; zz = invFit.skew[2][2] * zOut - invFit.dx[2] + zO; for (yOut = -yO; (yOut < ((double)ny - yO)); yOut += 1.0) { xy = xz + invFit.skew[0][1] * yOut; yy = yz + invFit.skew[1][1] * yOut; zy = zz + invFit.skew[2][1] * yOut; for (xOut = -xO; (xOut < ((double)nx - xO)); xOut += 1.0) { xIn = xy + invFit.skew[0][0] * xOut + 0.5; yIn = yy + invFit.skew[1][0] * xOut + 0.5; zIn = zy + invFit.skew[2][0] * xOut + 0.5; x = (long)xIn; if (xIn < 0.0) x--; y = (long)yIn; if (yIn < 0.0) y--; z = (long)zIn; if (zIn < 0.0) z--; if ((0L <= x) && (x < lnx) && (0L <= y) && (y < lny) && (0L <= z) && (z < lnz)) { d = (ptrdiff_t)(z * nxy + y * lnx + x); *outMsk = *(inMsk + d); } else { d = (ptrdiff_t)(-1); *outMsk = 0.0F; } if (*outMsk++ != 0.0F) { xIn -= 0.5; yIn -= 0.5; zIn -= 0.5; wtz = weightZ; fdz = foldZ; for (k = z - 1L; (k <= (z + 1L)); k++) { *wtz++ = (lnz == 1L) ? (1.0) : (BsplnWght1(k, zIn)); *fdz++ = (lnz == 1L) ? (0L) : (fold(k, lnz) * nxy); } wty = weightY; fdy = foldY; for (j = y - 1L; (j <= (y + 1L)); j++) { *wty++ = BsplnWght1(j, yIn); *fdy++ = fold(j, lny) * lnx; } wtx = weightX; fdx = foldX; for (i = x - 1L; (i <= (x + 1L)); i++) { *wtx++ = BsplnWght1(i, xIn); *fdx++ = fold(i, lnx); } q = 0.0; wtz = weightZ; fdz = foldZ; for (k = (lnz == 1L) ? (1L) : (3L); (k-- > 0L);) { wty = weightY; fdy = foldY; fpj = inPtr + (ptrdiff_t)(*fdz++); qj = 0.0; for (j = 3L; (j-- > 0L);) { wtx = weightX; fdx = foldX; fpi = fpj + (ptrdiff_t)(*fdy++); qi = 0.0; for (i = 3L; (i-- > 0L);) qi += *wtx++ * (double)*(fpi + (ptrdiff_t)(*fdx++)); qj += qi * *wty++; } q += qj * *wtz++; } } else q = (d == (ptrdiff_t)(-1)) ? (0.0) : ((double)*(inPtr + d) * exp(invFit.gamma)); *outPtr++ = (float)q; } } } break; case three: for (zOut = -zO; (zOut < ((double)nz - zO)); zOut += 1.0) { xz = invFit.skew[0][2] * zOut - invFit.dx[0] + xO; yz = invFit.skew[1][2] * zOut - invFit.dx[1] + yO; zz = invFit.skew[2][2] * zOut - invFit.dx[2] + zO; for (yOut = -yO; (yOut < ((double)ny - yO)); yOut += 1.0) { xy = xz + invFit.skew[0][1] * yOut; yy = yz + invFit.skew[1][1] * yOut; zy = zz + invFit.skew[2][1] * yOut; for (xOut = -xO; (xOut < ((double)nx - xO)); xOut += 1.0) { xIn = xy + invFit.skew[0][0] * xOut + 0.5; yIn = yy + invFit.skew[1][0] * xOut + 0.5; zIn = zy + invFit.skew[2][0] * xOut + 0.5; x = (long)xIn; if (xIn < 0.0) x--; y = (long)yIn; if (yIn < 0.0) y--; z = (long)zIn; if (zIn < 0.0) z--; if ((0L <= x) && (x < lnx) && (0L <= y) && (y < lny) && (0L <= z) && (z < lnz)) { d = (ptrdiff_t)(z * nxy + y * lnx + x); *outMsk = *(inMsk + d); } else { d = (ptrdiff_t)(-1); *outMsk = 0.0F; } if (*outMsk++ != 0.0F) { xIn -= 0.5; yIn -= 0.5; zIn -= 0.5; wtz = weightZ; fdz = foldZ; for (k = z - 2L; (k <= (z + 2L)); k++) { *wtz++ = (lnz == 1L) ? (1.0) : (BsplnWght3(k, zIn)); *fdz++ = (lnz == 1L) ? (0L) : (fold(k, lnz) * nxy); } wty = weightY; fdy = foldY; for (j = y - 2L; (j <= (y + 2L)); j++) { *wty++ = BsplnWght3(j, yIn); *fdy++ = fold(j, lny) * lnx; } wtx = weightX; fdx = foldX; for (i = x - 2L; (i <= (x + 2L)); i++) { *wtx++ = BsplnWght3(i, xIn); *fdx++ = fold(i, lnx); } q = 0.0; wtz = weightZ; fdz = foldZ; for (k = (lnz == 1L) ? (1L) : (5L); (k-- > 0L);) { wty = weightY; fdy = foldY; dpj = splinePtr + (ptrdiff_t)(*fdz++); qj = 0.0; for (j = 5L; (j-- > 0L);) { wtx = weightX; fdx = foldX; dpi = dpj + (ptrdiff_t)(*fdy++); qi = 0.0; for (i = 5L; (i-- > 0L);) qi += *wtx++ * *(dpi + (ptrdiff_t)(*fdx++)); qj += qi * *wty++; } q += qj * *wtz++; } } else q = (d == (ptrdiff_t)(-1)) ? (0.0) : ((double)*(inPtr + d) * exp(invFit.gamma)); *outPtr++ = (float)q; } } } break; default: message("ERROR - Unknown interpolation specification"); return(ERROR); } return(!ERROR); } /* End of invTransform */