MathHelper.cs 9.9 KB

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