123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474 |
- #pragma once
- #include <Mathematics/Logger.h>
- #include <Mathematics/Math.h>
- #include <Mathematics/Array2.h>
- #include <array>
- #include <cstring>
- namespace WwiseGTE
- {
- template <typename Real>
- struct UniqueKnot
- {
- Real t;
- int multiplicity;
- };
- template <typename Real>
- struct BasisFunctionInput
- {
-
- BasisFunctionInput()
- {
- }
-
- BasisFunctionInput(int inNumControls, int inDegree)
- :
- numControls(inNumControls),
- degree(inDegree),
- uniform(true),
- periodic(false),
- numUniqueKnots(numControls - degree + 1),
- uniqueKnots(numUniqueKnots)
- {
- uniqueKnots.front().t = (Real)0;
- uniqueKnots.front().multiplicity = degree + 1;
- for (int i = 1; i <= numUniqueKnots - 2; ++i)
- {
- uniqueKnots[i].t = i / (numUniqueKnots - (Real)1);
- uniqueKnots[i].multiplicity = 1;
- }
- uniqueKnots.back().t = (Real)1;
- uniqueKnots.back().multiplicity = degree + 1;
- }
- int numControls;
- int degree;
- bool uniform;
- bool periodic;
- int numUniqueKnots;
- std::vector<UniqueKnot<Real>> uniqueKnots;
- };
- template <typename Real>
- class BasisFunction
- {
- public:
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- BasisFunction()
- :
- mNumControls(0),
- mDegree(0),
- mTMin((Real)0),
- mTMax((Real)0),
- mTLength((Real)0),
- mOpen(false),
- mUniform(false),
- mPeriodic(false)
- {
- }
- BasisFunction(BasisFunctionInput<Real> const& input)
- :
- mNumControls(0),
- mDegree(0),
- mTMin((Real)0),
- mTMax((Real)0),
- mTLength((Real)0),
- mOpen(false),
- mUniform(false),
- mPeriodic(false)
- {
- Create(input);
- }
- ~BasisFunction()
- {
- }
-
- BasisFunction(BasisFunction const&) = delete;
- BasisFunction& operator=(BasisFunction const&) = delete;
-
-
- void Create(BasisFunctionInput<Real> const& input)
- {
- LogAssert(mNumControls == 0 && mDegree == 0, "Object already created.");
- LogAssert(input.numControls >= 2, "Invalid number of control points.");
- LogAssert(1 <= input.degree && input.degree < input.numControls, "Invalid degree.");
- LogAssert(input.numUniqueKnots >= 2, "Invalid number of unique knots.");
- mNumControls = (input.periodic ? input.numControls + input.degree : input.numControls);
- mDegree = input.degree;
- mTMin = (Real)0;
- mTMax = (Real)0;
- mTLength = (Real)0;
- mOpen = false;
- mUniform = input.uniform;
- mPeriodic = input.periodic;
- for (int i = 0; i < 4; ++i)
- {
- mJet[i] = Array2<Real>();
- }
- mUniqueKnots.resize(input.numUniqueKnots);
- std::copy(input.uniqueKnots.begin(),
- input.uniqueKnots.begin() + input.numUniqueKnots,
- mUniqueKnots.begin());
- Real u = mUniqueKnots.front().t;
- for (int i = 1; i < input.numUniqueKnots - 1; ++i)
- {
- Real uNext = mUniqueKnots[i].t;
- LogAssert(u < uNext, "Unique knots are not strictly increasing.");
- u = uNext;
- }
- int mult0 = mUniqueKnots.front().multiplicity;
- LogAssert(mult0 >= 1 && mult0 <= mDegree + 1, "Invalid first multiplicity.");
- int mult1 = mUniqueKnots.back().multiplicity;
- LogAssert(mult1 >= 1 && mult1 <= mDegree + 1, "Invalid last multiplicity.");
- for (int i = 1; i <= input.numUniqueKnots - 2; ++i)
- {
- int mult = mUniqueKnots[i].multiplicity;
- LogAssert(mult >= 1 && mult <= mDegree + 1, "Invalid interior multiplicity.");
- }
- mOpen = (mult0 == mult1 && mult0 == mDegree + 1);
- mKnots.resize(mNumControls + mDegree + 1);
- mKeys.resize(input.numUniqueKnots);
- int sum = 0;
- for (int i = 0, j = 0; i < input.numUniqueKnots; ++i)
- {
- Real tCommon = mUniqueKnots[i].t;
- int mult = mUniqueKnots[i].multiplicity;
- for (int k = 0; k < mult; ++k, ++j)
- {
- mKnots[j] = tCommon;
- }
- mKeys[i].first = tCommon;
- mKeys[i].second = sum - 1;
- sum += mult;
- }
- mTMin = mKnots[mDegree];
- mTMax = mKnots[mNumControls];
- mTLength = mTMax - mTMin;
- size_t numRows = mDegree + 1;
- size_t numCols = mNumControls + mDegree;
- size_t numBytes = numRows * numCols * sizeof(Real);
- for (int i = 0; i < 4; ++i)
- {
- mJet[i] = Array2<Real>(numCols, numRows);
- std::memset(mJet[i][0], 0, numBytes);
- }
- }
-
- inline int GetNumControls() const
- {
- return mNumControls;
- }
- inline int GetDegree() const
- {
- return mDegree;
- }
- inline int GetNumUniqueKnots() const
- {
- return static_cast<int>(mUniqueKnots.size());
- }
- inline int GetNumKnots() const
- {
- return static_cast<int>(mKnots.size());
- }
- inline Real GetMinDomain() const
- {
- return mTMin;
- }
- inline Real GetMaxDomain() const
- {
- return mTMax;
- }
- inline bool IsOpen() const
- {
- return mOpen;
- }
- inline bool IsUniform() const
- {
- return mUniform;
- }
- inline bool IsPeriodic() const
- {
- return mPeriodic;
- }
- inline UniqueKnot<Real> const* GetUniqueKnots() const
- {
- return &mUniqueKnots[0];
- }
- inline Real const* GetKnots() const
- {
- return &mKnots[0];
- }
-
-
-
- void Evaluate(Real t, unsigned int order, int& minIndex, int& maxIndex) const
- {
- LogAssert(order <= 3, "Invalid order.");
- int i = GetIndex(t);
- mJet[0][0][i] = (Real)1;
- if (order >= 1)
- {
- mJet[1][0][i] = (Real)0;
- if (order >= 2)
- {
- mJet[2][0][i] = (Real)0;
- if (order >= 3)
- {
- mJet[3][0][i] = (Real)0;
- }
- }
- }
- Real n0 = t - mKnots[i], n1 = mKnots[i + 1] - t;
- Real e0, e1, d0, d1, invD0, invD1;
- int j;
- for (j = 1; j <= mDegree; j++)
- {
- d0 = mKnots[i + j] - mKnots[i];
- d1 = mKnots[i + 1] - mKnots[i - j + 1];
- invD0 = (d0 > (Real)0 ? (Real)1 / d0 : (Real)0);
- invD1 = (d1 > (Real)0 ? (Real)1 / d1 : (Real)0);
- e0 = n0 * mJet[0][j - 1][i];
- mJet[0][j][i] = e0 * invD0;
- e1 = n1 * mJet[0][j - 1][i - j + 1];
- mJet[0][j][i - j] = e1 * invD1;
- if (order >= 1)
- {
- e0 = n0 * mJet[1][j - 1][i] + mJet[0][j - 1][i];
- mJet[1][j][i] = e0 * invD0;
- e1 = n1 * mJet[1][j - 1][i - j + 1] - mJet[0][j - 1][i - j + 1];
- mJet[1][j][i - j] = e1 * invD1;
- if (order >= 2)
- {
- e0 = n0 * mJet[2][j - 1][i] + ((Real)2) * mJet[1][j - 1][i];
- mJet[2][j][i] = e0 * invD0;
- e1 = n1 * mJet[2][j - 1][i - j + 1] - ((Real)2) * mJet[1][j - 1][i - j + 1];
- mJet[2][j][i - j] = e1 * invD1;
- if (order >= 3)
- {
- e0 = n0 * mJet[3][j - 1][i] + ((Real)3) * mJet[2][j - 1][i];
- mJet[3][j][i] = e0 * invD0;
- e1 = n1 * mJet[3][j - 1][i - j + 1] - ((Real)3) * mJet[2][j - 1][i - j + 1];
- mJet[3][j][i - j] = e1 * invD1;
- }
- }
- }
- }
- for (j = 2; j <= mDegree; ++j)
- {
- for (int k = i - j + 1; k < i; ++k)
- {
- n0 = t - mKnots[k];
- n1 = mKnots[k + j + 1] - t;
- d0 = mKnots[k + j] - mKnots[k];
- d1 = mKnots[k + j + 1] - mKnots[k + 1];
- invD0 = (d0 > (Real)0 ? (Real)1 / d0 : (Real)0);
- invD1 = (d1 > (Real)0 ? (Real)1 / d1 : (Real)0);
- e0 = n0 * mJet[0][j - 1][k];
- e1 = n1 * mJet[0][j - 1][k + 1];
- mJet[0][j][k] = e0 * invD0 + e1 * invD1;
- if (order >= 1)
- {
- e0 = n0 * mJet[1][j - 1][k] + mJet[0][j - 1][k];
- e1 = n1 * mJet[1][j - 1][k + 1] - mJet[0][j - 1][k + 1];
- mJet[1][j][k] = e0 * invD0 + e1 * invD1;
- if (order >= 2)
- {
- e0 = n0 * mJet[2][j - 1][k] + ((Real)2) * mJet[1][j - 1][k];
- e1 = n1 * mJet[2][j - 1][k + 1] - ((Real)2) * mJet[1][j - 1][k + 1];
- mJet[2][j][k] = e0 * invD0 + e1 * invD1;
- if (order >= 3)
- {
- e0 = n0 * mJet[3][j - 1][k] + ((Real)3) * mJet[2][j - 1][k];
- e1 = n1 * mJet[3][j - 1][k + 1] - ((Real)3) * mJet[2][j - 1][k + 1];
- mJet[3][j][k] = e0 * invD0 + e1 * invD1;
- }
- }
- }
- }
- }
- minIndex = i - mDegree;
- maxIndex = i;
- }
-
-
-
-
-
- Real GetValue(unsigned int order, int i) const
- {
- if (order < 4)
- {
- if (0 <= i && i < mNumControls + mDegree)
- {
- return mJet[order][mDegree][i];
- }
- LogError("Invalid index.");
- }
- LogError("Invalid order.");
- }
- private:
-
-
-
- int GetIndex(Real& t) const
- {
-
- if (mPeriodic)
- {
-
- Real r = std::fmod(t - mTMin, mTLength);
- if (r < (Real)0)
- {
- r += mTLength;
- }
- t = mTMin + r;
- }
-
-
- if (t <= mTMin)
- {
- t = mTMin;
- return mDegree;
- }
- if (t >= mTMax)
- {
- t = mTMax;
- return mNumControls - 1;
- }
-
- for (auto const& key : mKeys)
- {
- if (t < key.first)
- {
- return key.second;
- }
- }
-
- LogError("Unexpected condition.");
- }
-
- int mNumControls;
- int mDegree;
- Real mTMin, mTMax, mTLength;
- bool mOpen;
- bool mUniform;
- bool mPeriodic;
- std::vector<UniqueKnot<Real>> mUniqueKnots;
- std::vector<Real> mKnots;
-
-
-
- std::vector<std::pair<Real, int>> mKeys;
-
-
- mutable std::array<Array2<Real>, 4> mJet;
- };
- }
|