babylon.math.scalar.ts 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. module BABYLON {
  2. export class Scalar {
  3. /**
  4. * Two pi constants convenient for computation.
  5. */
  6. public static TwoPi: number = Math.PI * 2;
  7. /**
  8. * Boolean : true if the absolute difference between a and b is lower than epsilon (default = 1.401298E-45)
  9. */
  10. public static WithinEpsilon(a: number, b: number, epsilon: number = 1.401298E-45): boolean {
  11. var num = a - b;
  12. return -epsilon <= num && num <= epsilon;
  13. }
  14. /**
  15. * Returns a string : the upper case translation of the number i to hexadecimal.
  16. */
  17. public static ToHex(i: number): string {
  18. var str = i.toString(16);
  19. if (i <= 15) {
  20. return ("0" + str).toUpperCase();
  21. }
  22. return str.toUpperCase();
  23. }
  24. /**
  25. * Returns -1 if value is negative and +1 is value is positive.
  26. * Returns the value itself if it's equal to zero.
  27. */
  28. public static Sign(value: number): number {
  29. value = +value; // convert to a number
  30. if (value === 0 || isNaN(value))
  31. return value;
  32. return value > 0 ? 1 : -1;
  33. }
  34. /**
  35. * Returns the value itself if it's between min and max.
  36. * Returns min if the value is lower than min.
  37. * Returns max if the value is greater than max.
  38. */
  39. public static Clamp(value: number, min = 0, max = 1): number {
  40. return Math.min(max, Math.max(min, value));
  41. }
  42. /**
  43. * Returns the log2 of value.
  44. */
  45. public static Log2(value: number): number {
  46. return Math.log(value) * Math.LOG2E;
  47. }
  48. /**
  49. * Loops the value, so that it is never larger than length and never smaller than 0.
  50. *
  51. * This is similar to the modulo operator but it works with floating point numbers.
  52. * For example, using 3.0 for t and 2.5 for length, the result would be 0.5.
  53. * With t = 5 and length = 2.5, the result would be 0.0.
  54. * Note, however, that the behaviour is not defined for negative numbers as it is for the modulo operator
  55. */
  56. public static Repeat(value: number, length: number): number {
  57. return value - Math.floor(value / length) * length;
  58. }
  59. /**
  60. * Normalize the value between 0.0 and 1.0 using min and max values
  61. */
  62. public static Normalize(value: number, min: number, max: number): number {
  63. return (value - min) / (max - min);
  64. }
  65. /**
  66. * Denormalize the value from 0.0 and 1.0 using min and max values
  67. */
  68. public static Denormalize(normalized: number, min: number, max: number): number {
  69. return (normalized * (max - min) + min);
  70. }
  71. /**
  72. * Calculates the shortest difference between two given angles given in degrees.
  73. */
  74. public static DeltaAngle(current: number, target: number): number {
  75. var num: number = Scalar.Repeat(target - current, 360.0);
  76. if (num > 180.0) {
  77. num -= 360.0;
  78. }
  79. return num;
  80. }
  81. /**
  82. * PingPongs the value t, so that it is never larger than length and never smaller than 0.
  83. *
  84. * The returned value will move back and forth between 0 and length
  85. */
  86. public static PingPong(tx: number, length: number): number {
  87. var t: number = Scalar.Repeat(tx, length * 2.0);
  88. return length - Math.abs(t - length);
  89. }
  90. /**
  91. * Interpolates between min and max with smoothing at the limits.
  92. *
  93. * This function interpolates between min and max in a similar way to Lerp. However, the interpolation will gradually speed up
  94. * from the start and slow down toward the end. This is useful for creating natural-looking animation, fading and other transitions.
  95. */
  96. public static SmoothStep(from: number, to: number, tx: number): number {
  97. var t: number = Scalar.Clamp(tx);
  98. t = -2.0 * t * t * t + 3.0 * t * t;
  99. return to * t + from * (1.0 - t);
  100. }
  101. /**
  102. * Moves a value current towards target.
  103. *
  104. * This is essentially the same as Mathf.Lerp but instead the function will ensure that the speed never exceeds maxDelta.
  105. * Negative values of maxDelta pushes the value away from target.
  106. */
  107. public static MoveTowards(current: number, target: number, maxDelta: number): number {
  108. var result: number = 0;
  109. if (Math.abs(target - current) <= maxDelta) {
  110. result = target;
  111. } else {
  112. result = current + Scalar.Sign(target - current) * maxDelta;
  113. }
  114. return result;
  115. }
  116. /**
  117. * Same as MoveTowards but makes sure the values interpolate correctly when they wrap around 360 degrees.
  118. *
  119. * Variables current and target are assumed to be in degrees. For optimization reasons, negative values of maxDelta
  120. * are not supported and may cause oscillation. To push current away from a target angle, add 180 to that angle instead.
  121. */
  122. public static MoveTowardsAngle(current: number, target: number, maxDelta: number): number {
  123. var num: number = Scalar.DeltaAngle(current, target);
  124. var result: number = 0;
  125. if (-maxDelta < num && num < maxDelta) {
  126. result = target;
  127. } else {
  128. target = current + num;
  129. result = Scalar.MoveTowards(current, target, maxDelta);
  130. }
  131. return result;
  132. }
  133. /**
  134. * Creates a new scalar with values linearly interpolated of "amount" between the start scalar and the end scalar.
  135. */
  136. public static Lerp(start: number, end: number, amount: number): number {
  137. return start + ((end - start) * amount);
  138. }
  139. /**
  140. * Same as Lerp but makes sure the values interpolate correctly when they wrap around 360 degrees.
  141. * The parameter t is clamped to the range [0, 1]. Variables a and b are assumed to be in degrees.
  142. */
  143. public static LerpAngle(start: number, end: number, amount: number): number {
  144. var num: number = Scalar.Repeat(end - start, 360.0);
  145. if (num > 180.0) {
  146. num -= 360.0;
  147. }
  148. return start + num * Scalar.Clamp(amount);
  149. }
  150. /**
  151. * Calculates the linear parameter t that produces the interpolant value within the range [a, b].
  152. */
  153. public static InverseLerp(a: number, b: number, value: number): number {
  154. var result: number = 0;
  155. if (a != b) {
  156. result = Scalar.Clamp((value - a) / (b - a));
  157. } else {
  158. result = 0.0;
  159. }
  160. return result;
  161. }
  162. /**
  163. * Returns a new scalar located for "amount" (float) on the Hermite spline defined by the scalars "value1", "value3", "tangent1", "tangent2".
  164. */
  165. public static Hermite(value1: number, tangent1: number, value2: number, tangent2: number, amount: number): number {
  166. var squared = amount * amount;
  167. var cubed = amount * squared;
  168. var part1 = ((2.0 * cubed) - (3.0 * squared)) + 1.0;
  169. var part2 = (-2.0 * cubed) + (3.0 * squared);
  170. var part3 = (cubed - (2.0 * squared)) + amount;
  171. var part4 = cubed - squared;
  172. return (((value1 * part1) + (value2 * part2)) + (tangent1 * part3)) + (tangent2 * part4);
  173. }
  174. /**
  175. * Returns a random float number between and min and max values
  176. */
  177. public static RandomRange(min: number, max: number): number {
  178. if (min === max) return min;
  179. return ((Math.random() * (max - min)) + min);
  180. }
  181. /**
  182. * This function returns percentage of a number in a given range.
  183. *
  184. * RangeToPercent(40,20,60) will return 0.5 (50%)
  185. * RangeToPercent(34,0,100) will return 0.34 (34%)
  186. */
  187. public static RangeToPercent(number: number, min: number, max: number): number {
  188. return ((number - min) / (max - min));
  189. }
  190. /**
  191. * This function returns number that corresponds to the percentage in a given range.
  192. *
  193. * PercentToRange(0.34,0,100) will return 34.
  194. */
  195. public static PercentToRange(percent: number, min: number, max: number): number {
  196. return ((max - min) * percent + min);
  197. }
  198. /**
  199. * Returns the angle converted to equivalent value between -Math.PI and Math.PI radians.
  200. * @param angle The angle to normalize in radian.
  201. * @return The converted angle.
  202. */
  203. public static NormalizeRadians(angle: number): number {
  204. // More precise but slower version kept for reference.
  205. // angle = angle % Tools.TwoPi;
  206. // angle = (angle + Tools.TwoPi) % Tools.TwoPi;
  207. //if (angle > Math.PI) {
  208. // angle -= Tools.TwoPi;
  209. //}
  210. angle -= (Scalar.TwoPi * Math.floor((angle + Math.PI) / Scalar.TwoPi));
  211. return angle;
  212. }
  213. }
  214. }