babylon.math.scalar.ts 12 KB

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