MathUtils.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184
  1. /******************************************************************************
  2. * Spine Runtimes License Agreement
  3. * Last updated July 28, 2023. Replaces all prior versions.
  4. *
  5. * Copyright (c) 2013-2023, 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 or
  13. * 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 THE
  27. * 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 InvPI2 = 1 / PI2;
  36. public const float RadDeg = 180f / PI;
  37. public const float DegRad = PI / 180;
  38. static Random random = new Random();
  39. #if USE_FAST_SIN_COS_ATAN2_APPROXIMATIONS
  40. const int SIN_BITS = 14; // 16KB. Adjust for accuracy.
  41. const int SIN_MASK = ~(-1 << SIN_BITS);
  42. const int SIN_COUNT = SIN_MASK + 1;
  43. const float RadFull = PI * 2;
  44. const float DegFull = 360;
  45. const float RadToIndex = SIN_COUNT / RadFull;
  46. const float DegToIndex = SIN_COUNT / DegFull;
  47. static float[] sin = new float[SIN_COUNT];
  48. static MathUtils () {
  49. for (int i = 0; i < SIN_COUNT; i++)
  50. sin[i] = (float)Math.Sin((i + 0.5f) / SIN_COUNT * RadFull);
  51. for (int i = 0; i < 360; i += 90)
  52. sin[(int)(i * DegToIndex) & SIN_MASK] = (float)Math.Sin(i * DegRad);
  53. }
  54. /// <summary>Returns the sine of a given angle in radians from a lookup table.</summary>
  55. static public float Sin (float radians) {
  56. return sin[(int)(radians * RadToIndex) & SIN_MASK];
  57. }
  58. /// <summary>Returns the cosine of a given angle in radians from a lookup table.</summary>
  59. static public float Cos (float radians) {
  60. return sin[(int)((radians + PI / 2) * RadToIndex) & SIN_MASK];
  61. }
  62. /// <summary>Returns the sine of a given angle in degrees from a lookup table.</summary>
  63. static public float SinDeg (float degrees) {
  64. return sin[(int)(degrees * DegToIndex) & SIN_MASK];
  65. }
  66. /// <summary>Returns the cosine of a given angle in degrees from a lookup table.</summary>
  67. static public float CosDeg (float degrees) {
  68. return sin[(int)((degrees + 90) * DegToIndex) & SIN_MASK];
  69. }
  70. static public float Atan2Deg (float y, float x) {
  71. return Atan2(y, x) * RadDeg;
  72. }
  73. /// <summary>Returns atan2 in radians, faster but less accurate than Math.Atan2. Average error of 0.00231 radians (0.1323
  74. /// degrees), largest error of 0.00488 radians (0.2796 degrees).</summary>
  75. static public float Atan2 (float y, float x) {
  76. if (x == 0f) {
  77. if (y > 0f) return PI / 2;
  78. if (y == 0f) return 0f;
  79. return -PI / 2;
  80. }
  81. float atan, z = y / x;
  82. if (Math.Abs(z) < 1f) {
  83. atan = z / (1f + 0.28f * z * z);
  84. if (x < 0f) return atan + (y < 0f ? -PI : PI);
  85. return atan;
  86. }
  87. atan = PI / 2 - z / (z * z + 0.28f);
  88. return y < 0f ? atan - PI : atan;
  89. }
  90. #else
  91. /// <summary>Returns the sine of a given angle in radians.</summary>
  92. static public float Sin (float radians) {
  93. return (float)Math.Sin(radians);
  94. }
  95. /// <summary>Returns the cosine of a given angle in radians.</summary>
  96. static public float Cos (float radians) {
  97. return (float)Math.Cos(radians);
  98. }
  99. /// <summary>Returns the sine of a given angle in degrees.</summary>
  100. static public float SinDeg (float degrees) {
  101. return (float)Math.Sin(degrees * DegRad);
  102. }
  103. /// <summary>Returns the cosine of a given angle in degrees.</summary>
  104. static public float CosDeg (float degrees) {
  105. return (float)Math.Cos(degrees * DegRad);
  106. }
  107. static public float Atan2Deg (float y, float x) {
  108. return (float)Math.Atan2(y, x) * RadDeg;
  109. }
  110. /// <summary>Returns the atan2 using Math.Atan2.</summary>
  111. static public float Atan2 (float y, float x) {
  112. return (float)Math.Atan2(y, x);
  113. }
  114. #endif
  115. static public float Clamp (float value, float min, float max) {
  116. if (value < min) return min;
  117. if (value > max) return max;
  118. return value;
  119. }
  120. static public float RandomTriangle (float min, float max) {
  121. return RandomTriangle(min, max, (min + max) * 0.5f);
  122. }
  123. static public float RandomTriangle (float min, float max, float mode) {
  124. float u = (float)random.NextDouble();
  125. float d = max - min;
  126. if (u <= (mode - min) / d) return min + (float)Math.Sqrt(u * d * (mode - min));
  127. return max - (float)Math.Sqrt((1 - u) * d * (max - mode));
  128. }
  129. }
  130. public abstract class IInterpolation {
  131. public static IInterpolation Pow2 = new Pow(2);
  132. public static IInterpolation Pow2Out = new PowOut(2);
  133. protected abstract float Apply (float a);
  134. public float Apply (float start, float end, float a) {
  135. return start + (end - start) * Apply(a);
  136. }
  137. }
  138. public class Pow : IInterpolation {
  139. public float Power { get; set; }
  140. public Pow (float power) {
  141. Power = power;
  142. }
  143. protected override float Apply (float a) {
  144. if (a <= 0.5f) return (float)Math.Pow(a * 2, Power) / 2;
  145. return (float)Math.Pow((a - 1) * 2, Power) / (Power % 2 == 0 ? -2 : 2) + 1;
  146. }
  147. }
  148. public class PowOut : Pow {
  149. public PowOut (float power) : base(power) {
  150. }
  151. protected override float Apply (float a) {
  152. return (float)Math.Pow(a - 1, Power) * (Power % 2 == 0 ? -1 : 1) + 1;
  153. }
  154. }
  155. }