IntpBicubic2.h 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395
  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)-values. The input samples
  11. // F must be stored in row-major order to represent f(x,y); that is,
  12. // F[c + xBound*r] corresponds to f(x,y), where c is the index corresponding
  13. // to x and r is the index corresponding to y. Exact interpolation is
  14. // achieved by setting catmullRom to 'true', giving you the Catmull-Rom
  15. // blending matrix. If a smooth interpolation is desired, set catmullRom to
  16. // 'false' to obtain B-spline blending.
  17. namespace WwiseGTE
  18. {
  19. template <typename Real>
  20. class IntpBicubic2
  21. {
  22. public:
  23. // Construction.
  24. IntpBicubic2(int xBound, int yBound, Real xMin, Real xSpacing,
  25. Real yMin, Real ySpacing, Real const* F, bool catmullRom)
  26. :
  27. mXBound(xBound),
  28. mYBound(yBound),
  29. mQuantity(xBound* yBound),
  30. mXMin(xMin),
  31. mXSpacing(xSpacing),
  32. mYMin(yMin),
  33. mYSpacing(ySpacing),
  34. mF(F)
  35. {
  36. // At least a 3x3 block of data points are needed to construct the
  37. // estimates of the boundary derivatives.
  38. LogAssert(mXBound >= 3 && mYBound >= 3 && mF != nullptr, "Invalid input.");
  39. LogAssert(mXSpacing > (Real)0 && mYSpacing > (Real)0, "Invalid input.");
  40. mXMax = mXMin + mXSpacing * static_cast<Real>(mXBound - 1);
  41. mInvXSpacing = (Real)1 / mXSpacing;
  42. mYMax = mYMin + mYSpacing * static_cast<Real>(mYBound - 1);
  43. mInvYSpacing = (Real)1 / mYSpacing;
  44. if (catmullRom)
  45. {
  46. mBlend[0][0] = (Real)0;
  47. mBlend[0][1] = (Real)-0.5;
  48. mBlend[0][2] = (Real)1;
  49. mBlend[0][3] = (Real)-0.5;
  50. mBlend[1][0] = (Real)1;
  51. mBlend[1][1] = (Real)0;
  52. mBlend[1][2] = (Real)-2.5;
  53. mBlend[1][3] = (Real)1.5;
  54. mBlend[2][0] = (Real)0;
  55. mBlend[2][1] = (Real)0.5;
  56. mBlend[2][2] = (Real)2;
  57. mBlend[2][3] = (Real)-1.5;
  58. mBlend[3][0] = (Real)0;
  59. mBlend[3][1] = (Real)0;
  60. mBlend[3][2] = (Real)-0.5;
  61. mBlend[3][3] = (Real)0.5;
  62. }
  63. else
  64. {
  65. mBlend[0][0] = (Real)1 / (Real)6;
  66. mBlend[0][1] = (Real)-3 / (Real)6;
  67. mBlend[0][2] = (Real)3 / (Real)6;
  68. mBlend[0][3] = (Real)-1 / (Real)6;;
  69. mBlend[1][0] = (Real)4 / (Real)6;
  70. mBlend[1][1] = (Real)0 / (Real)6;
  71. mBlend[1][2] = (Real)-6 / (Real)6;
  72. mBlend[1][3] = (Real)3 / (Real)6;
  73. mBlend[2][0] = (Real)1 / (Real)6;
  74. mBlend[2][1] = (Real)3 / (Real)6;
  75. mBlend[2][2] = (Real)3 / (Real)6;
  76. mBlend[2][3] = (Real)-3 / (Real)6;
  77. mBlend[3][0] = (Real)0 / (Real)6;
  78. mBlend[3][1] = (Real)0 / (Real)6;
  79. mBlend[3][2] = (Real)0 / (Real)6;
  80. mBlend[3][3] = (Real)1 / (Real)6;
  81. }
  82. }
  83. // Member access.
  84. inline int GetXBound() const
  85. {
  86. return mXBound;
  87. }
  88. inline int GetYBound() const
  89. {
  90. return mYBound;
  91. }
  92. inline int GetQuantity() const
  93. {
  94. return mQuantity;
  95. }
  96. inline Real const* GetF() const
  97. {
  98. return mF;
  99. }
  100. inline Real GetXMin() const
  101. {
  102. return mXMin;
  103. }
  104. inline Real GetXMax() const
  105. {
  106. return mXMax;
  107. }
  108. inline Real GetXSpacing() const
  109. {
  110. return mXSpacing;
  111. }
  112. inline Real GetYMin() const
  113. {
  114. return mYMin;
  115. }
  116. inline Real GetYMax() const
  117. {
  118. return mYMax;
  119. }
  120. inline Real GetYSpacing() const
  121. {
  122. return mYSpacing;
  123. }
  124. // Evaluate the function and its derivatives. The functions clamp the
  125. // inputs to xmin <= x <= xmax and ymin <= y <= ymax. The first
  126. // operator is for function evaluation. The second operator is for
  127. // function or derivative evaluations. The xOrder argument is the
  128. // order of the x-derivative and the yOrder argument is the order of
  129. // the y-derivative. Both orders are zero to get the function value
  130. // itself.
  131. Real operator()(Real x, Real y) const
  132. {
  133. // Compute x-index and clamp to image.
  134. Real xIndex = (x - mXMin) * mInvXSpacing;
  135. int ix = static_cast<int>(xIndex);
  136. if (ix < 0)
  137. {
  138. ix = 0;
  139. }
  140. else if (ix >= mXBound)
  141. {
  142. ix = mXBound - 1;
  143. }
  144. // Compute y-index and clamp to image.
  145. Real yIndex = (y - mYMin) * mInvYSpacing;
  146. int iy = static_cast<int>(yIndex);
  147. if (iy < 0)
  148. {
  149. iy = 0;
  150. }
  151. else if (iy >= mYBound)
  152. {
  153. iy = mYBound - 1;
  154. }
  155. std::array<Real, 4> U;
  156. U[0] = (Real)1;
  157. U[1] = xIndex - ix;
  158. U[2] = U[1] * U[1];
  159. U[3] = U[1] * U[2];
  160. std::array<Real, 4> V;
  161. V[0] = (Real)1;
  162. V[1] = yIndex - iy;
  163. V[2] = V[1] * V[1];
  164. V[3] = V[1] * V[2];
  165. // Compute P = M*U and Q = M*V.
  166. std::array<Real, 4> P, Q;
  167. for (int row = 0; row < 4; ++row)
  168. {
  169. P[row] = (Real)0;
  170. Q[row] = (Real)0;
  171. for (int col = 0; col < 4; ++col)
  172. {
  173. P[row] += mBlend[row][col] * U[col];
  174. Q[row] += mBlend[row][col] * V[col];
  175. }
  176. }
  177. // Compute (M*U)^t D (M*V) where D is the 4x4 subimage
  178. // containing (x,y).
  179. --ix;
  180. --iy;
  181. Real result = (Real)0;
  182. for (int row = 0; row < 4; ++row)
  183. {
  184. int yClamp = iy + row;
  185. if (yClamp < 0)
  186. {
  187. yClamp = 0;
  188. }
  189. else if (yClamp > mYBound - 1)
  190. {
  191. yClamp = mYBound - 1;
  192. }
  193. for (int col = 0; col < 4; ++col)
  194. {
  195. int xClamp = ix + col;
  196. if (xClamp < 0)
  197. {
  198. xClamp = 0;
  199. }
  200. else if (xClamp > mXBound - 1)
  201. {
  202. xClamp = mXBound - 1;
  203. }
  204. result += P[col] * Q[row] * mF[xClamp + mXBound * yClamp];
  205. }
  206. }
  207. return result;
  208. }
  209. Real operator()(int xOrder, int yOrder, Real x, Real y) const
  210. {
  211. // Compute x-index and clamp to image.
  212. Real xIndex = (x - mXMin) * mInvXSpacing;
  213. int ix = static_cast<int>(xIndex);
  214. if (ix < 0)
  215. {
  216. ix = 0;
  217. }
  218. else if (ix >= mXBound)
  219. {
  220. ix = mXBound - 1;
  221. }
  222. // Compute y-index and clamp to image.
  223. Real yIndex = (y - mYMin) * mInvYSpacing;
  224. int iy = static_cast<int>(yIndex);
  225. if (iy < 0)
  226. {
  227. iy = 0;
  228. }
  229. else if (iy >= mYBound)
  230. {
  231. iy = mYBound - 1;
  232. }
  233. std::array<Real, 4> U;
  234. Real dx, xMult;
  235. switch (xOrder)
  236. {
  237. case 0:
  238. dx = xIndex - ix;
  239. U[0] = (Real)1;
  240. U[1] = dx;
  241. U[2] = dx * U[1];
  242. U[3] = dx * U[2];
  243. xMult = (Real)1;
  244. break;
  245. case 1:
  246. dx = xIndex - ix;
  247. U[0] = (Real)0;
  248. U[1] = (Real)1;
  249. U[2] = (Real)2 * dx;
  250. U[3] = (Real)3 * dx * dx;
  251. xMult = mInvXSpacing;
  252. break;
  253. case 2:
  254. dx = xIndex - ix;
  255. U[0] = (Real)0;
  256. U[1] = (Real)0;
  257. U[2] = (Real)2;
  258. U[3] = (Real)6 * dx;
  259. xMult = mInvXSpacing * mInvXSpacing;
  260. break;
  261. case 3:
  262. U[0] = (Real)0;
  263. U[1] = (Real)0;
  264. U[2] = (Real)0;
  265. U[3] = (Real)6;
  266. xMult = mInvXSpacing * mInvXSpacing * mInvXSpacing;
  267. break;
  268. default:
  269. return (Real)0;
  270. }
  271. std::array<Real, 4> V;
  272. Real dy, yMult;
  273. switch (yOrder)
  274. {
  275. case 0:
  276. dy = yIndex - iy;
  277. V[0] = (Real)1;
  278. V[1] = dy;
  279. V[2] = dy * V[1];
  280. V[3] = dy * V[2];
  281. yMult = (Real)1;
  282. break;
  283. case 1:
  284. dy = yIndex - iy;
  285. V[0] = (Real)0;
  286. V[1] = (Real)1;
  287. V[2] = (Real)2 * dy;
  288. V[3] = (Real)3 * dy * dy;
  289. yMult = mInvYSpacing;
  290. break;
  291. case 2:
  292. dy = yIndex - iy;
  293. V[0] = (Real)0;
  294. V[1] = (Real)0;
  295. V[2] = (Real)2;
  296. V[3] = (Real)6 * dy;
  297. yMult = mInvYSpacing * mInvYSpacing;
  298. break;
  299. case 3:
  300. V[0] = (Real)0;
  301. V[1] = (Real)0;
  302. V[2] = (Real)0;
  303. V[3] = (Real)6;
  304. yMult = mInvYSpacing * mInvYSpacing * mInvYSpacing;
  305. break;
  306. default:
  307. return (Real)0;
  308. }
  309. // Compute P = M*U and Q = M*V.
  310. std::array<Real, 4> P, Q;
  311. for (int row = 0; row < 4; ++row)
  312. {
  313. P[row] = (Real)0;
  314. Q[row] = (Real)0;
  315. for (int col = 0; col < 4; ++col)
  316. {
  317. P[row] += mBlend[row][col] * U[col];
  318. Q[row] += mBlend[row][col] * V[col];
  319. }
  320. }
  321. // Compute (M*U)^t D (M*V) where D is the 4x4 subimage containing (x,y).
  322. --ix;
  323. --iy;
  324. Real result = (Real)0;
  325. for (int row = 0; row < 4; ++row)
  326. {
  327. int yClamp = iy + row;
  328. if (yClamp < 0)
  329. {
  330. yClamp = 0;
  331. }
  332. else if (yClamp > mYBound - 1)
  333. {
  334. yClamp = mYBound - 1;
  335. }
  336. for (int col = 0; col < 4; ++col)
  337. {
  338. int xClamp = ix + col;
  339. if (xClamp < 0)
  340. {
  341. xClamp = 0;
  342. }
  343. else if (xClamp > mXBound - 1)
  344. {
  345. xClamp = mXBound - 1;
  346. }
  347. result += P[col] * Q[row] * mF[xClamp + mXBound * yClamp];
  348. }
  349. }
  350. result *= xMult * yMult;
  351. return result;
  352. }
  353. private:
  354. int mXBound, mYBound, mQuantity;
  355. Real mXMin, mXMax, mXSpacing, mInvXSpacing;
  356. Real mYMin, mYMax, mYSpacing, mInvYSpacing;
  357. Real const* mF;
  358. std::array<std::array<Real, 4>, 4> mBlend;
  359. };
  360. }