IntpTricubic3.h 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528
  1. // David Eberly, Geometric Tools, Redmond WA 98052
  2. // Copyright (c) 1998-2020
  3. // Distributed under the Boost Software License, Version 1.0.
  4. // https://www.boost.org/LICENSE_1_0.txt
  5. // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
  6. // Version: 4.0.2019.08.13
  7. #pragma once
  8. #include <Mathematics/Logger.h>
  9. #include <array>
  10. // The interpolator is for uniformly spaced(x,y z)-values. The input samples
  11. // must be stored in lexicographical order to represent f(x,y,z); that is,
  12. // F[c + xBound*(r + yBound*s)] corresponds to f(x,y,z), where c is the index
  13. // corresponding to x, r is the index corresponding to y, and s is the index
  14. // corresponding to z. Exact interpolation is achieved by setting catmullRom
  15. // to 'true', giving you the Catmull-Rom blending matrix. If a smooth
  16. // interpolation is desired, set catmullRom to 'false' to obtain B-spline
  17. // blending.
  18. namespace WwiseGTE
  19. {
  20. template <typename Real>
  21. class IntpTricubic3
  22. {
  23. public:
  24. // Construction.
  25. IntpTricubic3(int xBound, int yBound, int zBound, Real xMin,
  26. Real xSpacing, Real yMin, Real ySpacing, Real zMin, Real zSpacing,
  27. Real const* F, bool catmullRom)
  28. :
  29. mXBound(xBound),
  30. mYBound(yBound),
  31. mZBound(zBound),
  32. mQuantity(xBound * yBound * zBound),
  33. mXMin(xMin),
  34. mXSpacing(xSpacing),
  35. mYMin(yMin),
  36. mYSpacing(ySpacing),
  37. mZMin(zMin),
  38. mZSpacing(zSpacing),
  39. mF(F)
  40. {
  41. // At least a 4x4x4 block of data points are needed to construct
  42. // the tricubic interpolation.
  43. LogAssert(xBound >= 4 && yBound >= 4 && zBound >= 4 && F != nullptr
  44. && xSpacing > (Real)0 && ySpacing > (Real)0 && zSpacing > (Real)0,
  45. "Invalid input.");
  46. mXMax = mXMin + mXSpacing * static_cast<Real>(mXBound - 1);
  47. mInvXSpacing = (Real)1 / mXSpacing;
  48. mYMax = mYMin + mYSpacing * static_cast<Real>(mYBound - 1);
  49. mInvYSpacing = (Real)1 / mYSpacing;
  50. mZMax = mZMin + mZSpacing * static_cast<Real>(mZBound - 1);
  51. mInvZSpacing = (Real)1 / mZSpacing;
  52. if (catmullRom)
  53. {
  54. mBlend[0][0] = (Real)0;
  55. mBlend[0][1] = (Real)-0.5;
  56. mBlend[0][2] = (Real)1;
  57. mBlend[0][3] = (Real)-0.5;
  58. mBlend[1][0] = (Real)1;
  59. mBlend[1][1] = (Real)0;
  60. mBlend[1][2] = (Real)-2.5;
  61. mBlend[1][3] = (Real)1.5;
  62. mBlend[2][0] = (Real)0;
  63. mBlend[2][1] = (Real)0.5;
  64. mBlend[2][2] = (Real)2;
  65. mBlend[2][3] = (Real)-1.5;
  66. mBlend[3][0] = (Real)0;
  67. mBlend[3][1] = (Real)0;
  68. mBlend[3][2] = (Real)-0.5;
  69. mBlend[3][3] = (Real)0.5;
  70. }
  71. else
  72. {
  73. mBlend[0][0] = (Real)1 / (Real)6;
  74. mBlend[0][1] = (Real)-3 / (Real)6;
  75. mBlend[0][2] = (Real)3 / (Real)6;
  76. mBlend[0][3] = (Real)-1 / (Real)6;;
  77. mBlend[1][0] = (Real)4 / (Real)6;
  78. mBlend[1][1] = (Real)0 / (Real)6;
  79. mBlend[1][2] = (Real)-6 / (Real)6;
  80. mBlend[1][3] = (Real)3 / (Real)6;
  81. mBlend[2][0] = (Real)1 / (Real)6;
  82. mBlend[2][1] = (Real)3 / (Real)6;
  83. mBlend[2][2] = (Real)3 / (Real)6;
  84. mBlend[2][3] = (Real)-3 / (Real)6;
  85. mBlend[3][0] = (Real)0 / (Real)6;
  86. mBlend[3][1] = (Real)0 / (Real)6;
  87. mBlend[3][2] = (Real)0 / (Real)6;
  88. mBlend[3][3] = (Real)1 / (Real)6;
  89. }
  90. }
  91. // Member access.
  92. inline int GetXBound() const
  93. {
  94. return mXBound;
  95. }
  96. inline int GetYBound() const
  97. {
  98. return mYBound;
  99. }
  100. inline int GetZBound() const
  101. {
  102. return mZBound;
  103. }
  104. inline int GetQuantity() const
  105. {
  106. return mQuantity;
  107. }
  108. inline Real const* GetF() const
  109. {
  110. return mF;
  111. }
  112. inline Real GetXMin() const
  113. {
  114. return mXMin;
  115. }
  116. inline Real GetXMax() const
  117. {
  118. return mXMax;
  119. }
  120. inline Real GetXSpacing() const
  121. {
  122. return mXSpacing;
  123. }
  124. inline Real GetYMin() const
  125. {
  126. return mYMin;
  127. }
  128. inline Real GetYMax() const
  129. {
  130. return mYMax;
  131. }
  132. inline Real GetYSpacing() const
  133. {
  134. return mYSpacing;
  135. }
  136. inline Real GetZMin() const
  137. {
  138. return mZMin;
  139. }
  140. inline Real GetZMax() const
  141. {
  142. return mZMax;
  143. }
  144. inline Real GetZSpacing() const
  145. {
  146. return mZSpacing;
  147. }
  148. // Evaluate the function and its derivatives. The functions clamp the
  149. // inputs to xmin <= x <= xmax, ymin <= y <= ymax, and zmin <= z <= zmax.
  150. // The first operator is for function evaluation. The second operator is
  151. // for function or derivative evaluations. The xOrder argument is the
  152. // order of the x-derivative, the yOrder argument is the order of the
  153. // y-derivative, and the zOrder argument is the order of the z-derivative.
  154. // All orders are zero to get the function value itself.
  155. Real operator()(Real x, Real y, Real z) const
  156. {
  157. // Compute x-index and clamp to image.
  158. Real xIndex = (x - mXMin) * mInvXSpacing;
  159. int ix = static_cast<int>(xIndex);
  160. if (ix < 0)
  161. {
  162. ix = 0;
  163. }
  164. else if (ix >= mXBound)
  165. {
  166. ix = mXBound - 1;
  167. }
  168. // Compute y-index and clamp to image.
  169. Real yIndex = (y - mYMin) * mInvYSpacing;
  170. int iy = static_cast<int>(yIndex);
  171. if (iy < 0)
  172. {
  173. iy = 0;
  174. }
  175. else if (iy >= mYBound)
  176. {
  177. iy = mYBound - 1;
  178. }
  179. // Compute z-index and clamp to image.
  180. Real zIndex = (z - mZMin) * mInvZSpacing;
  181. int iz = static_cast<int>(zIndex);
  182. if (iz < 0)
  183. {
  184. iz = 0;
  185. }
  186. else if (iz >= mZBound)
  187. {
  188. iz = mZBound - 1;
  189. }
  190. std::array<Real, 4> U;
  191. U[0] = (Real)1;
  192. U[1] = xIndex - ix;
  193. U[2] = U[1] * U[1];
  194. U[3] = U[1] * U[2];
  195. std::array<Real, 4> V;
  196. V[0] = (Real)1;
  197. V[1] = yIndex - iy;
  198. V[2] = V[1] * V[1];
  199. V[3] = V[1] * V[2];
  200. std::array<Real, 4> W;
  201. W[0] = (Real)1;
  202. W[1] = zIndex - iz;
  203. W[2] = W[1] * W[1];
  204. W[3] = W[1] * W[2];
  205. // Compute P = M*U, Q = M*V, R = M*W.
  206. std::array<Real, 4> P, Q, R;
  207. for (int row = 0; row < 4; ++row)
  208. {
  209. P[row] = (Real)0;
  210. Q[row] = (Real)0;
  211. R[row] = (Real)0;
  212. for (int col = 0; col < 4; ++col)
  213. {
  214. P[row] += mBlend[row][col] * U[col];
  215. Q[row] += mBlend[row][col] * V[col];
  216. R[row] += mBlend[row][col] * W[col];
  217. }
  218. }
  219. // Compute the tensor product (M*U)(M*V)(M*W)*D where D is the 4x4x4
  220. // subimage containing (x,y,z).
  221. --ix;
  222. --iy;
  223. --iz;
  224. Real result = (Real)0;
  225. for (int slice = 0; slice < 4; ++slice)
  226. {
  227. int zClamp = iz + slice;
  228. if (zClamp < 0)
  229. {
  230. zClamp = 0;
  231. }
  232. else if (zClamp > mZBound - 1)
  233. {
  234. zClamp = mZBound - 1;
  235. }
  236. for (int row = 0; row < 4; ++row)
  237. {
  238. int yClamp = iy + row;
  239. if (yClamp < 0)
  240. {
  241. yClamp = 0;
  242. }
  243. else if (yClamp > mYBound - 1)
  244. {
  245. yClamp = mYBound - 1;
  246. }
  247. for (int col = 0; col < 4; ++col)
  248. {
  249. int xClamp = ix + col;
  250. if (xClamp < 0)
  251. {
  252. xClamp = 0;
  253. }
  254. else if (xClamp > mXBound - 1)
  255. {
  256. xClamp = mXBound - 1;
  257. }
  258. result += P[col] * Q[row] * R[slice] *
  259. mF[xClamp + mXBound * (yClamp + mYBound * zClamp)];
  260. }
  261. }
  262. }
  263. return result;
  264. }
  265. Real operator()(int xOrder, int yOrder, int zOrder, Real x, Real y, Real z) const
  266. {
  267. // Compute x-index and clamp to image.
  268. Real xIndex = (x - mXMin) * mInvXSpacing;
  269. int ix = static_cast<int>(xIndex);
  270. if (ix < 0)
  271. {
  272. ix = 0;
  273. }
  274. else if (ix >= mXBound)
  275. {
  276. ix = mXBound - 1;
  277. }
  278. // Compute y-index and clamp to image.
  279. Real yIndex = (y - mYMin) * mInvYSpacing;
  280. int iy = static_cast<int>(yIndex);
  281. if (iy < 0)
  282. {
  283. iy = 0;
  284. }
  285. else if (iy >= mYBound)
  286. {
  287. iy = mYBound - 1;
  288. }
  289. // Compute z-index and clamp to image.
  290. Real zIndex = (z - mZMin) * mInvZSpacing;
  291. int iz = static_cast<int>(zIndex);
  292. if (iz < 0)
  293. {
  294. iz = 0;
  295. }
  296. else if (iz >= mZBound)
  297. {
  298. iz = mZBound - 1;
  299. }
  300. std::array<Real, 4> U;
  301. Real dx, xMult;
  302. switch (xOrder)
  303. {
  304. case 0:
  305. dx = xIndex - ix;
  306. U[0] = (Real)1;
  307. U[1] = dx;
  308. U[2] = dx * U[1];
  309. U[3] = dx * U[2];
  310. xMult = (Real)1;
  311. break;
  312. case 1:
  313. dx = xIndex - ix;
  314. U[0] = (Real)0;
  315. U[1] = (Real)1;
  316. U[2] = (Real)2 * dx;
  317. U[3] = (Real)3 * dx * dx;
  318. xMult = mInvXSpacing;
  319. break;
  320. case 2:
  321. dx = xIndex - ix;
  322. U[0] = (Real)0;
  323. U[1] = (Real)0;
  324. U[2] = (Real)2;
  325. U[3] = (Real)6 * dx;
  326. xMult = mInvXSpacing * mInvXSpacing;
  327. break;
  328. case 3:
  329. U[0] = (Real)0;
  330. U[1] = (Real)0;
  331. U[2] = (Real)0;
  332. U[3] = (Real)6;
  333. xMult = mInvXSpacing * mInvXSpacing * mInvXSpacing;
  334. break;
  335. default:
  336. return (Real)0;
  337. }
  338. std::array<Real, 4> V;
  339. Real dy, yMult;
  340. switch (yOrder)
  341. {
  342. case 0:
  343. dy = yIndex - iy;
  344. V[0] = (Real)1;
  345. V[1] = dy;
  346. V[2] = dy * V[1];
  347. V[3] = dy * V[2];
  348. yMult = (Real)1;
  349. break;
  350. case 1:
  351. dy = yIndex - iy;
  352. V[0] = (Real)0;
  353. V[1] = (Real)1;
  354. V[2] = (Real)2 * dy;
  355. V[3] = (Real)3 * dy * dy;
  356. yMult = mInvYSpacing;
  357. break;
  358. case 2:
  359. dy = yIndex - iy;
  360. V[0] = (Real)0;
  361. V[1] = (Real)0;
  362. V[2] = (Real)2;
  363. V[3] = (Real)6 * dy;
  364. yMult = mInvYSpacing * mInvYSpacing;
  365. break;
  366. case 3:
  367. V[0] = (Real)0;
  368. V[1] = (Real)0;
  369. V[2] = (Real)0;
  370. V[3] = (Real)6;
  371. yMult = mInvYSpacing * mInvYSpacing * mInvYSpacing;
  372. break;
  373. default:
  374. return (Real)0;
  375. }
  376. std::array<Real, 4> W;
  377. Real dz, zMult;
  378. switch (zOrder)
  379. {
  380. case 0:
  381. dz = zIndex - iz;
  382. W[0] = (Real)1;
  383. W[1] = dz;
  384. W[2] = dz * W[1];
  385. W[3] = dz * W[2];
  386. zMult = (Real)1;
  387. break;
  388. case 1:
  389. dz = zIndex - iz;
  390. W[0] = (Real)0;
  391. W[1] = (Real)1;
  392. W[2] = (Real)2 * dz;
  393. W[3] = (Real)3 * dz * dz;
  394. zMult = mInvZSpacing;
  395. break;
  396. case 2:
  397. dz = zIndex - iz;
  398. W[0] = (Real)0;
  399. W[1] = (Real)0;
  400. W[2] = (Real)2;
  401. W[3] = (Real)6 * dz;
  402. zMult = mInvZSpacing * mInvZSpacing;
  403. break;
  404. case 3:
  405. W[0] = (Real)0;
  406. W[1] = (Real)0;
  407. W[2] = (Real)0;
  408. W[3] = (Real)6;
  409. zMult = mInvZSpacing * mInvZSpacing * mInvZSpacing;
  410. break;
  411. default:
  412. return (Real)0;
  413. }
  414. // Compute P = M*U, Q = M*V, and R = M*W.
  415. std::array<Real, 4> P, Q, R;
  416. for (int row = 0; row < 4; ++row)
  417. {
  418. P[row] = (Real)0;
  419. Q[row] = (Real)0;
  420. R[row] = (Real)0;
  421. for (int col = 0; col < 4; ++col)
  422. {
  423. P[row] += mBlend[row][col] * U[col];
  424. Q[row] += mBlend[row][col] * V[col];
  425. R[row] += mBlend[row][col] * W[col];
  426. }
  427. }
  428. // Compute the tensor product (M*U)(M*V)(M*W)*D where D is the 4x4x4
  429. // subimage containing (x,y,z).
  430. --ix;
  431. --iy;
  432. --iz;
  433. Real result = (Real)0;
  434. for (int slice = 0; slice < 4; ++slice)
  435. {
  436. int zClamp = iz + slice;
  437. if (zClamp < 0)
  438. {
  439. zClamp = 0;
  440. }
  441. else if (zClamp > mZBound - 1)
  442. {
  443. zClamp = mZBound - 1;
  444. }
  445. for (int row = 0; row < 4; ++row)
  446. {
  447. int yClamp = iy + row;
  448. if (yClamp < 0)
  449. {
  450. yClamp = 0;
  451. }
  452. else if (yClamp > mYBound - 1)
  453. {
  454. yClamp = mYBound - 1;
  455. }
  456. for (int col = 0; col < 4; ++col)
  457. {
  458. int xClamp = ix + col;
  459. if (xClamp < 0)
  460. {
  461. xClamp = 0;
  462. }
  463. else if (xClamp > mXBound - 1)
  464. {
  465. xClamp = mXBound - 1;
  466. }
  467. result += P[col] * Q[row] * R[slice] *
  468. mF[xClamp + mXBound * (yClamp + mYBound * zClamp)];
  469. }
  470. }
  471. }
  472. result *= xMult * yMult * zMult;
  473. return result;
  474. }
  475. private:
  476. int mXBound, mYBound, mZBound, mQuantity;
  477. Real mXMin, mXMax, mXSpacing, mInvXSpacing;
  478. Real mYMin, mYMax, mYSpacing, mInvYSpacing;
  479. Real mZMin, mZMax, mZSpacing, mInvZSpacing;
  480. Real const* mF;
  481. std::array<std::array<Real, 4>, 4> mBlend;
  482. };
  483. }