Easing.cs 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. Copyright (c) 2014, Lars Brubaker
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. 1. Redistributions of source code must retain the above copyright notice, this
  7. list of conditions and the following disclaimer.
  8. 2. Redistributions in binary form must reproduce the above copyright notice,
  9. this list of conditions and the following disclaimer in the documentation
  10. and/or other materials provided with the distribution.
  11. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  12. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  13. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  14. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
  15. ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  16. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  17. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  18. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  19. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  20. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  21. The views and conclusions contained in the software and documentation are those
  22. of the authors and should not be interpreted as representing official policies,
  23. either expressed or implied, of the FreeBSD Project.
  24. */
  25. using System;
  26. namespace MatterHackers.VectorMath
  27. {
  28. /*
  29. * Functions taken from Tween.js - Licensed under the MIT license
  30. * at https://github.com/sole/tween.js
  31. */
  32. public class Easing
  33. {
  34. public enum EaseType
  35. {
  36. Linear,
  37. Quadratic,
  38. Cubic,
  39. Quartic,
  40. Quintic,
  41. Sinusoidal,
  42. }
  43. public enum EaseOption
  44. {
  45. In,
  46. Out,
  47. InOut
  48. }
  49. /// <summary>
  50. /// Iteretively solve for the required input given a known output
  51. /// </summary>
  52. /// <param name="function">The easing function (must be monotonic)</param>
  53. /// <param name="output">The output value needing an input (0 to 1)</param>
  54. /// <param name="errorTolerance">When this error is achived evaluation will stop</param>
  55. /// <returns></returns>
  56. public static double CalculateInverse(Func<double, double> function, double output, double errorTolerance = .000000001)
  57. {
  58. if (output >= 0 && output <= 1)
  59. {
  60. var start = 0.0;
  61. var end = 1.0;
  62. var mid = .5;
  63. var iterations = 0;
  64. var error = 1.0;
  65. while (error > errorTolerance && iterations < 128)
  66. {
  67. iterations++;
  68. var delta = end - start;
  69. mid = start + delta / 2;
  70. var testOutput = function(mid);
  71. error = Math.Abs(output - testOutput);
  72. if (error <= errorTolerance)
  73. {
  74. return mid;
  75. }
  76. if (testOutput > output)
  77. {
  78. end = mid;
  79. }
  80. else
  81. {
  82. start = mid;
  83. }
  84. }
  85. return mid;
  86. }
  87. return 0;
  88. }
  89. public static Func<double, double> GetEasingFunction(EaseType easeType, EaseOption easeOption)
  90. {
  91. switch (easeType)
  92. {
  93. case EaseType.Quadratic:
  94. switch (easeOption)
  95. {
  96. case EaseOption.In:
  97. return Quadratic.In;
  98. case EaseOption.Out:
  99. return Quadratic.Out;
  100. case EaseOption.InOut:
  101. return Quadratic.InOut;
  102. }
  103. break;
  104. case EaseType.Cubic:
  105. switch (easeOption)
  106. {
  107. case EaseOption.In:
  108. return Cubic.In;
  109. case EaseOption.Out:
  110. return Cubic.Out;
  111. case EaseOption.InOut:
  112. return Cubic.InOut;
  113. }
  114. break;
  115. case EaseType.Quartic:
  116. switch (easeOption)
  117. {
  118. case EaseOption.In:
  119. return Quartic.In;
  120. case EaseOption.Out:
  121. return Quartic.Out;
  122. case EaseOption.InOut:
  123. return Quartic.InOut;
  124. }
  125. break;
  126. case EaseType.Quintic:
  127. switch (easeOption)
  128. {
  129. case EaseOption.In:
  130. return Quintic.In;
  131. case EaseOption.Out:
  132. return Quintic.Out;
  133. case EaseOption.InOut:
  134. return Quintic.InOut;
  135. }
  136. break;
  137. case EaseType.Sinusoidal:
  138. switch (easeOption)
  139. {
  140. case EaseOption.In:
  141. return Sinusoidal.In;
  142. case EaseOption.Out:
  143. return Sinusoidal.Out;
  144. case EaseOption.InOut:
  145. return Sinusoidal.InOut;
  146. }
  147. break;
  148. }
  149. return Linear;
  150. }
  151. public static double Calculate(EaseType easeType, EaseOption easeOption, double k)
  152. {
  153. return GetEasingFunction(easeType, easeOption)(k);
  154. }
  155. /// <summary>
  156. /// Given the easing functions output, find the approximate input that would generate it.
  157. /// </summary>
  158. /// <param name="easeType">The easing type</param>
  159. /// <param name="easeOption">The easing option</param>
  160. /// <param name="k">The output value to find the input for</param>
  161. /// <returns></returns>
  162. public static double CalculateInverse(EaseType easeType, EaseOption easeOption, double k, double errorTolerance = .000000001)
  163. {
  164. if (easeType == EaseType.Linear)
  165. {
  166. return k;
  167. }
  168. return CalculateInverse(GetEasingFunction(easeType, easeOption), k, errorTolerance);
  169. }
  170. public static double Linear(double k)
  171. {
  172. return k;
  173. }
  174. public class Quadratic
  175. {
  176. public static double In(double k)
  177. {
  178. return k * k;
  179. }
  180. public static double Out(double k)
  181. {
  182. return k * (2f - k);
  183. }
  184. public static double InOut(double k)
  185. {
  186. if ((k *= 2f) < 1f)
  187. {
  188. return 0.5f * k * k;
  189. }
  190. return -0.5f * ((k -= 1f) * (k - 2f) - 1f);
  191. }
  192. }
  193. public class Cubic
  194. {
  195. public static double In(double k)
  196. {
  197. return k * k * k;
  198. }
  199. public static double Out(double k)
  200. {
  201. return 1f + ((k -= 1f) * k * k);
  202. }
  203. public static double InOut(double k)
  204. {
  205. if ((k *= 2f) < 1f)
  206. {
  207. return 0.5f * k * k * k;
  208. }
  209. return 0.5f * ((k -= 2f) * k * k + 2f);
  210. }
  211. }
  212. public class Quartic
  213. {
  214. public static double In(double k)
  215. {
  216. return k * k * k * k;
  217. }
  218. public static double Out(double k)
  219. {
  220. return 1f - ((k -= 1f) * k * k * k);
  221. }
  222. public static double InOut(double k)
  223. {
  224. if ((k *= 2f) < 1f)
  225. {
  226. return 0.5f * k * k * k * k;
  227. }
  228. return -0.5f * ((k -= 2f) * k * k * k - 2f);
  229. }
  230. }
  231. public class Quintic
  232. {
  233. public static double In(double k)
  234. {
  235. return k * k * k * k * k;
  236. }
  237. public static double Out(double k)
  238. {
  239. return 1f + ((k -= 1f) * k * k * k * k);
  240. }
  241. public static double InOut(double k)
  242. {
  243. if ((k *= 2f) < 1f)
  244. {
  245. return 0.5f * k * k * k * k * k;
  246. }
  247. return 0.5f * ((k -= 2f) * k * k * k * k + 2f);
  248. }
  249. }
  250. public class Sinusoidal
  251. {
  252. public static double In(double k)
  253. {
  254. return 1f - Math.Cos(k * Math.PI / 2f);
  255. }
  256. public static double Out(double k)
  257. {
  258. return Math.Sin(k * Math.PI / 2f);
  259. }
  260. public static double InOut(double k)
  261. {
  262. return 0.5f * (1f - Math.Cos(Math.PI * k));
  263. }
  264. }
  265. public class Exponential
  266. {
  267. public static double In(double k)
  268. {
  269. return k == 0f ? 0f : Math.Pow(1024f, k - 1f);
  270. }
  271. public static double Out(double k)
  272. {
  273. return k == 1f ? 1f : 1f - Math.Pow(2f, -10f * k);
  274. }
  275. public static double InOut(double k)
  276. {
  277. if (k == 0f)
  278. {
  279. return 0f;
  280. }
  281. if (k == 1f)
  282. {
  283. return 1f;
  284. }
  285. if ((k *= 2f) < 1f)
  286. {
  287. return 0.5f * Math.Pow(1024f, k - 1f);
  288. }
  289. return 0.5f * (-Math.Pow(2f, -10f * (k - 1f)) + 2f);
  290. }
  291. }
  292. public class Circular
  293. {
  294. public static double In(double k)
  295. {
  296. return 1f - Math.Sqrt(1f - k * k);
  297. }
  298. public static double Out(double k)
  299. {
  300. return Math.Sqrt(1f - ((k -= 1f) * k));
  301. }
  302. public static double InOut(double k)
  303. {
  304. if ((k *= 2f) < 1f)
  305. {
  306. return -0.5f * (Math.Sqrt(1f - k * k) - 1);
  307. }
  308. return 0.5f * (Math.Sqrt(1f - (k -= 2f) * k) + 1f);
  309. }
  310. }
  311. public class Elastic
  312. {
  313. public static double In(double k)
  314. {
  315. if (k == 0)
  316. {
  317. return 0;
  318. }
  319. if (k == 1)
  320. {
  321. return 1;
  322. }
  323. return -Math.Pow(2f, 10f * (k -= 1f)) * Math.Sin((k - 0.1f) * (2f * Math.PI) / 0.4f);
  324. }
  325. public static double Out(double k)
  326. {
  327. if (k == 0)
  328. {
  329. return 0;
  330. }
  331. if (k == 1)
  332. {
  333. return 1;
  334. }
  335. return Math.Pow(2f, -10f * k) * Math.Sin((k - 0.1f) * (2f * Math.PI) / 0.4f) + 1f;
  336. }
  337. public static double InOut(double k)
  338. {
  339. if ((k *= 2f) < 1f)
  340. {
  341. return -0.5f * Math.Pow(2f, 10f * (k -= 1f)) * Math.Sin((k - 0.1f) * (2f * Math.PI) / 0.4f);
  342. }
  343. return Math.Pow(2f, -10f * (k -= 1f)) * Math.Sin((k - 0.1f) * (2f * Math.PI) / 0.4f) * 0.5f + 1f;
  344. }
  345. }
  346. public class Back
  347. {
  348. private static readonly double S = 1.70158f;
  349. private static readonly double S2 = 2.5949095f;
  350. public static double In(double k)
  351. {
  352. return k * k * ((S + 1f) * k - S);
  353. }
  354. public static double Out(double k)
  355. {
  356. return (k -= 1f) * k * ((S + 1f) * k + S) + 1f;
  357. }
  358. public static double InOut(double k)
  359. {
  360. if ((k *= 2f) < 1f)
  361. {
  362. return 0.5f * (k * k * ((S2 + 1f) * k - S2));
  363. }
  364. return 0.5f * ((k -= 2f) * k * ((S2 + 1f) * k + S2) + 2f);
  365. }
  366. }
  367. public class Bounce
  368. {
  369. public static double In(double k)
  370. {
  371. return 1f - Out(1f - k);
  372. }
  373. public static double Out(double k)
  374. {
  375. if (k < (1f / 2.75f))
  376. {
  377. return 7.5625f * k * k;
  378. }
  379. else if (k < (2f / 2.75f))
  380. {
  381. return 7.5625f * (k -= 1.5f / 2.75f) * k + 0.75f;
  382. }
  383. else if (k < (2.5f / 2.75f))
  384. {
  385. return 7.5625f * (k -= 2.25f / 2.75f) * k + 0.9375f;
  386. }
  387. else
  388. {
  389. return 7.5625f * (k -= 2.625f / 2.75f) * k + 0.984375f;
  390. }
  391. }
  392. public static double InOut(double k)
  393. {
  394. if (k < 0.5f)
  395. {
  396. return In(k * 2f) * 0.5f;
  397. }
  398. return Out(k * 2f - 1f) * 0.5f + 0.5f;
  399. }
  400. }
  401. }
  402. }