BSplineCurve.h 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155
  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/BasisFunction.h>
  9. #include <Mathematics/ParametricCurve.h>
  10. namespace WwiseGTE
  11. {
  12. template <int N, typename Real>
  13. class BSplineCurve : public ParametricCurve<N, Real>
  14. {
  15. public:
  16. // Construction. If the input controls is non-null, a copy is made of
  17. // the controls. To defer setting the control points, pass a null
  18. // pointer and later access the control points via GetControls() or
  19. // SetControl() member functions. The domain is t in [t[d],t[n]],
  20. // where t[d] and t[n] are knots with d the degree and n the number of
  21. // control points.
  22. BSplineCurve(BasisFunctionInput<Real> const& input, Vector<N, Real> const* controls)
  23. :
  24. ParametricCurve<N, Real>((Real)0, (Real)1),
  25. mBasisFunction(input)
  26. {
  27. // The mBasisFunction stores the domain but so does
  28. // ParametricCurve.
  29. this->mTime.front() = mBasisFunction.GetMinDomain();
  30. this->mTime.back() = mBasisFunction.GetMaxDomain();
  31. // The replication of control points for periodic splines is
  32. // avoided by wrapping the i-loop index in Evaluate.
  33. mControls.resize(input.numControls);
  34. if (controls)
  35. {
  36. std::copy(controls, controls + input.numControls, mControls.begin());
  37. }
  38. else
  39. {
  40. Vector<N, Real> zero{ (Real)0 };
  41. std::fill(mControls.begin(), mControls.end(), zero);
  42. }
  43. this->mConstructed = true;
  44. }
  45. // Member access.
  46. inline BasisFunction<Real> const& GetBasisFunction() const
  47. {
  48. return mBasisFunction;
  49. }
  50. inline int GetNumControls() const
  51. {
  52. return static_cast<int>(mControls.size());
  53. }
  54. inline Vector<N, Real> const* GetControls() const
  55. {
  56. return mControls.data();
  57. }
  58. inline Vector<N, Real>* GetControls()
  59. {
  60. return mControls.data();
  61. }
  62. void SetControl(int i, Vector<N, Real> const& control)
  63. {
  64. if (0 <= i && i < GetNumControls())
  65. {
  66. mControls[i] = control;
  67. }
  68. }
  69. Vector<N, Real> const& GetControl(int i) const
  70. {
  71. if (0 <= i && i < GetNumControls())
  72. {
  73. return mControls[i];
  74. }
  75. else
  76. {
  77. return mControls[0];
  78. }
  79. }
  80. // Evaluation of the curve. The function supports derivative
  81. // calculation through order 3; that is, order <= 3 is required. If
  82. // you want/ only the position, pass in order of 0. If you want the
  83. // position and first derivative, pass in order of 1, and so on. The
  84. // output array 'jet' must have enough storage to support the maximum
  85. // order. The values are ordered as: position, first derivative,
  86. // second derivative, third derivative.
  87. virtual void Evaluate(Real t, unsigned int order, Vector<N, Real>* jet) const override
  88. {
  89. unsigned int const supOrder = ParametricCurve<N, Real>::SUP_ORDER;
  90. if (!this->mConstructed || order >= supOrder)
  91. {
  92. // Return a zero-valued jet for invalid state.
  93. for (unsigned int i = 0; i < supOrder; ++i)
  94. {
  95. jet[i].MakeZero();
  96. }
  97. return;
  98. }
  99. int imin, imax;
  100. mBasisFunction.Evaluate(t, order, imin, imax);
  101. // Compute position.
  102. jet[0] = Compute(0, imin, imax);
  103. if (order >= 1)
  104. {
  105. // Compute first derivative.
  106. jet[1] = Compute(1, imin, imax);
  107. if (order >= 2)
  108. {
  109. // Compute second derivative.
  110. jet[2] = Compute(2, imin, imax);
  111. if (order == 3)
  112. {
  113. jet[3] = Compute(3, imin, imax);
  114. }
  115. }
  116. }
  117. }
  118. private:
  119. // Support for Evaluate(...).
  120. Vector<N, Real> Compute(unsigned int order, int imin, int imax) const
  121. {
  122. // The j-index introduces a tiny amount of overhead in order to handle
  123. // both aperiodic and periodic splines. For aperiodic splines, j = i
  124. // always.
  125. int numControls = GetNumControls();
  126. Vector<N, Real> result;
  127. result.MakeZero();
  128. for (int i = imin; i <= imax; ++i)
  129. {
  130. Real tmp = mBasisFunction.GetValue(order, i);
  131. int j = (i >= numControls ? i - numControls : i);
  132. result += tmp * mControls[j];
  133. }
  134. return result;
  135. }
  136. BasisFunction<Real> mBasisFunction;
  137. std::vector<Vector<N, Real>> mControls;
  138. };
  139. }