IntpBSplineUniform.h 55 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440
  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 <Mathematics/Math.h>
  10. #include <Mathematics/Polynomial1.h>
  11. #include <array>
  12. // IntpBSplineUniform is the class for B-spline interpolation of uniformly
  13. // spaced N-dimensional data. The algorithm is described in
  14. // https://www.geometrictools.com/Documentation/BSplineInterpolation.pdf
  15. // A sample application for this topic is
  16. // GeometricTools/GTEngine/Samples/Imagics/BSplineInterpolation
  17. //
  18. // The Controls adapter allows access to your control points without regard
  19. // to how you organize your data. You can even defer the computation of a
  20. // control point until it is needed via the operator()(...) calls that
  21. // Controls must provide, and you can cache the points according to your own
  22. // needs. The minimal interface for a Controls adapter is
  23. //
  24. // struct Controls
  25. // {
  26. // // The control_point_type is of your choosing. It must support
  27. // // assignment, scalar multiplication and addition. Specifically, if
  28. // // C0, C1 and C2 are control points and s is a scalar, the interpolator
  29. // // needs to perform operations
  30. // // C1 = C0;
  31. // // C1 = C0 * s;
  32. // // C2 = C0 + C1;
  33. // typedef control_point_type Type;
  34. //
  35. // // The number of elements in the specified dimension.
  36. // int GetSize(int dimension) const;
  37. //
  38. // // Get a control point based on an n-tuple lookup. The interpolator
  39. // // does not need to know your organization; all it needs is the
  40. // // desired control point. The 'tuple' input must have n elements.
  41. // Type operator() (int const* tuple) const;
  42. //
  43. // // If you choose to use the specialized interpolators for dimensions
  44. // // 1, 2 or 3, you must also provide the following accessor, where
  45. // // the input is an n-tuple listed component-by-component (1, 2 or 3
  46. // // components).
  47. // Type operator() (int i0, int i1, ..., int inm1) const;
  48. // }
  49. namespace WwiseGTE
  50. {
  51. template <typename Real, typename Controls>
  52. class IntpBSplineUniformShared
  53. {
  54. protected:
  55. // Abstract base class construction. A virtual destructor is not
  56. // provided because there are no required side effects in the base
  57. // class when destroying objects from the derived classes.
  58. IntpBSplineUniformShared(int numDimensions, int const* degrees,
  59. Controls const& controls, typename Controls::Type ctZero, int cacheMode)
  60. :
  61. mNumDimensions(numDimensions),
  62. mDegree(numDimensions),
  63. mControls(&controls),
  64. mCTZero(ctZero),
  65. mCacheMode(cacheMode),
  66. mNumLocalControls(0),
  67. mDegreeP1(numDimensions),
  68. mNumControls(numDimensions),
  69. mTMin(numDimensions),
  70. mTMax(numDimensions),
  71. mBlender(numDimensions),
  72. mDCoefficient(numDimensions),
  73. mLMax(numDimensions),
  74. mPowerDSDT(numDimensions),
  75. mITuple(numDimensions),
  76. mJTuple(numDimensions),
  77. mKTuple(numDimensions),
  78. mLTuple(numDimensions),
  79. mSumIJTuple(numDimensions),
  80. mUTuple(numDimensions),
  81. mPTuple(numDimensions)
  82. {
  83. // The condition c+1 > d+1 is required so that when s = c+1-d, its
  84. // maximum value, we have at least two s-knots (d and d + 1).
  85. for (int dim = 0; dim < mNumDimensions; ++dim)
  86. {
  87. if (mControls->GetSize(dim) <= degrees[dim] + 1)
  88. {
  89. LogError("Incompatible degree and number of controls.");
  90. }
  91. }
  92. mNumLocalControls = 1;
  93. for (int dim = 0; dim < mNumDimensions; ++dim)
  94. {
  95. mDegree[dim] = degrees[dim];
  96. mDegreeP1[dim] = degrees[dim] + 1;
  97. mNumLocalControls *= mDegreeP1[dim];
  98. mNumControls[dim] = controls.GetSize(dim);
  99. mTMin[dim] = (Real)-0.5;
  100. mTMax[dim] = static_cast<Real>(mNumControls[dim]) - (Real)0.5;
  101. ComputeBlendingMatrix(mDegree[dim], mBlender[dim]);
  102. ComputeDCoefficients(mDegree[dim], mDCoefficient[dim], mLMax[dim]);
  103. ComputePowers(mDegree[dim], mNumControls[dim], mTMin[dim], mTMax[dim], mPowerDSDT[dim]);
  104. }
  105. if (mCacheMode == NO_CACHING)
  106. {
  107. mPhi.resize(mNumDimensions);
  108. for (int dim = 0; dim < mNumDimensions; ++dim)
  109. {
  110. mPhi[dim].resize(mDegreeP1[dim]);
  111. }
  112. }
  113. else
  114. {
  115. InitializeTensors();
  116. }
  117. }
  118. #if !defined(GTE_INTP_BSPLINE_UNIFORM_NO_SPECIALIZATION)
  119. IntpBSplineUniformShared()
  120. :
  121. mNumDimensions(0),
  122. mControls(nullptr),
  123. mCTZero(),
  124. mCacheMode(0),
  125. mNumLocalControls(0)
  126. {
  127. }
  128. #endif
  129. public:
  130. // Support for caching the intermediate tensor product of control
  131. // points with the blending matrices. A precached container has all
  132. // elements precomputed before any Evaluate(...) calls. The 'bool'
  133. // flags are all set to 'true'. A cached container fills the elements
  134. // on demand. The 'bool' flags are initially 'false', indicating the
  135. // EvalType component has not yet been computed. After it is computed
  136. // and stored, the flag is set to 'true'.
  137. enum
  138. {
  139. NO_CACHING,
  140. PRE_CACHING,
  141. ON_DEMAND_CACHING
  142. };
  143. // Member access.
  144. inline int GetDegree(int dim) const
  145. {
  146. return mDegree[dim];
  147. }
  148. inline int GetNumControls(int dim) const
  149. {
  150. return mNumControls[dim];
  151. }
  152. inline Real GetTMin(int dim) const
  153. {
  154. return mTMin[dim];
  155. }
  156. inline Real GetTMax(int dim) const
  157. {
  158. return mTMax[dim];
  159. }
  160. inline int GetCacheMode() const
  161. {
  162. return mCacheMode;
  163. }
  164. protected:
  165. // Disallow copying and moving.
  166. IntpBSplineUniformShared(IntpBSplineUniformShared const&) = delete;
  167. IntpBSplineUniformShared& operator=(IntpBSplineUniformShared const&) = delete;
  168. IntpBSplineUniformShared(IntpBSplineUniformShared&&) = delete;
  169. IntpBSplineUniformShared& operator=(IntpBSplineUniformShared&&) = delete;
  170. // ComputeBlendingMatrix, ComputeDCoefficients, ComputePowers and
  171. // GetKey are used by the general-dimension derived classes and by
  172. // the specializations for dimensions 1, 2 and 3.
  173. // Compute the blending matrix that combines the control points and
  174. // the polynomial vector. The matrix A is stored in row-major order.
  175. static void ComputeBlendingMatrix(int degree, std::vector<Real>& A)
  176. {
  177. int const degreeP1 = degree + 1;
  178. A.resize(degreeP1 * degreeP1);
  179. if (degree == 0)
  180. {
  181. A[0] = (Real)1;
  182. return;
  183. }
  184. // P_{0,0}(s)
  185. std::vector<Polynomial1<Real>> P(degreeP1);
  186. P[0][0] = (Real)1;
  187. // L0 = s/j
  188. Polynomial1<Real> L0(1);
  189. L0[0] = (Real)0;
  190. // L1(s) = (j + 1 - s)/j
  191. Polynomial1<Real> L1(1);
  192. // s-1 is used in computing translated P_{j-1,k-1}(s-1)
  193. Polynomial1<Real> sm1 = { (Real)-1, (Real)1 };
  194. // Compute
  195. // P_{j,k}(s) = L0(s)*P_{j-1,k}(s) + L1(s)*P_{j-1,k-1}(s-1)
  196. // for 0 <= k <= j where 1 <= j <= degree. When k = 0,
  197. // P_{j-1,-1}(s) = 0, so P_{j,0}(s) = L0(s)*P_{j-1,0}(s). When
  198. // k = j, P_{j-1,j}(s) = 0, so P_{j,j}(s) = L1(s)*P_{j-1,j-1}(s).
  199. // The polynomials at level j-1 are currently stored in P[0]
  200. // through P[j-1]. The polynomials at level j are computed and
  201. // stored in P[0] through P[j]; that is, they are computed in
  202. // place to reduce memory usage and copying. This requires
  203. // computing P[k] (level j) from P[k] (level j-1) and P[k-1]
  204. // (level j-1), which means we have to process k = j down to
  205. // k = 0.
  206. for (int j = 1; j <= degree; ++j)
  207. {
  208. Real invJ = (Real)1 / (Real)j;
  209. L0[1] = invJ;
  210. L1[0] = (Real)1 + invJ;
  211. L1[1] = -invJ;
  212. for (int k = j; k >= 0; --k)
  213. {
  214. Polynomial1<Real> result = { (Real)0 };
  215. if (k > 0)
  216. {
  217. result += L1 * P[k - 1].GetTranslation((Real)1);
  218. }
  219. if (k < j)
  220. {
  221. result += L0 * P[k];
  222. }
  223. P[k] = result;
  224. }
  225. }
  226. // Compute Q_{d,k}(s) = P_{d,k}(s + k).
  227. std::vector<Polynomial1<Real>> Q(degreeP1);
  228. for (int k = 0; k <= degree; ++k)
  229. {
  230. Q[k] = P[k].GetTranslation(static_cast<Real>(-k));
  231. }
  232. // Extract the matrix A from the Q-polynomials. Row r of A
  233. // contains the coefficients of Q_{d,d-r}(s).
  234. for (int k = 0, row = degree; k <= degree; ++k, --row)
  235. {
  236. for (int col = 0; col <= degree; ++col)
  237. {
  238. A[col + degreeP1 * row] = Q[k][col];
  239. }
  240. }
  241. }
  242. // Compute the coefficients for the derivative polynomial terms.
  243. static void ComputeDCoefficients(int degree, std::vector<Real>& dCoefficients,
  244. std::vector<int>& ellMax)
  245. {
  246. int numDCoefficients = (degree + 1) * (degree + 2) / 2;
  247. dCoefficients.resize(numDCoefficients);
  248. for (int i = 0; i < numDCoefficients; ++i)
  249. {
  250. dCoefficients[i] = 1;
  251. }
  252. for (int order = 1, col0 = 0, col1 = degree + 1; order <= degree; ++order)
  253. {
  254. ++col0;
  255. for (int c = order, m = 1; c <= degree; ++c, ++m, ++col0, ++col1)
  256. {
  257. dCoefficients[col1] = dCoefficients[col0] * m;
  258. }
  259. }
  260. ellMax.resize(degree + 1);
  261. ellMax[0] = degree;
  262. for (int i0 = 0, i1 = 1; i1 <= degree; i0 = i1++)
  263. {
  264. ellMax[i1] = ellMax[i0] + degree - i0;
  265. }
  266. }
  267. // Compute powers of ds/dt.
  268. void ComputePowers(int degree, int numControls, Real tmin, Real tmax,
  269. std::vector<Real>& powerDSDT)
  270. {
  271. Real dsdt = static_cast<Real>(numControls - degree) / (tmax - tmin);
  272. powerDSDT.resize(degree + 1);
  273. powerDSDT[0] = (Real)1;
  274. powerDSDT[1] = dsdt;
  275. for (int i = 2; i <= degree; ++i)
  276. {
  277. powerDSDT[i] = powerDSDT[i - 1] * dsdt;
  278. }
  279. }
  280. // Determine the interval [index,index+1) corresponding to the
  281. // specified value of t and compute u in that interval.
  282. static void GetKey(Real t, Real tmin, Real tmax, Real dsdt, int numControls,
  283. int degree, int& index, Real& u)
  284. {
  285. // Compute s - d = ((c + 1 - d)/(c + 1))(t + 1/2), the index for
  286. // which d + index <= s < d + index + 1. Let u = s - d - index so
  287. // that 0 <= u < 1.
  288. if (t > tmin)
  289. {
  290. if (t < tmax)
  291. {
  292. Real smd = dsdt * (t - tmin);
  293. index = static_cast<uint32_t>(std::floor(smd));
  294. u = smd - static_cast<float>(index);
  295. }
  296. else
  297. {
  298. // In the evaluation, s = c + 1 - d and i = c - d. This
  299. // causes s-d-i to be 1 in G_c(c+1-d). Effectively, the
  300. // selection of i extends the s-domain [d,c+1) to its
  301. // support [d,c+1].
  302. index = numControls - 1 - degree;
  303. u = (Real)1;
  304. }
  305. }
  306. else
  307. {
  308. index = 0;
  309. u = (Real)0;
  310. }
  311. }
  312. // The remaining functions are used only by the general-dimension
  313. // derived classes when caching is enabled.
  314. // For the multidimensional tensor Phi{iTuple, kTuple), compute the
  315. // portion of the 1-dimensional index that corresponds to iTuple.
  316. int GetRowIndex(std::vector<int> const& i) const
  317. {
  318. int rowIndex = i[mNumDimensions - 1];
  319. int j1 = 2 * mNumDimensions - 2;
  320. for (int j0 = mNumDimensions - 2; j0 >= 0; --j0, --j1)
  321. {
  322. rowIndex = mTBound[j1] * rowIndex + i[j0];
  323. }
  324. rowIndex = mTBound[j1] * rowIndex;
  325. return rowIndex;
  326. }
  327. // For the multidimensional tensor Phi{iTuple, kTuple), combine the
  328. // GetRowIndex(...) output with kTuple to produce the full
  329. // 1-dimensional index.
  330. int GetIndex(int rowIndex, std::vector<int> const& k) const
  331. {
  332. int index = rowIndex + k[mNumDimensions - 1];
  333. for (int j = mNumDimensions - 2; j >= 0; --j)
  334. {
  335. index = mTBound[j] * index + k[j];
  336. }
  337. return index;
  338. }
  339. // Compute Phi(iTuple, kTuple). The 'index' value is an already
  340. // computed 1-dimensional index for the tensor.
  341. void ComputeTensor(int const* i, int const* k, int index)
  342. {
  343. auto element = mCTZero;
  344. for (int dim = 0; dim < mNumDimensions; ++dim)
  345. {
  346. mComputeJTuple[dim] = 0;
  347. }
  348. for (int iterate = 0; iterate < mNumLocalControls; ++iterate)
  349. {
  350. Real blend(1);
  351. for (int dim = 0; dim < mNumDimensions; ++dim)
  352. {
  353. blend *= mBlender[dim][k[dim] + mDegreeP1[dim] * mComputeJTuple[dim]];
  354. mComputeSumIJTuple[dim] = i[dim] + mComputeJTuple[dim];
  355. }
  356. element = element + (*mControls)(mComputeSumIJTuple.data()) * blend;
  357. for (int dim = 0; dim < mNumDimensions; ++dim)
  358. {
  359. if (++mComputeJTuple[dim] < mDegreeP1[dim])
  360. {
  361. break;
  362. }
  363. mComputeJTuple[dim] = 0;
  364. }
  365. }
  366. mTensor[index] = element;
  367. }
  368. // Allocate the containers used for caching and fill in the tensor
  369. // for precaching when that mode is selected.
  370. void InitializeTensors()
  371. {
  372. mTBound.resize(2 * mNumDimensions);
  373. mComputeJTuple.resize(mNumDimensions);
  374. mComputeSumIJTuple.resize(mNumDimensions);
  375. mDegreeMinusOrder.resize(mNumDimensions);
  376. mTerm.resize(mNumDimensions);
  377. int current = 0;
  378. int numCached = 1;
  379. for (int dim = 0; dim < mNumDimensions; ++dim, ++current)
  380. {
  381. mTBound[current] = mDegreeP1[dim];
  382. numCached *= mTBound[current];
  383. }
  384. for (int dim = 0; dim < mNumDimensions; ++dim, ++current)
  385. {
  386. mTBound[current] = mNumControls[dim] - mDegree[dim];
  387. numCached *= mTBound[current];
  388. }
  389. mTensor.resize(numCached);
  390. mCached.resize(numCached);
  391. if (mCacheMode == PRE_CACHING)
  392. {
  393. std::vector<int> tuple(2 * mNumDimensions, 0);
  394. for (int index = 0; index < numCached; ++index)
  395. {
  396. ComputeTensor(&tuple[mNumDimensions], &tuple[0], index);
  397. for (int i = 0; i < 2 * mNumDimensions; ++i)
  398. {
  399. if (++tuple[i] < mTBound[i])
  400. {
  401. break;
  402. }
  403. tuple[i] = 0;
  404. }
  405. }
  406. std::fill(mCached.begin(), mCached.end(), true);
  407. }
  408. else
  409. {
  410. std::fill(mCached.begin(), mCached.end(), false);
  411. }
  412. }
  413. // Evaluate the interpolator. Each element of 'order' indicates the
  414. // order of the derivative you want to compute. For the function
  415. // value itself, pass in 'order' that has all 0 elements.
  416. typename Controls::Type EvaluateNoCaching(int const* order, Real const* t)
  417. {
  418. auto result = mCTZero;
  419. for (int dim = 0; dim < mNumDimensions; ++dim)
  420. {
  421. if (order[dim] < 0 || order[dim] > mDegree[dim])
  422. {
  423. return result;
  424. }
  425. }
  426. for (int dim = 0; dim < mNumDimensions; ++dim)
  427. {
  428. GetKey(t[dim], mTMin[dim], mTMax[dim], mPowerDSDT[dim][1],
  429. mNumControls[dim], mDegree[dim], mITuple[dim], mUTuple[dim]);
  430. }
  431. for (int dim = 0; dim < mNumDimensions; ++dim)
  432. {
  433. int jIndex = 0;
  434. for (int j = 0; j <= mDegree[dim]; ++j)
  435. {
  436. int kjIndex = mDegree[dim] + jIndex;
  437. int ell = mLMax[dim][order[dim]];
  438. mPhi[dim][j] = (Real)0;
  439. for (int k = mDegree[dim]; k >= order[dim]; --k)
  440. {
  441. mPhi[dim][j] = mPhi[dim][j] * mUTuple[dim] +
  442. mBlender[dim][kjIndex--] * mDCoefficient[dim][ell--];
  443. }
  444. jIndex += mDegreeP1[dim];
  445. }
  446. }
  447. for (int dim = 0; dim < mNumDimensions; ++dim)
  448. {
  449. mJTuple[dim] = 0;
  450. mSumIJTuple[dim] = mITuple[dim];
  451. mPTuple[dim] = mPhi[dim][0];
  452. }
  453. for (int iterate = 0; iterate < mNumLocalControls; ++iterate)
  454. {
  455. Real product(1);
  456. for (int dim = 0; dim < mNumDimensions; ++dim)
  457. {
  458. product *= mPTuple[dim];
  459. }
  460. result = result + (*mControls)(mSumIJTuple.data()) * product;
  461. for (int dim = 0; dim < mNumDimensions; ++dim)
  462. {
  463. if (++mJTuple[dim] <= mDegree[dim])
  464. {
  465. mSumIJTuple[dim] = mITuple[dim] + mJTuple[dim];
  466. mPTuple[dim] = mPhi[dim][mJTuple[dim]];
  467. break;
  468. }
  469. mJTuple[dim] = 0;
  470. mSumIJTuple[dim] = mITuple[dim];
  471. mPTuple[dim] = mPhi[dim][0];
  472. }
  473. }
  474. Real adjust(1);
  475. for (int dim = 0; dim < mNumDimensions; ++dim)
  476. {
  477. adjust *= mPowerDSDT[dim][order[dim]];
  478. }
  479. result = result * adjust;
  480. return result;
  481. }
  482. typename Controls::Type EvaluateCaching(int const* order, Real const* t)
  483. {
  484. int numIterates = 1;
  485. for (int dim = 0; dim < mNumDimensions; ++dim)
  486. {
  487. mDegreeMinusOrder[dim] = mDegree[dim] - order[dim];
  488. if (mDegreeMinusOrder[dim] < 0 || mDegreeMinusOrder[dim] > mDegree[dim])
  489. {
  490. return mCTZero;
  491. }
  492. numIterates *= mDegreeMinusOrder[dim] + 1;
  493. }
  494. for (int dim = 0; dim < mNumDimensions; ++dim)
  495. {
  496. GetKey(t[dim], mTMin[dim], mTMax[dim], mPowerDSDT[dim][1],
  497. mNumControls[dim], mDegree[dim], mITuple[dim], mUTuple[dim]);
  498. }
  499. int rowIndex = GetRowIndex(mITuple);
  500. for (int dim = 0; dim < mNumDimensions; ++dim)
  501. {
  502. mJTuple[dim] = 0;
  503. mKTuple[dim] = mDegree[dim];
  504. mLTuple[dim] = mLMax[dim][order[dim]];
  505. mTerm[dim] = mCTZero;
  506. }
  507. for (int iterate = 0; iterate < numIterates; ++iterate)
  508. {
  509. int index = GetIndex(rowIndex, mKTuple);
  510. if (mCacheMode == ON_DEMAND_CACHING && !mCached[index])
  511. {
  512. ComputeTensor(mITuple.data(), mKTuple.data(), index);
  513. mCached[index] = true;
  514. }
  515. mTerm[0] = mTerm[0] * mUTuple[0] + mTensor[index] * mDCoefficient[0][mLTuple[0]];
  516. for (int dim = 0; dim < mNumDimensions; ++dim)
  517. {
  518. if (++mJTuple[dim] <= mDegreeMinusOrder[dim])
  519. {
  520. --mKTuple[dim];
  521. --mLTuple[dim];
  522. break;
  523. }
  524. int dimp1 = dim + 1;
  525. if (dimp1 < mNumDimensions)
  526. {
  527. mTerm[dimp1] = mTerm[dimp1] * mUTuple[dimp1] + mTerm[dim] * mDCoefficient[dimp1][mLTuple[dimp1]];
  528. mTerm[dim] = mCTZero;
  529. mJTuple[dim] = 0;
  530. mKTuple[dim] = mDegree[dim];
  531. mLTuple[dim] = mLMax[dim][order[dim]];
  532. }
  533. }
  534. }
  535. auto result = mTerm[mNumDimensions - 1];
  536. Real adjust(1);
  537. for (int dim = 0; dim < mNumDimensions; ++dim)
  538. {
  539. adjust *= mPowerDSDT[dim][order[dim]];
  540. }
  541. result = result * adjust;
  542. return result;
  543. }
  544. // Constructor inputs.
  545. int const mNumDimensions; // N
  546. std::vector<int> mDegree; // degree[N]
  547. Controls const* mControls;
  548. typename Controls::Type const mCTZero;
  549. int const mCacheMode;
  550. // Parameters for B-spline evaluation. All std::vector containers
  551. // have N elements.
  552. int mNumLocalControls; // product of (degree[]+1)
  553. std::vector<int> mDegreeP1;
  554. std::vector<int> mNumControls;
  555. std::vector<Real> mTMin;
  556. std::vector<Real> mTMax;
  557. std::vector<std::vector<Real>> mBlender;
  558. std::vector<std::vector<Real>> mDCoefficient;
  559. std::vector<std::vector<int>> mLMax;
  560. std::vector<std::vector<Real>> mPowerDSDT;
  561. std::vector<int> mITuple;
  562. std::vector<int> mJTuple;
  563. std::vector<int> mKTuple;
  564. std::vector<int> mLTuple;
  565. std::vector<int> mSumIJTuple;
  566. std::vector<Real> mUTuple;
  567. std::vector<Real> mPTuple;
  568. // Support for no-cached B-spline evaluation. The std::vector
  569. // container has N elements.
  570. std::vector<std::vector<Real>> mPhi;
  571. // Support for cached B-spline evaluation.
  572. std::vector<int> mTBound; // tbound[2*N]
  573. std::vector<int> mComputeJTuple; // computejtuple[N]
  574. std::vector<int> mComputeSumIJTuple; // computesumijtuple[N]
  575. std::vector<int> mDegreeMinusOrder; // degreeminusorder[N]
  576. std::vector<typename Controls::Type> mTerm; // mTerm[N]
  577. std::vector<typename Controls::Type> mTensor; // depends on numcontrols
  578. std::vector<bool> mCached; // same size as mTensor
  579. };
  580. }
  581. // Implementation for B-spline interpolation whose dimension is known at
  582. // compile time.
  583. namespace WwiseGTE
  584. {
  585. template <typename Real, typename Controls, int N = 0>
  586. class IntpBSplineUniform : public IntpBSplineUniformShared<Real, Controls>
  587. {
  588. public:
  589. // The caller is responsible for ensuring that the IntpBSplineUniform
  590. // object persists as long as the input 'controls' exists.
  591. IntpBSplineUniform(std::array<int, N> const& degrees, Controls const& controls,
  592. typename Controls::Type ctZero, int cacheMode)
  593. :
  594. IntpBSplineUniformShared<Real, Controls>(N, degrees.data(), controls,
  595. ctZero, cacheMode)
  596. {
  597. }
  598. // Disallow copying and moving.
  599. IntpBSplineUniform(IntpBSplineUniform const&) = delete;
  600. IntpBSplineUniform& operator=(IntpBSplineUniform const&) = delete;
  601. IntpBSplineUniform(IntpBSplineUniform&&) = delete;
  602. IntpBSplineUniform& operator=(IntpBSplineUniform&&) = delete;
  603. // Evaluate the interpolator. Each element of 'order' indicates the
  604. // order of the derivative you want to compute. For the function
  605. // value itself, pass in 'order' that has all 0 elements.
  606. typename Controls::Type Evaluate(std::array<int, N> const& order,
  607. std::array<Real, N> const& t)
  608. {
  609. if (this->mCacheMode == this->NO_CACHING)
  610. {
  611. return this->EvaluateNoCaching(order.data(), t.data());
  612. }
  613. else
  614. {
  615. return this->EvaluateCaching(order.data(), t.data());
  616. }
  617. }
  618. };
  619. }
  620. // Implementation for B-spline interpolation whose dimension is known only
  621. // at run time.
  622. namespace WwiseGTE
  623. {
  624. template <typename Real, typename Controls>
  625. class IntpBSplineUniform<Real, Controls, 0> : public IntpBSplineUniformShared<Real, Controls>
  626. {
  627. public:
  628. // The caller is responsible for ensuring that the IntpBSplineUniform
  629. // object persists as long as the input 'controls' exists.
  630. IntpBSplineUniform(std::vector<int> const& degrees, Controls const& controls,
  631. typename Controls::Type ctZero, int cacheMode)
  632. :
  633. IntpBSplineUniformShared<Real, Controls>(static_cast<int>(degrees.size()),
  634. degrees.data(), controls, ctZero, cacheMode)
  635. {
  636. }
  637. // Disallow copying and moving.
  638. IntpBSplineUniform(IntpBSplineUniform const&) = delete;
  639. IntpBSplineUniform& operator=(IntpBSplineUniform const&) = delete;
  640. IntpBSplineUniform(IntpBSplineUniform&&) = delete;
  641. IntpBSplineUniform& operator=(IntpBSplineUniform&&) = delete;
  642. // Evaluate the interpolator. Each element of 'order' indicates the
  643. // order of the derivative you want to compute. For the function
  644. // value itself, pass in 'order' that has all 0 elements.
  645. typename Controls::Type Evaluate(std::vector<int> const& order,
  646. std::vector<Real> const& t)
  647. {
  648. if (static_cast<int>(order.size()) >= this->mNumDimensions
  649. && static_cast<int>(t.size()) >= this->mNumDimensions)
  650. {
  651. if (this->mCacheMode == this->NO_CACHING)
  652. {
  653. return this->EvaluateNoCaching(order.data(), t.data());
  654. }
  655. else
  656. {
  657. return this->EvaluateCaching(order.data(), t.data());
  658. }
  659. }
  660. else
  661. {
  662. return this->mCTZero;
  663. }
  664. }
  665. };
  666. }
  667. // To use only the N-dimensional template code above, define the symbol
  668. // GTE_INTP_BSPLINE_UNIFORM_NO_SPECIALIZATION to disable the specializations
  669. // that occur below. Notice that the interfaces are different between the
  670. // specializations and the general code.
  671. #if !defined(GTE_INTP_BSPLINE_UNIFORM_NO_SPECIALIZATION)
  672. // Specialization for 1-dimensional data.
  673. namespace WwiseGTE
  674. {
  675. template <typename Real, typename Controls>
  676. class IntpBSplineUniform<Real, Controls, 1> : public IntpBSplineUniformShared<Real, Controls>
  677. {
  678. public:
  679. // The caller is responsible for ensuring that the IntpBSplineUniform
  680. // object persists as long as the input 'controls' exists.
  681. IntpBSplineUniform(int degree, Controls const& controls,
  682. typename Controls::Type ctZero, int cacheMode)
  683. :
  684. IntpBSplineUniformShared<Real, Controls>(),
  685. mDegree(degree),
  686. mControls(&controls),
  687. mCTZero(ctZero),
  688. mCacheMode(cacheMode)
  689. {
  690. // The condition c+1 > d+1 is required so that when s = c+1-d, its
  691. // maximum value, we have at least two s-knots (d and d + 1).
  692. if (mControls->GetSize(0) <= mDegree + 1)
  693. {
  694. LogError("Incompatible degree and number of controls.");
  695. }
  696. mDegreeP1 = mDegree + 1;
  697. mNumControls = mControls->GetSize(0);
  698. mTMin = (Real)-0.5;
  699. mTMax = static_cast<Real>(mNumControls) - (Real)0.5;
  700. mNumTRows = 0;
  701. mNumTCols = 0;
  702. this->ComputeBlendingMatrix(mDegree, mBlender);
  703. this->ComputeDCoefficients(mDegree, mDCoefficient, mLMax);
  704. this->ComputePowers(mDegree, mNumControls, mTMin, mTMax, mPowerDSDT);
  705. if (mCacheMode == this->NO_CACHING)
  706. {
  707. mPhi.resize(mDegreeP1);
  708. }
  709. else
  710. {
  711. InitializeTensors();
  712. }
  713. }
  714. // Disallow copying and moving.
  715. IntpBSplineUniform(IntpBSplineUniform const&) = delete;
  716. IntpBSplineUniform& operator=(IntpBSplineUniform const&) = delete;
  717. IntpBSplineUniform(IntpBSplineUniform&&) = delete;
  718. IntpBSplineUniform& operator=(IntpBSplineUniform&&) = delete;
  719. // Member access.
  720. inline int GetDegree(int) const
  721. {
  722. return mDegree;
  723. }
  724. inline int GetNumControls(int) const
  725. {
  726. return mNumControls;
  727. }
  728. inline Real GetTMin(int) const
  729. {
  730. return mTMin;
  731. }
  732. inline Real GetTMax(int) const
  733. {
  734. return mTMax;
  735. }
  736. inline int GetCacheMode() const
  737. {
  738. return mCacheMode;
  739. }
  740. // Evaluate the interpolator. The order is 0 when you want the B-spline
  741. // function value itself. The order is 1 for the first derivative of the
  742. // function, and so on.
  743. typename Controls::Type Evaluate(std::array<int, 1> const& order,
  744. std::array<Real,1> const& t)
  745. {
  746. auto result = mCTZero;
  747. if (0 <= order[0] && order[0] <= mDegree)
  748. {
  749. int i;
  750. Real u;
  751. this->GetKey(t[0], mTMin, mTMax, mPowerDSDT[1], mNumControls, mDegree, i, u);
  752. if (mCacheMode == this->NO_CACHING)
  753. {
  754. int jIndex = 0;
  755. for (int j = 0; j <= mDegree; ++j)
  756. {
  757. int kjIndex = mDegree + jIndex;
  758. int ell = mLMax[order[0]];
  759. mPhi[j] = (Real)0;
  760. for (int k = mDegree; k >= order[0]; --k)
  761. {
  762. mPhi[j] = mPhi[j] * u + mBlender[kjIndex--] * mDCoefficient[ell--];
  763. }
  764. jIndex += mDegreeP1;
  765. }
  766. for (int j = 0; j <= mDegree; ++j)
  767. {
  768. result = result + (*mControls)(i + j) * mPhi[j];
  769. }
  770. }
  771. else
  772. {
  773. int iIndex = mNumTCols * i;
  774. int kiIndex = mDegree + iIndex;
  775. int ell = mLMax[order[0]];
  776. for (int k = mDegree; k >= order[0]; --k)
  777. {
  778. if (mCacheMode == this->ON_DEMAND_CACHING && !mCached[kiIndex])
  779. {
  780. ComputeTensor(i, k, kiIndex);
  781. mCached[kiIndex] = true;
  782. }
  783. result = result * u + mTensor[kiIndex--] * mDCoefficient[ell--];
  784. }
  785. }
  786. result = result * mPowerDSDT[order[0]];
  787. }
  788. return result;
  789. }
  790. protected:
  791. void ComputeTensor(int r, int c, int index)
  792. {
  793. auto element = mCTZero;
  794. for (int j = 0; j <= mDegree; ++j)
  795. {
  796. element = element + (*mControls)(r + j) * mBlender[c + mDegreeP1 * j];
  797. }
  798. mTensor[index] = element;
  799. }
  800. void InitializeTensors()
  801. {
  802. mNumTRows = mNumControls - mDegree;
  803. mNumTCols = mDegreeP1;
  804. int numCached = mNumTRows * mNumTCols;
  805. mTensor.resize(numCached);
  806. mCached.resize(numCached);
  807. if (mCacheMode == this->PRE_CACHING)
  808. {
  809. for (int r = 0, index = 0; r < mNumTRows; ++r)
  810. {
  811. for (int c = 0; c < mNumTCols; ++c, ++index)
  812. {
  813. ComputeTensor(r, c, index);
  814. }
  815. }
  816. std::fill(mCached.begin(), mCached.end(), true);
  817. }
  818. else
  819. {
  820. std::fill(mCached.begin(), mCached.end(), false);
  821. }
  822. }
  823. // Constructor inputs.
  824. int mDegree;
  825. Controls const* mControls;
  826. typename Controls::Type mCTZero;
  827. int mCacheMode;
  828. // Parameters for B-spline evaluation.
  829. int mDegreeP1;
  830. int mNumControls;
  831. Real mTMin, mTMax;
  832. std::vector<Real> mBlender;
  833. std::vector<Real> mDCoefficient;
  834. std::vector<int> mLMax;
  835. std::vector<Real> mPowerDSDT;
  836. // Support for no-cached B-spline evaluation.
  837. std::vector<Real> mPhi;
  838. // Support for cached B-spline evaluation.
  839. int mNumTRows, mNumTCols;
  840. std::vector<typename Controls::Type> mTensor;
  841. std::vector<bool> mCached;
  842. };
  843. }
  844. // Specialization for 2-dimensional data.
  845. namespace WwiseGTE
  846. {
  847. template <typename Real, typename Controls>
  848. class IntpBSplineUniform<Real, Controls, 2> : public IntpBSplineUniformShared<Real, Controls>
  849. {
  850. public:
  851. // The caller is responsible for ensuring that the IntpBSplineUniform2
  852. // object persists as long as the input 'controls' exists.
  853. IntpBSplineUniform(std::array<int, 2> const& degrees, Controls const& controls,
  854. typename Controls::Type ctZero, int cacheMode)
  855. :
  856. IntpBSplineUniformShared<Real, Controls>(),
  857. mDegree(degrees),
  858. mControls(&controls),
  859. mCTZero(ctZero),
  860. mCacheMode(cacheMode)
  861. {
  862. // The condition c+1 > d+1 is required so that when s = c+1-d, its
  863. // maximum value, we have at least two s-knots (d and d + 1).
  864. for (int dim = 0; dim < 2; ++dim)
  865. {
  866. if (mControls->GetSize(dim) <= mDegree[dim] + 1)
  867. {
  868. LogError("Incompatible degree and number of controls.");
  869. }
  870. }
  871. for (int dim = 0; dim < 2; ++dim)
  872. {
  873. mDegreeP1[dim] = mDegree[dim] + 1;
  874. mNumControls[dim] = mControls->GetSize(dim);
  875. mTMin[dim] = (Real)-0.5;
  876. mTMax[dim] = static_cast<Real>(mNumControls[dim]) - (Real)0.5;
  877. mNumTRows[dim] = 0;
  878. mNumTCols[dim] = 0;
  879. this->ComputeBlendingMatrix(mDegree[dim], mBlender[dim]);
  880. this->ComputeDCoefficients(mDegree[dim], mDCoefficient[dim], mLMax[dim]);
  881. this->ComputePowers(mDegree[dim], mNumControls[dim], mTMin[dim], mTMax[dim], mPowerDSDT[dim]);
  882. }
  883. if (mCacheMode == this->NO_CACHING)
  884. {
  885. for (int dim = 0; dim < 2; ++dim)
  886. {
  887. mPhi[dim].resize(mDegreeP1[dim]);
  888. }
  889. }
  890. else
  891. {
  892. InitializeTensors();
  893. }
  894. }
  895. // Disallow copying and moving.
  896. IntpBSplineUniform(IntpBSplineUniform const&) = delete;
  897. IntpBSplineUniform& operator=(IntpBSplineUniform const&) = delete;
  898. IntpBSplineUniform(IntpBSplineUniform&&) = delete;
  899. IntpBSplineUniform& operator=(IntpBSplineUniform&&) = delete;
  900. // Member access.
  901. inline int GetDegree(int dim) const
  902. {
  903. return mDegree[dim];
  904. }
  905. inline int GetNumControls(int dim) const
  906. {
  907. return mNumControls[dim];
  908. }
  909. inline Real GetTMin(int dim) const
  910. {
  911. return mTMin[dim];
  912. }
  913. inline Real GetTMax(int dim) const
  914. {
  915. return mTMax[dim];
  916. }
  917. inline int GetCacheMode() const
  918. {
  919. return mCacheMode;
  920. }
  921. // Evaluate the interpolator. The order is (0,0) when you want the
  922. // B-spline function value itself. The order0 is 1 for the first
  923. // derivative with respect to t0 and the order1 is 1 for the first
  924. // derivative with respect to t1. Higher-order derivatives in other
  925. // t-inputs are computed similarly.
  926. typename Controls::Type Evaluate(std::array<int, 2> const& order,
  927. std::array<Real, 2> const& t)
  928. {
  929. auto result = mCTZero;
  930. if (0 <= order[0] && order[0] <= mDegree[0]
  931. && 0 <= order[1] && order[1] <= mDegree[1])
  932. {
  933. std::array<int, 2> i;
  934. std::array<Real, 2> u;
  935. for (int dim = 0; dim < 2; ++dim)
  936. {
  937. this->GetKey(t[dim], mTMin[dim], mTMax[dim], mPowerDSDT[dim][1],
  938. mNumControls[dim], mDegree[dim], i[dim], u[dim]);
  939. }
  940. if (mCacheMode == this->NO_CACHING)
  941. {
  942. for (int dim = 0; dim < 2; ++dim)
  943. {
  944. int jIndex = 0;
  945. for (int j = 0; j <= mDegree[dim]; ++j)
  946. {
  947. int kjIndex = mDegree[dim] + jIndex;
  948. int ell = mLMax[dim][order[dim]];
  949. mPhi[dim][j] = (Real)0;
  950. for (int k = mDegree[dim]; k >= order[dim]; --k)
  951. {
  952. mPhi[dim][j] = mPhi[dim][j] * u[dim] +
  953. mBlender[dim][kjIndex--] * mDCoefficient[dim][ell--];
  954. }
  955. jIndex += mDegreeP1[dim];
  956. }
  957. }
  958. for (int j1 = 0; j1 <= mDegree[1]; ++j1)
  959. {
  960. Real phi1 = mPhi[1][j1];
  961. for (int j0 = 0; j0 <= mDegree[0]; ++j0)
  962. {
  963. Real phi0 = mPhi[0][j0];
  964. Real phi01 = phi0 * phi1;
  965. result = result + (*mControls)(i[0] + j0, i[1] + j1) * phi01;
  966. }
  967. }
  968. }
  969. else
  970. {
  971. int i0i1Index = mNumTCols[1] * (i[0] + mNumTRows[0] * i[1]);
  972. int k1i0i1Index = mDegree[1] + i0i1Index;
  973. int ell1 = mLMax[1][order[1]];
  974. for (int k1 = mDegree[1]; k1 >= order[1]; --k1)
  975. {
  976. int k0k1i0i1Index = mDegree[0] + mNumTCols[0] * k1i0i1Index;
  977. int ell0 = mLMax[0][order[0]];
  978. auto term = mCTZero;
  979. for (int k0 = mDegree[0]; k0 >= order[0]; --k0)
  980. {
  981. if (mCacheMode == this->ON_DEMAND_CACHING && !mCached[k0k1i0i1Index])
  982. {
  983. ComputeTensor(i[0], i[1], k0, k1, k0k1i0i1Index);
  984. mCached[k0k1i0i1Index] = true;
  985. }
  986. term = term * u[0] + mTensor[k0k1i0i1Index--] * mDCoefficient[0][ell0--];
  987. }
  988. result = result * u[1] + term * mDCoefficient[1][ell1--];
  989. --k1i0i1Index;
  990. }
  991. }
  992. Real adjust(1);
  993. for (int dim = 0; dim < 2; ++dim)
  994. {
  995. adjust *= mPowerDSDT[dim][order[dim]];
  996. }
  997. result = result * adjust;
  998. }
  999. return result;
  1000. }
  1001. void ComputeTensor(int r0, int r1, int c0, int c1, int index)
  1002. {
  1003. auto element = mCTZero;
  1004. for (int j1 = 0; j1 <= mDegree[1]; ++j1)
  1005. {
  1006. Real blend1 = mBlender[1][c1 + mDegreeP1[1] * j1];
  1007. for (int j0 = 0; j0 <= mDegree[0]; ++j0)
  1008. {
  1009. Real blend0 = mBlender[0][c0 + mDegreeP1[0] * j0];
  1010. Real blend01 = blend0 * blend1;
  1011. element = element + (*mControls)(r0 + j0, r1 + j1) * blend01;
  1012. }
  1013. }
  1014. mTensor[index] = element;
  1015. }
  1016. void InitializeTensors()
  1017. {
  1018. int numCached = 1;
  1019. for (int dim = 0; dim < 2; ++dim)
  1020. {
  1021. mNumTRows[dim] = mNumControls[dim] - mDegree[dim];
  1022. mNumTCols[dim] = mDegreeP1[dim];
  1023. numCached *= mNumTRows[dim] * mNumTCols[dim];
  1024. }
  1025. mTensor.resize(numCached);
  1026. mCached.resize(numCached);
  1027. if (mCacheMode == this->PRE_CACHING)
  1028. {
  1029. for (int r1 = 0, index = 0; r1 < mNumTRows[1]; ++r1)
  1030. {
  1031. for (int r0 = 0; r0 < mNumTRows[0]; ++r0)
  1032. {
  1033. for (int c1 = 0; c1 < mNumTCols[1]; ++c1)
  1034. {
  1035. for (int c0 = 0; c0 < mNumTCols[0]; ++c0, ++index)
  1036. {
  1037. ComputeTensor(r0, r1, c0, c1, index);
  1038. }
  1039. }
  1040. }
  1041. }
  1042. std::fill(mCached.begin(), mCached.end(), true);
  1043. }
  1044. else
  1045. {
  1046. std::fill(mCached.begin(), mCached.end(), false);
  1047. }
  1048. }
  1049. // Constructor inputs.
  1050. std::array<int, 2> mDegree;
  1051. Controls const* mControls;
  1052. typename Controls::Type mCTZero;
  1053. int mCacheMode;
  1054. // Parameters for B-spline evaluation.
  1055. std::array<int, 2> mDegreeP1;
  1056. std::array<int, 2> mNumControls;
  1057. std::array<Real, 2> mTMin, mTMax;
  1058. std::array<std::vector<Real>, 2> mBlender;
  1059. std::array<std::vector<Real>, 2> mDCoefficient;
  1060. std::array<std::vector<int>, 2> mLMax;
  1061. std::array<std::vector<Real>, 2> mPowerDSDT;
  1062. // Support for no-cached B-spline evaluation.
  1063. std::array<std::vector<Real>, 2> mPhi;
  1064. // Support for cached B-spline evaluation.
  1065. std::array<int, 2> mNumTRows, mNumTCols;
  1066. std::vector<typename Controls::Type> mTensor;
  1067. std::vector<bool> mCached;
  1068. };
  1069. }
  1070. // Specialization for 3-dimensional data.
  1071. namespace WwiseGTE
  1072. {
  1073. template <typename Real, typename Controls>
  1074. class IntpBSplineUniform<Real, Controls, 3> : public IntpBSplineUniformShared<Real, Controls>
  1075. {
  1076. public:
  1077. // The caller is responsible for ensuring that the IntpBSplineUniform3
  1078. // object persists as long as the input 'controls' exists.
  1079. IntpBSplineUniform(std::array<int, 3> const& degrees, Controls const& controls,
  1080. typename Controls::Type ctZero, int cacheMode)
  1081. :
  1082. IntpBSplineUniformShared<Real, Controls>(),
  1083. mDegree(degrees),
  1084. mControls(&controls),
  1085. mCTZero(ctZero),
  1086. mCacheMode(cacheMode)
  1087. {
  1088. // The condition c+1 > d+1 is required so that when s = c+1-d, its
  1089. // maximum value, we have at least two s-knots (d and d + 1).
  1090. for (int dim = 0; dim < 3; ++dim)
  1091. {
  1092. if (mControls->GetSize(dim) <= mDegree[dim] + 1)
  1093. {
  1094. LogError("Incompatible degree and number of controls.");
  1095. }
  1096. }
  1097. for (int dim = 0; dim < 3; ++dim)
  1098. {
  1099. mDegreeP1[dim] = mDegree[dim] + 1;
  1100. mNumControls[dim] = mControls->GetSize(dim);
  1101. mTMin[dim] = (Real)-0.5;
  1102. mTMax[dim] = static_cast<Real>(mNumControls[dim]) - (Real)0.5;
  1103. mNumTRows[dim] = 0;
  1104. mNumTCols[dim] = 0;
  1105. this->ComputeBlendingMatrix(mDegree[dim], mBlender[dim]);
  1106. this->ComputeDCoefficients(mDegree[dim], mDCoefficient[dim], mLMax[dim]);
  1107. this->ComputePowers(mDegree[dim], mNumControls[dim], mTMin[dim], mTMax[dim], mPowerDSDT[dim]);
  1108. }
  1109. if (mCacheMode == this->NO_CACHING)
  1110. {
  1111. for (int dim = 0; dim < 3; ++dim)
  1112. {
  1113. mPhi[dim].resize(mDegreeP1[dim]);
  1114. }
  1115. }
  1116. else
  1117. {
  1118. InitializeTensors();
  1119. }
  1120. }
  1121. // Disallow copying and moving.
  1122. IntpBSplineUniform(IntpBSplineUniform const&) = delete;
  1123. IntpBSplineUniform& operator=(IntpBSplineUniform const&) = delete;
  1124. IntpBSplineUniform(IntpBSplineUniform&&) = delete;
  1125. IntpBSplineUniform& operator=(IntpBSplineUniform&&) = delete;
  1126. // Member access. The input i specifies the dimension (0, 1, 2).
  1127. inline int GetDegree(int dim) const
  1128. {
  1129. return mDegree[dim];
  1130. }
  1131. inline int GetNumControls(int dim) const
  1132. {
  1133. return mNumControls[dim];
  1134. }
  1135. inline Real GetTMin(int dim) const
  1136. {
  1137. return mTMin[dim];
  1138. }
  1139. inline Real GetTMax(int dim) const
  1140. {
  1141. return mTMax[dim];
  1142. }
  1143. // Evaluate the interpolator. The order is (0,0,0) when you want the
  1144. // B-spline function value itself. The order0 is 1 for the first
  1145. // derivative with respect to t0, the order1 is 1 for the first
  1146. // derivative with respect to t1 or the order2 is 1 for the first
  1147. // derivative with respect to t2. Higher-order derivatives in other
  1148. // t-inputs are computed similarly.
  1149. typename Controls::Type Evaluate(std::array<int, 3> const& order,
  1150. std::array<Real, 3> const& t)
  1151. {
  1152. auto result = mCTZero;
  1153. if (0 <= order[0] && order[0] <= mDegree[0]
  1154. && 0 <= order[1] && order[1] <= mDegree[1]
  1155. && 0 <= order[2] && order[2] <= mDegree[2])
  1156. {
  1157. std::array<int, 3> i;
  1158. std::array<Real, 3> u;
  1159. for (int dim = 0; dim < 3; ++dim)
  1160. {
  1161. this->GetKey(t[dim], mTMin[dim], mTMax[dim], mPowerDSDT[dim][1],
  1162. mNumControls[dim], mDegree[dim], i[dim], u[dim]);
  1163. }
  1164. if (mCacheMode == this->NO_CACHING)
  1165. {
  1166. for (int dim = 0; dim < 3; ++dim)
  1167. {
  1168. int jIndex = 0;
  1169. for (int j = 0; j <= mDegree[dim]; ++j)
  1170. {
  1171. int kjIndex = mDegree[dim] + jIndex;
  1172. int ell = mLMax[dim][order[dim]];
  1173. mPhi[dim][j] = (Real)0;
  1174. for (int k = mDegree[dim]; k >= order[dim]; --k)
  1175. {
  1176. mPhi[dim][j] = mPhi[dim][j] * u[dim] +
  1177. mBlender[dim][kjIndex--] * mDCoefficient[dim][ell--];
  1178. }
  1179. jIndex += mDegreeP1[dim];
  1180. }
  1181. }
  1182. for (int j2 = 0; j2 <= mDegree[2]; ++j2)
  1183. {
  1184. Real phi2 = mPhi[2][j2];
  1185. for (int j1 = 0; j1 <= mDegree[1]; ++j1)
  1186. {
  1187. Real phi1 = mPhi[1][j1];
  1188. Real phi12 = phi1 * phi2;
  1189. for (int j0 = 0; j0 <= mDegree[0]; ++j0)
  1190. {
  1191. Real phi0 = mPhi[0][j0];
  1192. Real phi012 = phi0 * phi12;
  1193. result = result + (*mControls)(i[0] + j0, i[1] + j1, i[2] + j2) * phi012;
  1194. }
  1195. }
  1196. }
  1197. }
  1198. else
  1199. {
  1200. int i0i1i2Index = mNumTCols[2] * (i[0] + mNumTRows[0] * (i[1] + mNumTRows[1] * i[2]));
  1201. int k2i0i1i2Index = mDegree[2] + i0i1i2Index;
  1202. int ell2 = mLMax[2][order[2]];
  1203. for (int k2 = mDegree[2]; k2 >= order[2]; --k2)
  1204. {
  1205. int k1k2i0i1i2Index = mDegree[1] + mNumTCols[1] * k2i0i1i2Index;
  1206. int ell1 = mLMax[1][order[1]];
  1207. auto term1 = mCTZero;
  1208. for (int k1 = mDegree[1]; k1 >= order[1]; --k1)
  1209. {
  1210. int k0k1k2i0i1i2Index = mDegree[0] + mNumTCols[0] * k1k2i0i1i2Index;
  1211. int ell0 = mLMax[0][order[0]];
  1212. auto term0 = mCTZero;
  1213. for (int k0 = mDegree[0]; k0 >= order[0]; --k0)
  1214. {
  1215. if (mCacheMode == this->ON_DEMAND_CACHING && !mCached[k0k1k2i0i1i2Index])
  1216. {
  1217. ComputeTensor(i[0], i[1], i[2], k0, k1, k2, k0k1k2i0i1i2Index);
  1218. mCached[k0k1k2i0i1i2Index] = true;
  1219. }
  1220. term0 = term0 * u[0] + mTensor[k0k1k2i0i1i2Index--] * mDCoefficient[0][ell0--];
  1221. }
  1222. term1 = term1 * u[1] + term0 * mDCoefficient[1][ell1--];
  1223. --k1k2i0i1i2Index;
  1224. }
  1225. result = result * u[2] + term1 * mDCoefficient[2][ell2--];
  1226. --k2i0i1i2Index;
  1227. }
  1228. }
  1229. Real adjust(1);
  1230. for (int dim = 0; dim < 3; ++dim)
  1231. {
  1232. adjust *= mPowerDSDT[dim][order[dim]];
  1233. }
  1234. result = result * adjust;
  1235. }
  1236. return result;
  1237. }
  1238. protected:
  1239. void ComputeTensor(int r0, int r1, int r2, int c0, int c1, int c2, int index)
  1240. {
  1241. auto element = mCTZero;
  1242. for (int j2 = 0; j2 <= mDegree[2]; ++j2)
  1243. {
  1244. Real blend2 = mBlender[2][c2 + mDegreeP1[2] * j2];
  1245. for (int j1 = 0; j1 <= mDegree[1]; ++j1)
  1246. {
  1247. Real blend1 = mBlender[1][c1 + mDegreeP1[1] * j1];
  1248. Real blend12 = blend1 * blend2;
  1249. for (int j0 = 0; j0 <= mDegree[0]; ++j0)
  1250. {
  1251. Real blend0 = mBlender[0][c0 + mDegreeP1[0] * j0];
  1252. Real blend012 = blend0 * blend12;
  1253. element = element + (*mControls)(r0 + j0, r1 + j1, r2 + j2) * blend012;
  1254. }
  1255. }
  1256. }
  1257. mTensor[index] = element;
  1258. }
  1259. void InitializeTensors()
  1260. {
  1261. int numCached = 1;
  1262. for (int dim = 0; dim < 3; ++dim)
  1263. {
  1264. mNumTRows[dim] = mNumControls[dim] - mDegree[dim];
  1265. mNumTCols[dim] = mDegreeP1[dim];
  1266. numCached *= mNumTRows[dim] * mNumTCols[dim];
  1267. }
  1268. mTensor.resize(numCached);
  1269. mCached.resize(numCached);
  1270. if (mCacheMode == this->PRE_CACHING)
  1271. {
  1272. for (int r2 = 0, index = 0; r2 < mNumTRows[2]; ++r2)
  1273. {
  1274. for (int r1 = 0; r1 < mNumTRows[1]; ++r1)
  1275. {
  1276. for (int r0 = 0; r0 < mNumTRows[0]; ++r0)
  1277. {
  1278. for (int c2 = 0; c2 < mNumTCols[2]; ++c2)
  1279. {
  1280. for (int c1 = 0; c1 < mNumTCols[1]; ++c1)
  1281. {
  1282. for (int c0 = 0; c0 < mNumTCols[0]; ++c0, ++index)
  1283. {
  1284. ComputeTensor(r0, r1, r2, c0, c1, c2, index);
  1285. }
  1286. }
  1287. }
  1288. }
  1289. }
  1290. }
  1291. std::fill(mCached.begin(), mCached.end(), true);
  1292. }
  1293. else
  1294. {
  1295. std::fill(mCached.begin(), mCached.end(), false);
  1296. }
  1297. }
  1298. // Constructor inputs.
  1299. std::array<int, 3> mDegree;
  1300. Controls const* mControls;
  1301. typename Controls::Type mCTZero;
  1302. int mCacheMode;
  1303. // Parameters for B-spline evaluation.
  1304. std::array<int, 3> mDegreeP1;
  1305. std::array<int, 3> mNumControls;
  1306. std::array<Real, 3> mTMin, mTMax;
  1307. std::array<std::vector<Real>, 3> mBlender;
  1308. std::array<std::vector<Real>, 3> mDCoefficient;
  1309. std::array<std::vector<int>, 3> mLMax;
  1310. std::array<std::vector<Real>, 3> mPowerDSDT;
  1311. // Support for no-cached B-spline evaluation.
  1312. std::array<std::vector<Real>, 3> mPhi;
  1313. // Support for cached B-spline evaluation.
  1314. std::array<int, 3> mNumTRows, mNumTCols;
  1315. std::vector<typename Controls::Type> mTensor;
  1316. std::vector<bool> mCached;
  1317. };
  1318. }
  1319. #endif