MathHelper.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342
  1. #region --- License ---
  2. /* Licensed under the MIT/X11 license.
  3. * Copyright (c) 2006-2008 the OpenTK Team.
  4. * This notice may not be removed from any source distribution.
  5. * See license.txt for licensing detailed licensing details.
  6. *
  7. * Contributions by Andy Gill, James Talton and Georg Wächter.
  8. */
  9. #endregion
  10. using System;
  11. namespace AtomicEngine
  12. {
  13. /// <summary>
  14. /// Contains common mathematical functions and constants.
  15. /// </summary>
  16. public static class MathHelper
  17. {
  18. #region Fields
  19. /// <summary>
  20. /// Defines the value of Pi as a <see cref="System.Single"/>.
  21. /// </summary>
  22. public const float Pi = 3.141592653589793238462643383279502884197169399375105820974944592307816406286208998628034825342117067982148086513282306647093844609550582231725359408128481117450284102701938521105559644622948954930382f;
  23. /// <summary>
  24. /// Defines the value of Pi divided by two as a <see cref="System.Single"/>.
  25. /// </summary>
  26. public const float PiOver2 = Pi / 2;
  27. /// <summary>
  28. /// Defines the value of Pi divided by three as a <see cref="System.Single"/>.
  29. /// </summary>
  30. public const float PiOver3 = Pi / 3;
  31. /// <summary>
  32. /// Definesthe value of Pi divided by four as a <see cref="System.Single"/>.
  33. /// </summary>
  34. public const float PiOver4 = Pi / 4;
  35. /// <summary>
  36. /// Defines the value of Pi divided by six as a <see cref="System.Single"/>.
  37. /// </summary>
  38. public const float PiOver6 = Pi / 6;
  39. /// <summary>
  40. /// Defines the value of Pi multiplied by two as a <see cref="System.Single"/>.
  41. /// </summary>
  42. public const float TwoPi = 2 * Pi;
  43. /// <summary>
  44. /// Defines the value of Pi multiplied by 3 and divided by two as a <see cref="System.Single"/>.
  45. /// </summary>
  46. public const float ThreePiOver2 = 3 * Pi / 2;
  47. /// <summary>
  48. /// Defines the value of E as a <see cref="System.Single"/>.
  49. /// </summary>
  50. public const float E = 2.71828182845904523536f;
  51. /// <summary>
  52. /// Defines the base-10 logarithm of E.
  53. /// </summary>
  54. public const float Log10E = 0.434294482f;
  55. /// <summary>
  56. /// Defines the base-2 logarithm of E.
  57. /// </summary>
  58. public const float Log2E = 1.442695041f;
  59. public static readonly float DTORF = Pi / 180.0f;
  60. #endregion
  61. #region Public Members
  62. #region NextPowerOfTwo
  63. /// <summary>
  64. /// Returns the next power of two that is larger than the specified number.
  65. /// </summary>
  66. /// <param name="n">The specified number.</param>
  67. /// <returns>The next power of two.</returns>
  68. public static long NextPowerOfTwo(long n)
  69. {
  70. if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive.");
  71. return (long)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2)));
  72. }
  73. /// <summary>
  74. /// Returns the next power of two that is larger than the specified number.
  75. /// </summary>
  76. /// <param name="n">The specified number.</param>
  77. /// <returns>The next power of two.</returns>
  78. public static int NextPowerOfTwo(int n)
  79. {
  80. if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive.");
  81. return (int)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2)));
  82. }
  83. /// <summary>
  84. /// Returns the next power of two that is larger than the specified number.
  85. /// </summary>
  86. /// <param name="n">The specified number.</param>
  87. /// <returns>The next power of two.</returns>
  88. public static float NextPowerOfTwo(float n)
  89. {
  90. if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive.");
  91. return (float)System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2)));
  92. }
  93. /// <summary>
  94. /// Returns the next power of two that is larger than the specified number.
  95. /// </summary>
  96. /// <param name="n">The specified number.</param>
  97. /// <returns>The next power of two.</returns>
  98. public static double NextPowerOfTwo(double n)
  99. {
  100. if (n < 0) throw new ArgumentOutOfRangeException("n", "Must be positive.");
  101. return System.Math.Pow(2, System.Math.Ceiling(System.Math.Log((double)n, 2)));
  102. }
  103. #endregion
  104. #region Factorial
  105. /// <summary>Calculates the factorial of a given natural number.
  106. /// </summary>
  107. /// <param name="n">The number.</param>
  108. /// <returns>n!</returns>
  109. public static long Factorial(int n)
  110. {
  111. long result = 1;
  112. for (; n > 1; n--)
  113. result *= n;
  114. return result;
  115. }
  116. #endregion
  117. #region BinomialCoefficient
  118. /// <summary>
  119. /// Calculates the binomial coefficient <paramref name="n"/> above <paramref name="k"/>.
  120. /// </summary>
  121. /// <param name="n">The n.</param>
  122. /// <param name="k">The k.</param>
  123. /// <returns>n! / (k! * (n - k)!)</returns>
  124. public static long BinomialCoefficient(int n, int k)
  125. {
  126. return Factorial(n) / (Factorial(k) * Factorial(n - k));
  127. }
  128. #endregion
  129. #region InverseSqrtFast
  130. /// <summary>
  131. /// Returns an approximation of the inverse square root of left number.
  132. /// </summary>
  133. /// <param name="x">A number.</param>
  134. /// <returns>An approximation of the inverse square root of the specified number, with an upper error bound of 0.001</returns>
  135. /// <remarks>
  136. /// This is an improved implementation of the the method known as Carmack's inverse square root
  137. /// which is found in the Quake III source code. This implementation comes from
  138. /// http://www.codemaestro.com/reviews/review00000105.html. For the history of this method, see
  139. /// http://www.beyond3d.com/content/articles/8/
  140. /// </remarks>
  141. public static float InverseSqrtFast(float x)
  142. {
  143. unsafe
  144. {
  145. float xhalf = 0.5f * x;
  146. int i = *(int*)&x; // Read bits as integer.
  147. i = 0x5f375a86 - (i >> 1); // Make an initial guess for Newton-Raphson approximation
  148. x = *(float*)&i; // Convert bits back to float
  149. x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step.
  150. return x;
  151. }
  152. }
  153. /// <summary>
  154. /// Returns an approximation of the inverse square root of left number.
  155. /// </summary>
  156. /// <param name="x">A number.</param>
  157. /// <returns>An approximation of the inverse square root of the specified number, with an upper error bound of 0.001</returns>
  158. /// <remarks>
  159. /// This is an improved implementation of the the method known as Carmack's inverse square root
  160. /// which is found in the Quake III source code. This implementation comes from
  161. /// http://www.codemaestro.com/reviews/review00000105.html. For the history of this method, see
  162. /// http://www.beyond3d.com/content/articles/8/
  163. /// </remarks>
  164. public static double InverseSqrtFast(double x)
  165. {
  166. return InverseSqrtFast((float)x);
  167. // TODO: The following code is wrong. Fix it, to improve precision.
  168. #if false
  169. unsafe
  170. {
  171. double xhalf = 0.5f * x;
  172. int i = *(int*)&x; // Read bits as integer.
  173. i = 0x5f375a86 - (i >> 1); // Make an initial guess for Newton-Raphson approximation
  174. x = *(float*)&i; // Convert bits back to float
  175. x = x * (1.5f - xhalf * x * x); // Perform left single Newton-Raphson step.
  176. return x;
  177. }
  178. #endif
  179. }
  180. #endregion
  181. #region DegreesToRadians
  182. /// <summary>
  183. /// Convert degrees to radians
  184. /// </summary>
  185. /// <param name="degrees">An angle in degrees</param>
  186. /// <returns>The angle expressed in radians</returns>
  187. public static float DegreesToRadians(float degrees)
  188. {
  189. const float degToRad = (float)System.Math.PI / 180.0f;
  190. return degrees * degToRad;
  191. }
  192. /// <summary>
  193. /// Convert radians to degrees
  194. /// </summary>
  195. /// <param name="radians">An angle in radians</param>
  196. /// <returns>The angle expressed in degrees</returns>
  197. public static float RadiansToDegrees(float radians)
  198. {
  199. const float radToDeg = 180.0f / (float)System.Math.PI;
  200. return radians * radToDeg;
  201. }
  202. /// <summary>
  203. /// Convert degrees to radians
  204. /// </summary>
  205. /// <param name="degrees">An angle in degrees</param>
  206. /// <returns>The angle expressed in radians</returns>
  207. public static double DegreesToRadians(double degrees)
  208. {
  209. const double degToRad = System.Math.PI / 180.0;
  210. return degrees * degToRad;
  211. }
  212. /// <summary>
  213. /// Convert radians to degrees
  214. /// </summary>
  215. /// <param name="radians">An angle in radians</param>
  216. /// <returns>The angle expressed in degrees</returns>
  217. public static double RadiansToDegrees(double radians)
  218. {
  219. const double radToDeg = 180.0 / System.Math.PI;
  220. return radians * radToDeg;
  221. }
  222. #endregion
  223. #region Swap
  224. /// <summary>
  225. /// Swaps two double values.
  226. /// </summary>
  227. /// <param name="a">The first value.</param>
  228. /// <param name="b">The second value.</param>
  229. public static void Swap(ref double a, ref double b)
  230. {
  231. double temp = a;
  232. a = b;
  233. b = temp;
  234. }
  235. /// <summary>
  236. /// Swaps two float values.
  237. /// </summary>
  238. /// <param name="a">The first value.</param>
  239. /// <param name="b">The second value.</param>
  240. public static void Swap(ref float a, ref float b)
  241. {
  242. float temp = a;
  243. a = b;
  244. b = temp;
  245. }
  246. #endregion
  247. #endregion
  248. /// <summary>
  249. /// Clamp a float to a range.
  250. /// </summary>
  251. public static float Clamp(float value, float min, float max)
  252. {
  253. if (value < min)
  254. return min;
  255. else if (value > max)
  256. return max;
  257. else
  258. return value;
  259. }
  260. public static float Lerp(float lhs, float rhs, float t)
  261. {
  262. return lhs * (1.0f - t) + rhs * t;
  263. }
  264. public static float WrapAngle(float angle)
  265. {
  266. angle = (float)Math.IEEERemainder((double)angle, 6.2831854820251465);
  267. if (angle <= -3.14159274f)
  268. {
  269. angle += 6.28318548f;
  270. }
  271. else
  272. {
  273. if (angle > 3.14159274f)
  274. {
  275. angle -= 6.28318548f;
  276. }
  277. }
  278. return angle;
  279. }
  280. public static float CatmullRom(float value1, float value2, float value3, float value4, float amount)
  281. {
  282. // Using formula from http://www.mvps.org/directx/articles/catmull/
  283. // Internally using doubles not to lose precission
  284. double amountSquared = amount * amount;
  285. double amountCubed = amountSquared * amount;
  286. return (float)(0.5 * (2.0 * value2 +
  287. (value3 - value1) * amount +
  288. (2.0 * value1 - 5.0 * value2 + 4.0 * value3 - value4) * amountSquared +
  289. (3.0 * value2 - value1 - 3.0 * value3 + value4) * amountCubed));
  290. }
  291. }
  292. }