Paradox Game Engine  v1.0.0 beta06
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Events Macros Pages
MathUtil.cs
Go to the documentation of this file.
1 // Copyright (c) 2014 Silicon Studio Corp. (http://siliconstudio.co.jp)
2 // This file is distributed under MIT License. See LICENSE.md for details.
3 //
4 // -----------------------------------------------------------------------------
5 // Original code from SlimMath project. http://code.google.com/p/slimmath/
6 // Greetings to SlimDX Group. Original code published with the following license:
7 // -----------------------------------------------------------------------------
8 /*
9 * Copyright (c) 2007-2011 SlimDX Group
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this software and associated documentation files (the "Software"), to deal
13 * in the Software without restriction, including without limitation the rights
14 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
15 * copies of the Software, and to permit persons to whom the Software is
16 * furnished to do so, subject to the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
26 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
27 * THE SOFTWARE.
28 */
29 
30 using System;
31 namespace SiliconStudio.Core.Mathematics
32 {
33  public static class MathUtil
34  {
35  /// <summary>
36  /// The value for which all absolute numbers smaller than are considered equal to zero.
37  /// </summary>
38  public const float ZeroTolerance = 1e-6f; // Value a 8x higher than 1.19209290E-07F
39 
40  /// <summary>
41  /// The value for which all absolute numbers smaller than are considered equal to zero.
42  /// </summary>
43  public const double ZeroToleranceDouble = Double.Epsilon*8;
44 
45  /// <summary>
46  /// A value specifying the approximation of π which is 180 degrees.
47  /// </summary>
48  public const float Pi = (float)Math.PI;
49 
50  /// <summary>
51  /// A value specifying the approximation of 2π which is 360 degrees.
52  /// </summary>
53  public const float TwoPi = (float)(2 * Math.PI);
54 
55  /// <summary>
56  /// A value specifying the approximation of π/2 which is 90 degrees.
57  /// </summary>
58  public const float PiOverTwo = (float)(Math.PI / 2);
59 
60  /// <summary>
61  /// A value specifying the approximation of π/4 which is 45 degrees.
62  /// </summary>
63  public const float PiOverFour = (float)(Math.PI / 4);
64 
65  /// <summary>
66  /// Checks if a and b are almost equals, taking into account the magnitude of floating point numbers (unlike <see cref="WithinEpsilon"/> method). See Remarks.
67  /// See remarks.
68  /// </summary>
69  /// <param name="a">The left value to compare.</param>
70  /// <param name="b">The right value to compare.</param>
71  /// <returns><c>true</c> if a almost equal to b, <c>false</c> otherwise</returns>
72  /// <remarks>
73  /// The code is using the technique described by Bruce Dawson in
74  /// <a href="http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/">Comparing Floating point numbers 2012 edition</a>.
75  /// </remarks>
76  public unsafe static bool NearEqual(float a, float b)
77  {
78  // Check if the numbers are really close -- needed
79  // when comparing numbers near zero.
80  if (IsZero(a - b))
81  return true;
82 
83  // Original from Bruce Dawson: http://randomascii.wordpress.com/2012/02/25/comparing-floating-point-numbers-2012-edition/
84  int aInt = *(int*)&a;
85  int bInt = *(int*)&b;
86 
87  // Different signs means they do not match.
88  if ((aInt < 0) != (bInt < 0))
89  return false;
90 
91  // Find the difference in ULPs.
92  int ulp = Math.Abs(aInt - bInt);
93 
94  // Choose of maxUlp = 4
95  // according to http://code.google.com/p/googletest/source/browse/trunk/include/gtest/internal/gtest-internal.h
96  const int maxUlp = 4;
97  return (ulp <= maxUlp);
98  }
99 
100  /// <summary>
101  /// Determines whether the specified value is close to zero (0.0f).
102  /// </summary>
103  /// <param name="a">The floating value.</param>
104  /// <returns><c>true</c> if the specified value is close to zero (0.0f); otherwise, <c>false</c>.</returns>
105  public static bool IsZero(float a)
106  {
107  return Math.Abs(a) < ZeroTolerance;
108  }
109 
110  /// <summary>
111  /// Determines whether the specified value is close to zero (0.0f).
112  /// </summary>
113  /// <param name="a">The floating value.</param>
114  /// <returns><c>true</c> if the specified value is close to zero (0.0f); otherwise, <c>false</c>.</returns>
115  public static bool IsZero(double a)
116  {
117  return Math.Abs(a) < ZeroToleranceDouble;
118  }
119 
120  /// <summary>
121  /// Determines whether the specified value is close to one (1.0f).
122  /// </summary>
123  /// <param name="a">The floating value.</param>
124  /// <returns><c>true</c> if the specified value is close to one (1.0f); otherwise, <c>false</c>.</returns>
125  public static bool IsOne(float a)
126  {
127  return IsZero(a - 1.0f);
128  }
129 
130  /// <summary>
131  /// Checks if a - b are almost equals within a float epsilon.
132  /// </summary>
133  /// <param name="a">The left value to compare.</param>
134  /// <param name="b">The right value to compare.</param>
135  /// <param name="epsilon">Epsilon value</param>
136  /// <returns><c>true</c> if a almost equal to b within a float epsilon, <c>false</c> otherwise</returns>
137  public static bool WithinEpsilon(float a, float b, float epsilon)
138  {
139  float num = a - b;
140  return ((-epsilon <= num) && (num <= epsilon));
141  }
142 
143  /// <summary>
144  /// Does something with arrays.
145  /// </summary>
146  /// <typeparam name="T">Most likely the type of elements in the array.</typeparam>
147  /// <param name="value">Who knows what this is for.</param>
148  /// <param name="count">Probably the length of the array.</param>
149  /// <returns>An array of who knows what.</returns>
150  public static T[] Array<T>(T value, int count)
151  {
152  T[] result = new T[count];
153  for (int i = 0; i < count; i++)
154  result[i] = value;
155 
156  return result;
157  }
158 
159  /// <summary>
160  /// Converts revolutions to degrees.
161  /// </summary>
162  /// <param name="revolution">The value to convert.</param>
163  /// <returns>The converted value.</returns>
164  public static float RevolutionsToDegrees(float revolution)
165  {
166  return revolution * 360.0f;
167  }
168 
169  /// <summary>
170  /// Converts revolutions to radians.
171  /// </summary>
172  /// <param name="revolution">The value to convert.</param>
173  /// <returns>The converted value.</returns>
174  public static float RevolutionsToRadians(float revolution)
175  {
176  return revolution * TwoPi;
177  }
178 
179  /// <summary>
180  /// Converts revolutions to gradians.
181  /// </summary>
182  /// <param name="revolution">The value to convert.</param>
183  /// <returns>The converted value.</returns>
184  public static float RevolutionsToGradians(float revolution)
185  {
186  return revolution * 400.0f;
187  }
188 
189  /// <summary>
190  /// Converts degrees to revolutions.
191  /// </summary>
192  /// <param name="degree">The value to convert.</param>
193  /// <returns>The converted value.</returns>
194  public static float DegreesToRevolutions(float degree)
195  {
196  return degree / 360.0f;
197  }
198 
199  /// <summary>
200  /// Converts degrees to radians.
201  /// </summary>
202  /// <param name="degree">The value to convert.</param>
203  /// <returns>The converted value.</returns>
204  public static float DegreesToRadians(float degree)
205  {
206  return degree * (Pi / 180.0f);
207  }
208 
209  /// <summary>
210  /// Converts radians to revolutions.
211  /// </summary>
212  /// <param name="radian">The value to convert.</param>
213  /// <returns>The converted value.</returns>
214  public static float RadiansToRevolutions(float radian)
215  {
216  return radian / TwoPi;
217  }
218 
219  /// <summary>
220  /// Converts radians to gradians.
221  /// </summary>
222  /// <param name="radian">The value to convert.</param>
223  /// <returns>The converted value.</returns>
224  public static float RadiansToGradians(float radian)
225  {
226  return radian * (200.0f / Pi);
227  }
228 
229  /// <summary>
230  /// Converts gradians to revolutions.
231  /// </summary>
232  /// <param name="gradian">The value to convert.</param>
233  /// <returns>The converted value.</returns>
234  public static float GradiansToRevolutions(float gradian)
235  {
236  return gradian / 400.0f;
237  }
238 
239  /// <summary>
240  /// Converts gradians to degrees.
241  /// </summary>
242  /// <param name="gradian">The value to convert.</param>
243  /// <returns>The converted value.</returns>
244  public static float GradiansToDegrees(float gradian)
245  {
246  return gradian * (9.0f / 10.0f);
247  }
248 
249  /// <summary>
250  /// Converts gradians to radians.
251  /// </summary>
252  /// <param name="gradian">The value to convert.</param>
253  /// <returns>The converted value.</returns>
254  public static float GradiansToRadians(float gradian)
255  {
256  return gradian * (Pi / 200.0f);
257  }
258 
259  /// <summary>
260  /// Converts radians to degrees.
261  /// </summary>
262  /// <param name="radian">The value to convert.</param>
263  /// <returns>The converted value.</returns>
264  public static float RadiansToDegrees(float radian)
265  {
266  return radian * (180.0f / Pi);
267  }
268 
269  /// <summary>
270  /// Clamps the specified value.
271  /// </summary>
272  /// <param name="value">The value.</param>
273  /// <param name="min">The min.</param>
274  /// <param name="max">The max.</param>
275  /// <returns>The result of clamping a value between min and max</returns>
276  public static float Clamp(float value, float min, float max)
277  {
278  return value < min ? min : value > max ? max : value;
279  }
280 
281  /// <summary>
282  /// Clamps the specified value.
283  /// </summary>
284  /// <param name="value">The value.</param>
285  /// <param name="min">The min.</param>
286  /// <param name="max">The max.</param>
287  /// <returns>The result of clamping a value between min and max</returns>
288  public static double Clamp(double value, double min, double max)
289  {
290  return value < min ? min : value > max ? max : value;
291  }
292 
293  /// <summary>
294  /// Clamps the specified value.
295  /// </summary>
296  /// <param name="value">The value.</param>
297  /// <param name="min">The min.</param>
298  /// <param name="max">The max.</param>
299  /// <returns>The result of clamping a value between min and max</returns>
300  public static int Clamp(int value, int min, int max)
301  {
302  return value < min ? min : value > max ? max : value;
303  }
304 
305  /// <summary>
306  /// Inverse-interpolates a value linearly.
307  /// </summary>
308  /// <param name="value">Value to get inverse interpolation.</param>
309  /// <param name="min">Minimum value that takes place in inverse-interpolation.</param>
310  /// <param name="max">Maximum value that takes place in inverse-interpolation.</param>
311  /// <returns>Returns an inverse-linearly interpolated coeficient.</returns>
312  public static float InverseLerp(float min, float max, float value)
313  {
314  if (IsZero(Math.Abs(max - min)))
315  return float.NaN;
316  return (value - min) / (max - min);
317  }
318 
319  /// <summary>
320  /// Inverse-interpolates a value linearly.
321  /// </summary>
322  /// <param name="value">Value to get inverse interpolation.</param>
323  /// <param name="min">Minimum value that takes place in inverse-interpolation.</param>
324  /// <param name="max">Maximum value that takes place in inverse-interpolation.</param>
325  /// <returns>Returns an inverse-linearly interpolated coeficient.</returns>
326  public static double InverseLerp(double min, double max, double value)
327  {
328  if (IsZero(Math.Abs(max - min)))
329  return double.NaN;
330  return (value - min)/(max - min);
331  }
332 
333  /// <summary>
334  /// Interpolates between two values using a linear function by a given amount.
335  /// </summary>
336  /// <remarks>
337  /// See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and
338  /// http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
339  /// </remarks>
340  /// <param name="from">Value to interpolate from.</param>
341  /// <param name="to">Value to interpolate to.</param>
342  /// <param name="amount">Interpolation amount.</param>
343  /// <returns>The result of linear interpolation of values based on the amount.</returns>
344  public static double Lerp(double from, double to, double amount)
345  {
346  return (1 - amount) * from + amount * to;
347  }
348 
349  /// <summary>
350  /// Interpolates between two values using a linear function by a given amount.
351  /// </summary>
352  /// <remarks>
353  /// See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and
354  /// http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
355  /// </remarks>
356  /// <param name="from">Value to interpolate from.</param>
357  /// <param name="to">Value to interpolate to.</param>
358  /// <param name="amount">Interpolation amount.</param>
359  /// <returns>The result of linear interpolation of values based on the amount.</returns>
360  public static float Lerp(float from, float to, float amount)
361  {
362  return (1 - amount) * from + amount * to;
363  }
364 
365  /// <summary>
366  /// Interpolates between two values using a linear function by a given amount.
367  /// </summary>
368  /// <remarks>
369  /// See http://www.encyclopediaofmath.org/index.php/Linear_interpolation and
370  /// http://fgiesen.wordpress.com/2012/08/15/linear-interpolation-past-present-and-future/
371  /// </remarks>
372  /// <param name="from">Value to interpolate from.</param>
373  /// <param name="to">Value to interpolate to.</param>
374  /// <param name="amount">Interpolation amount.</param>
375  /// <returns>The result of linear interpolation of values based on the amount.</returns>
376  public static byte Lerp(byte from, byte to, float amount)
377  {
378  return (byte)Lerp((float)from, (float)to, amount);
379  }
380 
381  /// <summary>
382  /// Performs smooth (cubic Hermite) interpolation between 0 and 1.
383  /// </summary>
384  /// <remarks>
385  /// See https://en.wikipedia.org/wiki/Smoothstep
386  /// </remarks>
387  /// <param name="amount">Value between 0 and 1 indicating interpolation amount.</param>
388  public static float SmoothStep(float amount)
389  {
390  return (amount <= 0) ? 0
391  : (amount >= 1) ? 1
392  : amount * amount * (3 - (2 * amount));
393  }
394 
395  /// <summary>
396  /// Performs a smooth(er) interpolation between 0 and 1 with 1st and 2nd order derivatives of zero at endpoints.
397  /// </summary>
398  /// <remarks>
399  /// See https://en.wikipedia.org/wiki/Smoothstep
400  /// </remarks>
401  /// <param name="amount">Value between 0 and 1 indicating interpolation amount.</param>
402  public static float SmootherStep(float amount)
403  {
404  return (amount <= 0) ? 0
405  : (amount >= 1) ? 1
406  : amount * amount * amount * (amount * ((amount * 6) - 15) + 10);
407  }
408 
409  /// <summary>
410  /// Calculates the modulo of the specified value, handling negative values.
411  /// </summary>
412  /// <param name="value">The value.</param>
413  /// <param name="modulo">The modulo.</param>
414  /// <returns>The result of the modulo applied to value</returns>
415  public static int Mod(int value, int modulo)
416  {
417  if (modulo == 0)
418  {
419  return value;
420  }
421  value %= modulo;
422  return value < 0 ? value + modulo : value;
423  }
424 
425  /// <summary>
426  /// Calculates the modulo of the specified value.
427  /// </summary>
428  /// <param name="value">The value.</param>
429  /// <param name="modulo">The modulo.</param>
430  /// <returns>The result of the modulo applied to value</returns>
431  public static float Mod(float value, float modulo)
432  {
433  if (modulo == 0.0f)
434  {
435  return value;
436  }
437  value %= modulo;
438  return value < 0 ? value + modulo : value;
439  }
440 
441  /// <summary>
442  /// Calculates the modulo 2*PI of the specified value.
443  /// </summary>
444  /// <param name="value">The value.</param>
445  /// <returns>The result of the modulo applied to value</returns>
446  public static float Mod2PI(float value)
447  {
448  return Mod(value, TwoPi);
449  }
450 
451  /// <summary>
452  /// Wraps the specified value into a range [min, max]
453  /// </summary>
454  /// <param name="value">The value to wrap.</param>
455  /// <param name="min">The min.</param>
456  /// <param name="max">The max.</param>
457  /// <returns>Result of the wrapping.</returns>
458  /// <exception cref="ArgumentException">Is thrown when <paramref name="min"/> is greater than <paramref name="max"/>.</exception>
459  public static int Wrap(int value, int min, int max)
460  {
461  if (min > max)
462  throw new ArgumentException(string.Format("min {0} should be less than or equal to max {1}", min, max), "min");
463 
464  // Code from http://stackoverflow.com/a/707426/1356325
465  int range_size = max - min + 1;
466 
467  if (value < min)
468  value += range_size * ((min - value) / range_size + 1);
469 
470  return min + (value - min) % range_size;
471  }
472 
473  /// <summary>
474  /// Wraps the specified value into a range [min, max[
475  /// </summary>
476  /// <param name="value">The value.</param>
477  /// <param name="min">The min.</param>
478  /// <param name="max">The max.</param>
479  /// <returns>Result of the wrapping.</returns>
480  /// <exception cref="ArgumentException">Is thrown when <paramref name="min"/> is greater than <paramref name="max"/>.</exception>
481  public static float Wrap(float value, float min, float max)
482  {
483  if (NearEqual(min, max)) return min;
484 
485  double mind = min;
486  double maxd = max;
487  double valued = value;
488 
489  if (mind > maxd)
490  throw new ArgumentException(string.Format("min {0} should be less than or equal to max {1}", min, max), "min");
491 
492  var range_size = maxd - mind;
493  return (float)(mind + (valued - mind) - (range_size * Math.Floor((valued - mind) / range_size)));
494  }
495 
496  /// <summary>
497  /// Gauss function.
498  /// </summary>
499  /// <param name="amplitude">Curve amplitude.</param>
500  /// <param name="x">Position X.</param>
501  /// <param name="y">Position Y</param>
502  /// <param name="radX">Radius X.</param>
503  /// <param name="radY">Radius Y.</param>
504  /// <param name="sigmaX">Curve sigma X.</param>
505  /// <param name="sigmaY">Curve sigma Y.</param>
506  /// <returns>The result of Gaussian function.</returns>
507  public static float Gauss(float amplitude, float x, float y, float radX, float radY, float sigmaX, float sigmaY)
508  {
509  return (float)Gauss((double)amplitude, x, y, radX, radY, sigmaX, sigmaY);
510  }
511 
512  /// <summary>
513  /// Gauss function.
514  /// </summary>
515  /// <param name="amplitude">Curve amplitude.</param>
516  /// <param name="x">Position X.</param>
517  /// <param name="y">Position Y</param>
518  /// <param name="radX">Radius X.</param>
519  /// <param name="radY">Radius Y.</param>
520  /// <param name="sigmaX">Curve sigma X.</param>
521  /// <param name="sigmaY">Curve sigma Y.</param>
522  /// <returns>The result of Gaussian function.</returns>
523  public static double Gauss(double amplitude, double x, double y, double radX, double radY, double sigmaX, double sigmaY)
524  {
525  return (amplitude * Math.E) -
526  (
527  Math.Pow(x - (radX / 2), 2) / (2 * Math.Pow(sigmaX, 2)) +
528  Math.Pow(y - (radY / 2), 2) / (2 * Math.Pow(sigmaY, 2))
529  );
530  }
531  }
532 }
static double InverseLerp(double min, double max, double value)
Inverse-interpolates a value linearly.
Definition: MathUtil.cs:326
static float RevolutionsToDegrees(float revolution)
Converts revolutions to degrees.
Definition: MathUtil.cs:164
function b
static float RevolutionsToRadians(float revolution)
Converts revolutions to radians.
Definition: MathUtil.cs:174
function a
static double Gauss(double amplitude, double x, double y, double radX, double radY, double sigmaX, double sigmaY)
Gauss function.
Definition: MathUtil.cs:523
static bool IsOne(float a)
Determines whether the specified value is close to one (1.0f).
Definition: MathUtil.cs:125
_In_ size_t _In_ DXGI_FORMAT _In_ size_t _In_ float size_t y
Definition: DirectXTexP.h:191
static float Gauss(float amplitude, float x, float y, float radX, float radY, float sigmaX, float sigmaY)
Gauss function.
Definition: MathUtil.cs:507
static float Mod2PI(float value)
Calculates the modulo 2*PI of the specified value.
Definition: MathUtil.cs:446
static float SmootherStep(float amount)
Performs a smooth(er) interpolation between 0 and 1 with 1st and 2nd order derivatives of zero at end...
Definition: MathUtil.cs:402
static int Wrap(int value, int min, int max)
Wraps the specified value into a range [min, max]
Definition: MathUtil.cs:459
static float RadiansToDegrees(float radian)
Converts radians to degrees.
Definition: MathUtil.cs:264
static float GradiansToRadians(float gradian)
Converts gradians to radians.
Definition: MathUtil.cs:254
_In_ size_t count
Definition: DirectXTexP.h:174
static bool WithinEpsilon(float a, float b, float epsilon)
Checks if a - b are almost equals within a float epsilon.
Definition: MathUtil.cs:137
static float Wrap(float value, float min, float max)
Wraps the specified value into a range [min, max[
Definition: MathUtil.cs:481
static float Clamp(float value, float min, float max)
Clamps the specified value.
Definition: MathUtil.cs:276
static float DegreesToRevolutions(float degree)
Converts degrees to revolutions.
Definition: MathUtil.cs:194
static int Mod(int value, int modulo)
Calculates the modulo of the specified value, handling negative values.
Definition: MathUtil.cs:415
static float Lerp(float from, float to, float amount)
Interpolates between two values using a linear function by a given amount.
Definition: MathUtil.cs:360
static float GradiansToRevolutions(float gradian)
Converts gradians to revolutions.
Definition: MathUtil.cs:234
static byte Lerp(byte from, byte to, float amount)
Interpolates between two values using a linear function by a given amount.
Definition: MathUtil.cs:376
static int Clamp(int value, int min, int max)
Clamps the specified value.
Definition: MathUtil.cs:300
static float RadiansToRevolutions(float radian)
Converts radians to revolutions.
Definition: MathUtil.cs:214
static double Clamp(double value, double min, double max)
Clamps the specified value.
Definition: MathUtil.cs:288
static float SmoothStep(float amount)
Performs smooth (cubic Hermite) interpolation between 0 and 1.
Definition: MathUtil.cs:388
static float RadiansToGradians(float radian)
Converts radians to gradians.
Definition: MathUtil.cs:224
static unsafe bool NearEqual(float a, float b)
Checks if a and b are almost equals, taking into account the magnitude of floating point numbers (unl...
Definition: MathUtil.cs:76
static bool IsZero(float a)
Determines whether the specified value is close to zero (0.0f).
Definition: MathUtil.cs:105
static float DegreesToRadians(float degree)
Converts degrees to radians.
Definition: MathUtil.cs:204
static float Mod(float value, float modulo)
Calculates the modulo of the specified value.
Definition: MathUtil.cs:431
static float RevolutionsToGradians(float revolution)
Converts revolutions to gradians.
Definition: MathUtil.cs:184
static float GradiansToDegrees(float gradian)
Converts gradians to degrees.
Definition: MathUtil.cs:244
static bool IsZero(double a)
Determines whether the specified value is close to zero (0.0f).
Definition: MathUtil.cs:115
static double Lerp(double from, double to, double amount)
Interpolates between two values using a linear function by a given amount.
Definition: MathUtil.cs:344
static float InverseLerp(float min, float max, float value)
Inverse-interpolates a value linearly.
Definition: MathUtil.cs:312