123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178 |
- // David Eberly, Geometric Tools, Redmond WA 98052
- // Copyright (c) 1998-2020
- // Distributed under the Boost Software License, Version 1.0.
- // https://www.boost.org/LICENSE_1_0.txt
- // https://www.geometrictools.com/License/Boost/LICENSE_1_0.txt
- // Version: 4.0.2019.08.13
- #pragma once
- #include <Mathematics/Logger.h>
- #include <Mathematics/Array2.h>
- #include <Mathematics/ParametricCurve.h>
- namespace WwiseGTE
- {
- template <int N, typename Real>
- class BezierCurve : public ParametricCurve<N, Real>
- {
- public:
- // Construction and destruction. The number of control points must be
- // degree + 1. This object copies the input array. The domain is t
- // in [0,1]. To validate construction, create an object as shown:
- // BezierCurve<N, Real> curve(parameters);
- // if (!curve) { <constructor failed, handle accordingly>; }
- BezierCurve(int degree, Vector<N, Real> const* controls)
- :
- ParametricCurve<N, Real>((Real)0, (Real)1),
- mDegree(degree),
- mNumControls(degree + 1),
- mChoose(mNumControls, mNumControls)
- {
- LogAssert(degree >= 2 && controls != nullptr, "Invalid input.");
- // Copy the controls.
- mControls[0].resize(mNumControls);
- std::copy(controls, controls + mNumControls, mControls[0].begin());
- // Compute first-order differences.
- mControls[1].resize(mNumControls - 1);
- for (int i = 0; i < mNumControls - 1; ++i)
- {
- mControls[1][i] = mControls[0][i + 1] - mControls[0][i];
- }
- // Compute second-order differences.
- mControls[2].resize(mNumControls - 2);
- for (int i = 0; i < mNumControls - 2; ++i)
- {
- mControls[2][i] = mControls[1][i + 1] - mControls[1][i];
- }
- // Compute third-order differences.
- if (degree >= 3)
- {
- mControls[3].resize(mNumControls - 3);
- for (int i = 0; i < mNumControls - 3; ++i)
- {
- mControls[3][i] = mControls[2][i + 1] - mControls[2][i];
- }
- }
- // Compute combinatorial values Choose(n,k) and store in mChoose[n][k].
- // The values mChoose[r][c] are invalid for r < c; that is, we use only
- // the entries for r >= c.
- mChoose[0][0] = (Real)1;
- mChoose[1][0] = (Real)1;
- mChoose[1][1] = (Real)1;
- for (int i = 2; i <= mDegree; ++i)
- {
- mChoose[i][0] = (Real)1;
- mChoose[i][i] = (Real)1;
- for (int j = 1; j < i; ++j)
- {
- mChoose[i][j] = mChoose[i - 1][j - 1] + mChoose[i - 1][j];
- }
- }
- this->mConstructed = true;
- }
- virtual ~BezierCurve()
- {
- }
- // Member access.
- inline int GetDegree() const
- {
- return mDegree;
- }
- inline int GetNumControls() const
- {
- return mNumControls;
- }
- inline Vector<N, Real> const* GetControls() const
- {
- return &mControls[0][0];
- }
- // Evaluation of the curve. The function supports derivative
- // calculation through order 3; that is, order <= 3 is required. If
- // you want/ only the position, pass in order of 0. If you want the
- // position and first derivative, pass in order of 1, and so on. The
- // output array 'jet' must have enough storage to support the maximum
- // order. The values are ordered as: position, first derivative,
- // second derivative, third derivative.
- virtual void Evaluate(Real t, unsigned int order, Vector<N, Real>* jet) const override
- {
- unsigned int const supOrder = ParametricCurve<N, Real>::SUP_ORDER;
- if (!this->mConstructed || order >= supOrder)
- {
- // Return a zero-valued jet for invalid state.
- for (unsigned int i = 0; i < supOrder; ++i)
- {
- jet[i].MakeZero();
- }
- return;
- }
- // Compute position.
- Real omt = (Real)1 - t;
- jet[0] = Compute(t, omt, 0);
- if (order >= 1)
- {
- // Compute first derivative.
- jet[1] = Compute(t, omt, 1);
- if (order >= 2)
- {
- // Compute second derivative.
- jet[2] = Compute(t, omt, 2);
- if (order >= 3)
- {
- // Compute third derivative.
- if (mDegree >= 3)
- {
- jet[3] = Compute(t, omt, 3);
- }
- else
- {
- jet[3].MakeZero();
- }
- }
- }
- }
- }
- protected:
- // Support for Evaluate(...).
- Vector<N, Real> Compute(Real t, Real omt, int order) const
- {
- Vector<N, Real> result = omt * mControls[order][0];
- Real tpow = t;
- int isup = mDegree - order;
- for (int i = 1; i < isup; ++i)
- {
- Real c = mChoose[isup][i] * tpow;
- result = (result + c * mControls[order][i]) * omt;
- tpow *= t;
- }
- result = (result + tpow * mControls[order][isup]);
- int multiplier = 1;
- for (int i = 0; i < order; ++i)
- {
- multiplier *= mDegree - i;
- }
- result *= (Real)multiplier;
- return result;
- }
- int mDegree, mNumControls;
- std::array<std::vector<Vector<N, Real>>, ParametricCurve<N, Real>::SUP_ORDER> mControls;
- Array2<Real> mChoose;
- };
- }
|