MathUtils.cs 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated January 1, 2020. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2020, Esoteric Software LLC
  6. *
  7. * Integration of the Spine Runtimes into software or otherwise creating
  8. * derivative works of the Spine Runtimes is permitted under the terms and
  9. * conditions of Section 2 of the Spine Editor License Agreement:
  10. * http://esotericsoftware.com/spine-editor-license
  11. *
  12. * Otherwise, it is permitted to integrate the Spine Runtimes into software
  13. * or otherwise create derivative works of the Spine Runtimes (collectively,
  14. * "Products"), provided that each user of the Products must obtain their own
  15. * Spine Editor license and redistribution of the Products in any form must
  16. * include this license and copyright notice.
  17. *
  18. * THE SPINE RUNTIMES ARE PROVIDED BY ESOTERIC SOFTWARE LLC "AS IS" AND ANY
  19. * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  20. * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  21. * DISCLAIMED. IN NO EVENT SHALL ESOTERIC SOFTWARE LLC BE LIABLE FOR ANY
  22. * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  23. * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES,
  24. * BUSINESS INTERRUPTION, OR LOSS OF USE, DATA, OR PROFITS) HOWEVER CAUSED AND
  25. * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  26. * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  27. * THE SPINE RUNTIMES, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  28. *****************************************************************************/
  29. //#define USE_FAST_SIN_COS_ATAN2_APPROXIMATIONS
  30. using System;
  31. namespace Spine {
  32. public static class MathUtils {
  33. public const float PI = 3.1415927f;
  34. public const float PI2 = PI * 2;
  35. public const float RadDeg = 180f / PI;
  36. public const float DegRad = PI / 180;
  37. static Random random = new Random();
  38. #if USE_FAST_SIN_COS_ATAN2_APPROXIMATIONS
  39. const int SIN_BITS = 14; // 16KB. Adjust for accuracy.
  40. const int SIN_MASK = ~(-1 << SIN_BITS);
  41. const int SIN_COUNT = SIN_MASK + 1;
  42. const float RadFull = PI * 2;
  43. const float DegFull = 360;
  44. const float RadToIndex = SIN_COUNT / RadFull;
  45. const float DegToIndex = SIN_COUNT / DegFull;
  46. static float[] sin = new float[SIN_COUNT];
  47. static MathUtils () {
  48. for (int i = 0; i < SIN_COUNT; i++)
  49. sin[i] = (float)Math.Sin((i + 0.5f) / SIN_COUNT * RadFull);
  50. for (int i = 0; i < 360; i += 90)
  51. sin[(int)(i * DegToIndex) & SIN_MASK] = (float)Math.Sin(i * DegRad);
  52. }
  53. /// <summary>Returns the sine of a given angle in radians from a lookup table.</summary>
  54. static public float Sin (float radians) {
  55. return sin[(int)(radians * RadToIndex) & SIN_MASK];
  56. }
  57. /// <summary>Returns the cosine of a given angle in radians from a lookup table.</summary>
  58. static public float Cos (float radians) {
  59. return sin[(int)((radians + PI / 2) * RadToIndex) & SIN_MASK];
  60. }
  61. /// <summary>Returns the sine of a given angle in degrees from a lookup table.</summary>
  62. static public float SinDeg (float degrees) {
  63. return sin[(int)(degrees * DegToIndex) & SIN_MASK];
  64. }
  65. /// <summary>Returns the cosine of a given angle in degrees from a lookup table.</summary>
  66. static public float CosDeg (float degrees) {
  67. return sin[(int)((degrees + 90) * DegToIndex) & SIN_MASK];
  68. }
  69. /// <summary>Returns atan2 in radians, faster but less accurate than Math.Atan2. Average error of 0.00231 radians (0.1323
  70. /// degrees), largest error of 0.00488 radians (0.2796 degrees).</summary>
  71. static public float Atan2 (float y, float x) {
  72. if (x == 0f) {
  73. if (y > 0f) return PI / 2;
  74. if (y == 0f) return 0f;
  75. return -PI / 2;
  76. }
  77. float atan, z = y / x;
  78. if (Math.Abs(z) < 1f) {
  79. atan = z / (1f + 0.28f * z * z);
  80. if (x < 0f) return atan + (y < 0f ? -PI : PI);
  81. return atan;
  82. }
  83. atan = PI / 2 - z / (z * z + 0.28f);
  84. return y < 0f ? atan - PI : atan;
  85. }
  86. #else
  87. /// <summary>Returns the sine of a given angle in radians.</summary>
  88. static public float Sin (float radians) {
  89. return (float)Math.Sin(radians);
  90. }
  91. /// <summary>Returns the cosine of a given angle in radians.</summary>
  92. static public float Cos (float radians) {
  93. return (float)Math.Cos(radians);
  94. }
  95. /// <summary>Returns the sine of a given angle in degrees.</summary>
  96. static public float SinDeg (float degrees) {
  97. return (float)Math.Sin(degrees * DegRad);
  98. }
  99. /// <summary>Returns the cosine of a given angle in degrees.</summary>
  100. static public float CosDeg (float degrees) {
  101. return (float)Math.Cos(degrees * DegRad);
  102. }
  103. /// <summary>Returns the atan2 using Math.Atan2.</summary>
  104. static public float Atan2 (float y, float x) {
  105. return (float)Math.Atan2(y, x);
  106. }
  107. #endif
  108. static public float Clamp (float value, float min, float max) {
  109. if (value < min) return min;
  110. if (value > max) return max;
  111. return value;
  112. }
  113. static public float RandomTriangle(float min, float max) {
  114. return RandomTriangle(min, max, (min + max) * 0.5f);
  115. }
  116. static public float RandomTriangle(float min, float max, float mode) {
  117. float u = (float)random.NextDouble();
  118. float d = max - min;
  119. if (u <= (mode - min) / d) return min + (float)Math.Sqrt(u * d * (mode - min));
  120. return max - (float)Math.Sqrt((1 - u) * d * (max - mode));
  121. }
  122. }
  123. public abstract class IInterpolation {
  124. public static IInterpolation Pow2 = new Pow(2);
  125. public static IInterpolation Pow2Out = new PowOut(2);
  126. protected abstract float Apply(float a);
  127. public float Apply(float start, float end, float a) {
  128. return start + (end - start) * Apply(a);
  129. }
  130. }
  131. public class Pow: IInterpolation {
  132. public float Power { get; set; }
  133. public Pow(float power) {
  134. Power = power;
  135. }
  136. protected override float Apply(float a) {
  137. if (a <= 0.5f) return (float)Math.Pow(a * 2, Power) / 2;
  138. return (float)Math.Pow((a - 1) * 2, Power) / (Power % 2 == 0 ? -2 : 2) + 1;
  139. }
  140. }
  141. public class PowOut : Pow {
  142. public PowOut(float power) : base(power) {
  143. }
  144. protected override float Apply(float a) {
  145. return (float)Math.Pow(a - 1, Power) * (Power % 2 == 0 ? -1 : 1) + 1;
  146. }
  147. }
  148. }