Advertisement
FrayxRulez

Untitled

Jul 11th, 2015
281
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 8.15 KB | None | 0 0
  1. public class KeySplineHelper
  2. {
  3. public KeySplineHelper(KeySpline spline)
  4. {
  5. _controlPoint1 = spline.ControlPoint1;
  6. _controlPoint2 = spline.ControlPoint2;
  7. }
  8.  
  9. #region Public
  10. /// <summary>
  11. /// Implemented to linearly interpolate between the baseValue and the
  12. /// Value of this KeyFrame using the keyFrameProgress.
  13. /// </summary>
  14. public double InterpolateValueCore(SplineDoubleKeyFrame frame, double baseValue, double keyFrameProgress)
  15. {
  16. if (keyFrameProgress == 0.0)
  17. {
  18. return baseValue;
  19. }
  20. else if (keyFrameProgress == 1.0)
  21. {
  22. return frame.Value;
  23. }
  24. else
  25. {
  26. double splineProgress = GetSplineProgress(keyFrameProgress);
  27.  
  28. return InterpolateDouble(baseValue, frame.Value, splineProgress);
  29. }
  30. }
  31.  
  32. /// <summary>
  33. /// Calculates spline progress from a linear progress.
  34. /// </summary>
  35. /// <param name="linearProgress">the linear progress</param>
  36. /// <returns>the spline progress [0, 1]</returns>
  37. public double GetSplineProgress(double linearProgress)
  38. {
  39. if (_isDirty)
  40. {
  41. Build();
  42. }
  43.  
  44. if (!_isSpecified)
  45. {
  46. return linearProgress;
  47. }
  48. else
  49. {
  50. SetParameterFromX(linearProgress);
  51.  
  52. return GetBezierValue(_By, _Cy, _parameter);
  53. }
  54. }
  55.  
  56. #endregion
  57.  
  58. #region Private
  59. internal static Double InterpolateDouble(Double from, Double to, Double progress)
  60. {
  61. return from + ((to - from) * progress);
  62. }
  63.  
  64. private bool IsValidControlPoint(Point point)
  65. {
  66. return point.X >= 0.0
  67. && point.X <= 1.0;
  68. }
  69.  
  70. /// <summary>
  71. /// Compute cached coefficients.
  72. /// </summary>
  73. private void Build()
  74. {
  75. if (_controlPoint1 == new Point(0, 0)
  76. && _controlPoint2 == new Point(1, 1))
  77. {
  78. // This KeySpline would have no effect on the progress.
  79.  
  80. _isSpecified = false;
  81. }
  82. else
  83. {
  84. _isSpecified = true;
  85.  
  86. _parameter = 0;
  87.  
  88. // X coefficients
  89. _Bx = 3 * _controlPoint1.X;
  90. _Cx = 3 * _controlPoint2.X;
  91. _Cx_Bx = 2 * (_Cx - _Bx);
  92. _three_Cx = 3 - _Cx;
  93.  
  94. // Y coefficients
  95. _By = 3 * _controlPoint1.Y;
  96. _Cy = 3 * _controlPoint2.Y;
  97. }
  98.  
  99. _isDirty = false;
  100. }
  101.  
  102. /// <summary>
  103. /// Get an X or Y value with the Bezier formula.
  104. /// </summary>
  105. /// <param name="b">the second Bezier coefficient</param>
  106. /// <param name="c">the third Bezier coefficient</param>
  107. /// <param name="t">the parameter value to evaluate at</param>
  108. /// <returns>the value of the Bezier function at the given parameter</returns>
  109. static private double GetBezierValue(double b, double c, double t)
  110. {
  111. double s = 1.0 - t;
  112. double t2 = t * t;
  113.  
  114. return b * t * s * s + c * t2 * s + t2 * t;
  115. }
  116.  
  117. /// <summary>
  118. /// Get X and dX/dt at a given parameter
  119. /// </summary>
  120. /// <param name="t">the parameter value to evaluate at</param>
  121. /// <param name="x">the value of x there</param>
  122. /// <param name="dx">the value of dx/dt there</param>
  123. private void GetXAndDx(double t, out double x, out double dx)
  124. {
  125. double s = 1.0 - t;
  126. double t2 = t * t;
  127. double s2 = s * s;
  128.  
  129. x = _Bx * t * s2 + _Cx * t2 * s + t2 * t;
  130. dx = _Bx * s2 + _Cx_Bx * s * t + _three_Cx * t2;
  131. }
  132.  
  133. /// <summary>
  134. /// Compute the parameter value that corresponds to a given X value, using a modified
  135. /// clamped Newton-Raphson algorithm to solve the equation X(t) - time = 0. We make
  136. /// use of some known properties of this particular function:
  137. /// * We are only interested in solutions in the interval [0,1]
  138. /// * X(t) is increasing, so we can assume that if X(t) > time t > solution. We use
  139. /// that to clamp down the search interval with every probe.
  140. /// * The derivative of X and Y are between 0 and 3.
  141. /// </summary>
  142. /// <param name="time">the time, scaled to fit in [0,1]</param>
  143. private void SetParameterFromX(double time)
  144. {
  145. // Dynamic search interval to clamp with
  146. double bottom = 0;
  147. double top = 1;
  148.  
  149. if (time == 0)
  150. {
  151. _parameter = 0;
  152. }
  153. else if (time == 1)
  154. {
  155. _parameter = 1;
  156. }
  157. else
  158. {
  159. // Loop while improving the guess
  160. while (top - bottom > fuzz)
  161. {
  162. double x, dx, absdx;
  163.  
  164. // Get x and dx/dt at the current parameter
  165. GetXAndDx(_parameter, out x, out dx);
  166. absdx = Math.Abs(dx);
  167.  
  168. // Clamp down the search interval, relying on the monotonicity of X(t)
  169. if (x > time)
  170. {
  171. top = _parameter; // because parameter > solution
  172. }
  173. else
  174. {
  175. bottom = _parameter; // because parameter < solution
  176. }
  177.  
  178. // The desired accuracy is in ultimately in y, not in x, so the
  179. // accuracy needs to be multiplied by dx/dy = (dx/dt) / (dy/dt).
  180. // But dy/dt <=3, so we omit that
  181. if (Math.Abs(x - time) < accuracy * absdx)
  182. {
  183. break; // We're there
  184. }
  185.  
  186. if (absdx > fuzz)
  187. {
  188. // Nonzero derivative, use Newton-Raphson to obtain the next guess
  189. double next = _parameter - (x - time) / dx;
  190.  
  191. // If next guess is out of the search interval then clamp it in
  192. if (next >= top)
  193. {
  194. _parameter = (_parameter + top) / 2;
  195. }
  196. else if (next <= bottom)
  197. {
  198. _parameter = (_parameter + bottom) / 2;
  199. }
  200. else
  201. {
  202. // Next guess is inside the search interval, accept it
  203. _parameter = next;
  204. }
  205. }
  206. else // Zero derivative, halve the search interval
  207. {
  208. _parameter = (bottom + top) / 2;
  209. }
  210. }
  211. }
  212. }
  213.  
  214. #endregion
  215.  
  216. #region Data
  217. // Control points
  218. private Point _controlPoint1;
  219. private Point _controlPoint2;
  220. private bool _isSpecified;
  221. private bool _isDirty;
  222.  
  223. // The parameter that corresponds to the most recent time
  224. private double _parameter;
  225.  
  226. // Cached coefficients
  227. private double _Bx; // 3*points[0].X
  228. private double _Cx; // 3*points[1].X
  229. private double _Cx_Bx; // 2*(Cx - Bx)
  230. private double _three_Cx; // 3 - Cx
  231.  
  232. private double _By; // 3*points[0].Y
  233. private double _Cy; // 3*points[1].Y
  234.  
  235. // constants
  236. private const double accuracy = .001; // 1/3 the desired accuracy in X
  237. private const double fuzz = .000001; // computational zero
  238.  
  239. #endregion
  240. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement