gridResample3Dc.c 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289
  1. // gridResample3Dc.c
  2. // Accepts a 3D data grid along with its coordinate system information, and resamples
  3. // that grid onto another grid, specified by another coordiate system.
  4. #include <stdlib.h>
  5. #include <stdio.h>
  6. #include "mex.h"
  7. // macros for grid indexing
  8. #define GRIDIND3D(x,y,z,dim) ((x) + dim[0]*(y) + dim[0]*dim[1]*(z))
  9. // Input Arguments
  10. #define X (prhs[0]) // coordinate vector for first dimension of original data
  11. #define Y (prhs[1]) // coordinate vector for second dimension of original data
  12. #define Z (prhs[2]) // coordinate vector for third dimension of original data
  13. #define DATA (prhs[3]) // original data
  14. #define XNEW (prhs[4]) // coordinate vector for first dimension of resampled data
  15. #define YNEW (prhs[5]) // coordinate vector for second dimension of resampled data
  16. #define ZNEW (prhs[6]) // coordinate vector for third dimension of resampled data
  17. #define MODE (prhs[7]) // interpolation mode ('linear' or 'nearest')
  18. #define DATANEW (plhs[0]) // resampled data
  19. // Notes on inputs
  20. // Original coordinate vectors must be monotonically increasing, but this
  21. // does not have to be true for the new coordinate vectors.
  22. // Prototypes
  23. int binSearch(float *, float, int);
  24. void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[])
  25. {
  26. // pointers to input/output mxArray numbers of dimensions
  27. int xDim, yDim, zDim, dataDim, xNewDim, yNewDim, zNewDim, modeDim;
  28. // pointers to input/output mxArray dimensions
  29. const int *xDimPtr, *yDimPtr, *zDimPtr, *dataDimPtr;
  30. const int *xNewDimPtr, *yNewDimPtr, *zNewDimPtr, *modeDimPtr;
  31. int *dataNewDimPtr;
  32. // pointers to input/output data
  33. float *x, *y, *z, *dataPtr, *xNew, *yNew, *zNew, *dataNewPtr;
  34. char *modePtr;
  35. // utility variables
  36. int i,j,k,iNew,jNew,kNew,M,N,Q,Mnew,Nnew,Qnew;
  37. float t, u, v, f, one;
  38. int nearestNeighborFlag, linearFlag; // interpolation type flags
  39. float x0,y0,z0;
  40. float dx,dy,dz;
  41. int xUniformSpacingFlag, yUniformSpacingFlag,zUniformSpacingFlag;
  42. nearestNeighborFlag = 0;
  43. linearFlag = 0;
  44. one = 1.0;
  45. xDim = mxGetNumberOfDimensions(X);
  46. yDim = mxGetNumberOfDimensions(Y);
  47. zDim = mxGetNumberOfDimensions(Z);
  48. dataDim = mxGetNumberOfDimensions(DATA);
  49. xNewDim = mxGetNumberOfDimensions(XNEW);
  50. yNewDim = mxGetNumberOfDimensions(YNEW);
  51. zNewDim = mxGetNumberOfDimensions(ZNEW);
  52. modeDim = mxGetNumberOfDimensions(MODE);
  53. xDimPtr = mxGetDimensions(X);
  54. yDimPtr = mxGetDimensions(Y);
  55. zDimPtr = mxGetDimensions(Z);
  56. dataDimPtr = mxGetDimensions(DATA);
  57. xNewDimPtr = mxGetDimensions(XNEW);
  58. yNewDimPtr = mxGetDimensions(YNEW);
  59. zNewDimPtr = mxGetDimensions(ZNEW);
  60. modeDimPtr = mxGetDimensions(MODE);
  61. // check input arguments
  62. if ( (xDim != 2) || (yDim != 2) || (zDim != 2)
  63. || (xNewDim != 2) || (yNewDim != 2) || (zNewDim != 2)
  64. || (modeDim != 2))
  65. mexErrMsgTxt("X, Y, Z, XNEW, YNEW, ZNEW, and MODE inputs must all be vectors.");
  66. /*
  67. printf("xDim = (%d,%d)\n",xDimPtr[0],xDimPtr[1]);
  68. printf("yDim = (%d,%d)\n",yDimPtr[0],yDimPtr[1]);
  69. printf("zDim = (%d,%d)\n",zDimPtr[0],zDimPtr[1]); */
  70. // get the lengths of the vectors, as they are related to coordinate system sizes
  71. M = xDimPtr[0]*xDimPtr[1];
  72. N = yDimPtr[0]*yDimPtr[1];
  73. Q = zDimPtr[0]*zDimPtr[1];
  74. Mnew = xNewDimPtr[0]*xNewDimPtr[1];
  75. Nnew = yNewDimPtr[0]*yNewDimPtr[1];
  76. Qnew = zNewDimPtr[0]*zNewDimPtr[1];
  77. if ( !mxIsSingle(X) || !mxIsSingle(Y) || !mxIsSingle(Z)
  78. || !mxIsSingle(DATA)
  79. || !mxIsSingle(XNEW) || !mxIsSingle(YNEW) || !mxIsSingle(ZNEW))
  80. mexErrMsgTxt("X, Y, Z, DATA, XNEW, YNEW, ZNEW must be single arrays.");
  81. /*
  82. printf("DataDim = (%d,%d,%d)\n",dataDimPtr[0],dataDimPtr[1],dataDimPtr[2]);
  83. printf("X,Y,Z = (%d,%d,%d)\n",M,N,Q); */
  84. // check the size of the original data array against the original coordinate system
  85. if ( ((dataDim == 2) && ((M != dataDimPtr[0]) || (N != dataDimPtr[1]) || (Q != 1)))
  86. || ((dataDim == 3) && ((M != dataDimPtr[0]) || (N != dataDimPtr[1]) || (Q != dataDimPtr[2])))
  87. || (dataDim > 3))
  88. mexErrMsgTxt("DATA must be sized to match the lengths of X, Y, and Z.\n");
  89. if (!mxIsChar(MODE))
  90. mexErrMsgTxt("MODE must be a character array");
  91. // get coordinate system data pointers
  92. x = (float *)mxGetData(X);
  93. y = (float *)mxGetData(Y);
  94. z = (float *)mxGetData(Z);
  95. xNew = (float *)mxGetData(XNEW);
  96. yNew = (float *)mxGetData(YNEW);
  97. zNew = (float *)mxGetData(ZNEW);
  98. // ensure that the original coordinate system vectors are monotonically increasing
  99. for (i=1;i<M;i++)
  100. if ((x[i] - x[i-1]) <= 0.0)
  101. mexErrMsgTxt("X must be a monotonically increasing vector.");
  102. for (j=1;j<N;j++)
  103. if ((y[j] - y[j-1]) <= 0.0)
  104. mexErrMsgTxt("Y must be a monotonically increasing vector.");
  105. for (k=1;k<Q;k++)
  106. if ((z[k] - z[k-1]) <= 0.0)
  107. mexErrMsgTxt("Z must be a monotonically increasing vector.");
  108. xUniformSpacingFlag = 1;
  109. yUniformSpacingFlag = 1;
  110. zUniformSpacingFlag = 1;
  111. // centers of first elements in each axis
  112. x0 = x[0];
  113. y0 = y[0];
  114. z0 = z[0];
  115. // check to see if any axes are uniformly-spaced
  116. dx = x[1] - x[0];
  117. for (i=1;i<M;i++)
  118. if (fabs(fabs(x[i] - x[i-1]) - fabs(dx))/fabs(dx) > 1e-4)
  119. xUniformSpacingFlag = 0;
  120. dy = y[1] - y[0];
  121. for (j=1;j<N;j++)
  122. if (fabs(fabs(y[j] - y[j-1]) - fabs(dy))/fabs(dy) > 1e-4)
  123. yUniformSpacingFlag = 0;
  124. dz = z[1] - z[0];
  125. for (k=1;k<Q;k++)
  126. if (fabs(fabs(z[k] - z[k-1]) - fabs(dz))/fabs(dz) > 1e-4)
  127. zUniformSpacingFlag = 0;
  128. // set pointer to original data
  129. dataPtr = (float *)mxGetData(DATA);
  130. // read in the mode
  131. modePtr = (char *)malloc(sizeof(char)*modeDimPtr[0]*modeDimPtr[1]);
  132. mxGetString(MODE,modePtr,modeDimPtr[0]*modeDimPtr[1]+1);
  133. // determine the interpolation mode
  134. if (strcmp(modePtr,"nearest") == 0)
  135. nearestNeighborFlag = 1;
  136. else if (strcmp(modePtr,"linear") == 0)
  137. linearFlag = 1;
  138. else
  139. mexErrMsgTxt("Unknown interpolation mode. Must be either 'linear' or 'nearest'.");
  140. // set up the output grid
  141. dataNewDimPtr = (int *)malloc(sizeof(int)*3);
  142. dataNewDimPtr[0] = Mnew;
  143. dataNewDimPtr[1] = Nnew;
  144. dataNewDimPtr[2] = Qnew;
  145. if((DATANEW = mxCreateNumericArray(3,dataNewDimPtr,mxSINGLE_CLASS,mxREAL)) == NULL)
  146. mexErrMsgTxt("Unable to create DATANEW array.");
  147. dataNewPtr = (float *)mxGetData(DATANEW);
  148. // interpolate the old grid onto the new one
  149. for (kNew=0;kNew<Qnew;kNew++) for (jNew=0;jNew<Nnew;jNew++) for (iNew=0;iNew<Mnew;iNew++)
  150. {
  151. // mexPrintf("(iNew,jNew,kNew) = (%d,%d,%d)\n",iNew,jNew,kNew);
  152. // find the bordering indices in the old grid that contain the current point
  153. // in the new grid
  154. if (xUniformSpacingFlag == 0)
  155. i = binSearch(x,xNew[iNew],M);
  156. else
  157. i = (int)((xNew[iNew]-x0)/dx);
  158. if (yUniformSpacingFlag == 0)
  159. j = binSearch(y,yNew[jNew],N);
  160. else
  161. j = (int)((yNew[jNew]-y0)/dy);
  162. if (zUniformSpacingFlag == 0)
  163. k = binSearch(z,zNew[kNew],Q);
  164. else
  165. k = (int)((zNew[kNew]-z0)/dz);
  166. // mexPrintf("(i,j,k) = (%d,%d,%d)\n",i,j,k);
  167. // if the current point falls outside of the original grid, place a zero there
  168. if ( (i < 0) || (i+1 >= M)
  169. || (j < 0) || (j+1 >= N)
  170. || (k < 0) || (k+1 >= Q))
  171. dataNewPtr[GRIDIND3D(iNew,jNew,kNew,dataNewDimPtr)] = 0.0;
  172. else
  173. {
  174. // the divisions here are safe, since x, y, and z are monotonically increasing
  175. t = (xNew[iNew] - x[i])/(x[i+1] - x[i]);
  176. u = (yNew[jNew] - y[j])/(y[j+1] - y[j]);
  177. v = (zNew[kNew] - z[k])/(z[k+1] - z[k]);
  178. // printf("(i,j,k) = (%d,%d,%d), (t,u,v) = (%f,%f,%f)\n",i,j,k,t,u,v);
  179. if (linearFlag == 1)
  180. // linear interpolation
  181. f = dataPtr[GRIDIND3D(i,j,k,dataDimPtr)]*(one-t)*(one-u)*(one-v)
  182. + dataPtr[GRIDIND3D(i,j,k+1,dataDimPtr)]*(one-t)*(one-u)*v
  183. + dataPtr[GRIDIND3D(i,j+1,k+1,dataDimPtr)]*(one-t)*u*v
  184. + dataPtr[GRIDIND3D(i+1,j+1,k+1,dataDimPtr)]*t*u*v
  185. + dataPtr[GRIDIND3D(i,j+1,k,dataDimPtr)]*(one-t)*u*(one-v)
  186. + dataPtr[GRIDIND3D(i+1,j+1,k,dataDimPtr)]*t*u*(one-v)
  187. + dataPtr[GRIDIND3D(i+1,j,k+1,dataDimPtr)]*t*(one-u)*v
  188. + dataPtr[GRIDIND3D(i+1,j,k,dataDimPtr)]*t*(one-u)*(one-v);
  189. else if (nearestNeighborFlag == 1)
  190. // nearest neighbor interpolation
  191. {
  192. if (t >= 0.5)
  193. i = i + 1;
  194. if (u >= 0.5)
  195. j = j + 1;
  196. if (v >= 0.5)
  197. k = k + 1;
  198. f = dataPtr[GRIDIND3D(i,j,k,dataDimPtr)];
  199. }
  200. dataNewPtr[GRIDIND3D(iNew,jNew,kNew,dataNewDimPtr)] = f;
  201. }
  202. }
  203. // free the mallocs
  204. free(dataNewDimPtr);
  205. }
  206. int binSearch(float *a, float searchnum, int M)
  207. /* Accepts a float array of data of length M ordered lowest to highest and a number
  208. called searchnum. Returns the index of the first element of the array, a, that is
  209. less than or equal to the searchnum. If the searchnum is less than a[0], then -1
  210. is returned, and if the searchnum is greater than a[M-1], then M is returned. */
  211. {
  212. int bottom, mid, top;
  213. bottom = 0;
  214. top = M-1;
  215. // Ensure that the search parameter lies inside boundaries
  216. if(searchnum > a[top])
  217. return(M);
  218. if(searchnum < a[bottom])
  219. return(-1);
  220. while(1)
  221. {
  222. mid = (top + bottom)/2;
  223. if (searchnum == a[bottom])
  224. return(bottom);
  225. else if (searchnum == a[mid])
  226. return(mid);
  227. else if (searchnum == a[top])
  228. return(top);
  229. else if(searchnum < a[mid])
  230. top = mid - 1;
  231. else if(searchnum > a[mid + 1])
  232. bottom = mid + 1;
  233. else
  234. return(mid);
  235. }
  236. }