123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312 |
- #pragma once
- #include <Mathematics/Integration.h>
- #include <Mathematics/RootsBisection.h>
- #include <Mathematics/Vector.h>
- namespace WwiseGTE
- {
- template <int N, typename Real>
- class ParametricCurve
- {
- protected:
-
-
-
-
- ParametricCurve(Real tmin, Real tmax)
- :
- mTime(2),
- mSegmentLength(1),
- mAccumulatedLength(1),
- mRombergOrder(DEFAULT_ROMBERG_ORDER),
- mMaxBisections(DEFAULT_MAX_BISECTIONS),
- mConstructed(false)
- {
- mTime[0] = tmin;
- mTime[1] = tmax;
- mSegmentLength[0] = (Real)0;
- mAccumulatedLength[0] = (Real)0;
- }
- ParametricCurve(int numSegments, Real const* times)
- :
- mTime(numSegments + 1),
- mSegmentLength(numSegments),
- mAccumulatedLength(numSegments),
- mRombergOrder(DEFAULT_ROMBERG_ORDER),
- mMaxBisections(DEFAULT_MAX_BISECTIONS),
- mConstructed(false)
- {
- std::copy(times, times + numSegments + 1, mTime.begin());
- mSegmentLength[0] = (Real)0;
- mAccumulatedLength[0] = (Real)0;
- }
- public:
- virtual ~ParametricCurve()
- {
- }
-
-
-
- inline operator bool() const
- {
- return mConstructed;
- }
-
- inline Real GetTMin() const
- {
- return mTime.front();
- }
- inline Real GetTMax() const
- {
- return mTime.back();
- }
- inline int GetNumSegments() const
- {
- return static_cast<int>(mSegmentLength.size());
- }
- inline Real const* GetTimes() const
- {
- return &mTime[0];
- }
-
-
- void SetTimeInterval(Real tmin, Real tmax)
- {
- if (mTime.size() == 2)
- {
- mTime[0] = tmin;
- mTime[1] = tmax;
- }
- }
-
-
-
- inline void SetRombergOrder(int order)
- {
- mRombergOrder = std::max(order, 1);
- }
-
- inline void SetMaxBisections(unsigned int maxBisections)
- {
- mMaxBisections = std::max(maxBisections, 1u);
- }
-
-
-
-
-
-
-
- enum { SUP_ORDER = 4 };
- virtual void Evaluate(Real t, unsigned int order, Vector<N, Real>* jet) const = 0;
- void Evaluate(Real t, unsigned int order, Real* values) const
- {
- Evaluate(t, order, reinterpret_cast<Vector<N, Real>*>(values));
- }
-
- Vector<N, Real> GetPosition(Real t) const
- {
- Vector<N, Real> position;
- Evaluate(t, 0, &position);
- return position;
- }
- Vector<N, Real> GetTangent(Real t) const
- {
- std::array<Vector<N, Real>, 2> jet;
- Evaluate(t, 1, jet.data());
- Normalize(jet[1]);
- return jet[1];
- }
- Real GetSpeed(Real t) const
- {
- std::array<Vector<N, Real>, 2> jet;
- Evaluate(t, 1, jet.data());
- return Length(jet[1]);
- }
- Real GetLength(Real t0, Real t1) const
- {
- std::function<Real(Real)> speed = [this](Real t)
- {
- return GetSpeed(t);
- };
- if (mSegmentLength[0] == (Real)0)
- {
-
- int const numSegments = static_cast<int>(mSegmentLength.size());
- Real accumulated = (Real)0;
- for (int i = 0; i < numSegments; ++i)
- {
- mSegmentLength[i] = Integration<Real>::Romberg(mRombergOrder,
- mTime[i], mTime[i + 1], speed);
- accumulated += mSegmentLength[i];
- mAccumulatedLength[i] = accumulated;
- }
- }
- t0 = std::max(t0, GetTMin());
- t1 = std::min(t1, GetTMax());
- auto iter0 = std::lower_bound(mTime.begin(), mTime.end(), t0);
- int index0 = static_cast<int>(iter0 - mTime.begin());
- auto iter1 = std::lower_bound(mTime.begin(), mTime.end(), t1);
- int index1 = static_cast<int>(iter1 - mTime.begin());
- Real length;
- if (index0 < index1)
- {
- length = (Real)0;
- if (t0 < *iter0)
- {
- length += Integration<Real>::Romberg(mRombergOrder, t0,
- mTime[index0], speed);
- }
- int isup;
- if (t1 < *iter1)
- {
- length += Integration<Real>::Romberg(mRombergOrder,
- mTime[index1 - 1], t1, speed);
- isup = index1 - 1;
- }
- else
- {
- isup = index1;
- }
- for (int i = index0; i < isup; ++i)
- {
- length += mSegmentLength[i];
- }
- }
- else
- {
- length = Integration<Real>::Romberg(mRombergOrder, t0, t1, speed);
- }
- return length;
- }
- Real GetTotalLength() const
- {
- if (mAccumulatedLength.back() == (Real)0)
- {
-
- return GetLength(mTime.front(), mTime.back());
- }
- return mAccumulatedLength.back();
- }
-
-
-
-
-
-
-
-
-
- Real GetTime(Real length) const
- {
- if (length > (Real)0)
- {
- if (length < GetTotalLength())
- {
- std::function<Real(Real)> F = [this, &length](Real t)
- {
- return Integration<Real>::Romberg(mRombergOrder,
- mTime.front(), t, [this](Real z) { return GetSpeed(z); })
- - length;
- };
-
-
-
- Real ratio = length / GetTotalLength();
- Real omratio = (Real)1 - ratio;
- Real tmid = omratio * mTime.front() + ratio * mTime.back();
- Real fmid = F(tmid);
- if (fmid > (Real)0)
- {
- RootsBisection<Real>::Find(F, mTime.front(), tmid, (Real)-1,
- (Real)1, mMaxBisections, tmid);
- }
- else if (fmid < (Real)0)
- {
- RootsBisection<Real>::Find(F, tmid, mTime.back(), (Real)-1,
- (Real)1, mMaxBisections, tmid);
- }
- return tmid;
- }
- else
- {
- return mTime.back();
- }
- }
- else
- {
- return mTime.front();
- }
- }
-
-
- void SubdivideByTime(int numPoints, Vector<N, Real>* points) const
- {
- Real delta = (mTime.back() - mTime.front()) / (Real)(numPoints - 1);
- for (int i = 0; i < numPoints; ++i)
- {
- Real t = mTime.front() + delta * i;
- points[i] = GetPosition(t);
- }
- }
- void SubdivideByLength(int numPoints, Vector<N, Real>* points) const
- {
- Real delta = GetTotalLength() / (Real)(numPoints - 1);
- for (int i = 0; i < numPoints; ++i)
- {
- Real length = delta * i;
- Real t = GetTime(length);
- points[i] = GetPosition(t);
- }
- }
- protected:
- enum
- {
- DEFAULT_ROMBERG_ORDER = 8,
- DEFAULT_MAX_BISECTIONS = 1024
- };
- std::vector<Real> mTime;
- mutable std::vector<Real> mSegmentLength;
- mutable std::vector<Real> mAccumulatedLength;
- int mRombergOrder;
- unsigned int mMaxBisections;
- bool mConstructed;
- };
- }
|