PageRenderTime 57ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Helpers/MathHelper.cs

#
C# | 1153 lines | 639 code | 101 blank | 413 comment | 16 complexity | 06cf255bf32c37245088c5a434cf6eda MD5 | raw file
Possible License(s): Apache-2.0
  1. using System;
  2. using Delta.Utilities.Datatypes;
  3. using NUnit.Framework;
  4. namespace Delta.Utilities.Helpers
  5. {
  6. /// <summary>
  7. /// Math helper class. Provides the same functionality as System.Math, but
  8. /// instead of using doubles for all the functions here are using floats!
  9. /// </summary>
  10. public static class MathHelper
  11. {
  12. #region Constants
  13. /// <summary>
  14. /// Epsilon is a small comparison offset for NearlyEqual checks.
  15. /// Note: Other frameworks use float.Epsilon (1.192092896e-07f), but we
  16. /// work great with this value too, so we should keep it this way.
  17. /// </summary>
  18. public const float Epsilon = 0.0001f;
  19. /// <summary>
  20. /// E constant as a float (2.718282).
  21. /// </summary>
  22. public const float E = 2.718282f;
  23. /// <summary>
  24. /// Pi constants, same as PI (double), but as a float here (less precise),
  25. /// please note that we usually use degrees and not radians in the engine!
  26. /// </summary>
  27. public const float Pi = 3.14159265359f;
  28. /// <summary>
  29. /// Pi times two for getting around a whole circle (360 degrees).
  30. /// </summary>
  31. public const float PiDouble = Pi * 2.0f;
  32. /// <summary>
  33. /// Pi Half, which represents 90 degrees.
  34. /// </summary>
  35. public const float PiHalf = Pi * 0.5f;
  36. /// <summary>
  37. /// Pi Quarter, which represents 45 degrees.
  38. /// </summary>
  39. public const float PiQuarter = PiHalf * 0.5f;
  40. /// <summary>
  41. /// Represents just the fraction of 1/3 or in decimal 0.333333
  42. /// </summary>
  43. public const float OneThird = 1.0f / 3.0f;
  44. /// <summary>
  45. /// The default value for an invalid index check (-1), very often used to
  46. /// set invalid and initial values to integer values to make sure that we
  47. /// initialize them first before using them, e.g. for shader parameters or
  48. /// for indices in precomputed arrays, but also often used by the .NET
  49. /// framework, e.g String.IndexOf returns -1 for not found.
  50. /// </summary>
  51. public const int InvalidIndex = -1;
  52. /// <summary>
  53. /// Sinus value of 45 Degree
  54. /// </summary>
  55. public const float Sin45 = 0.707106781f;
  56. /// <summary>
  57. /// Half of the short max. value (32768), which is 16392. This is used
  58. /// for the calculation of ViewProjection2DViaShorts and in the
  59. /// MaterialManager to setup compressed vertices.
  60. /// </summary>
  61. public const short HalfShortMaxValue = short.MaxValue / 2;
  62. #endregion
  63. #region NearlyEqual (Static)
  64. /// <summary>
  65. /// Compares two floats if they are almost equal, taking an Epsilon offset
  66. /// (see Math.Epsilon) into account.
  67. /// </summary>
  68. /// <param name="value1">first float</param>
  69. /// <param name="value2">second float</param>
  70. /// <returns>Bool: True if Nearly Equal</returns>
  71. public static bool NearlyEqual(this float value1, float value2)
  72. {
  73. float difference = Abs(value1 - value2);
  74. return difference <= Epsilon;
  75. }
  76. #endregion
  77. #region InvertScalar (Static)
  78. /// <summary>
  79. /// Invert scalar safely.
  80. /// </summary>
  81. /// <param name="value">Value</param>
  82. /// <returns>1.0f</returns>
  83. public static float InvertScalar(float value)
  84. {
  85. if (Abs(value) < Epsilon)
  86. {
  87. return float.MaxValue;
  88. }
  89. return 1.0f / value;
  90. }
  91. #endregion
  92. #region Clamp (Static)
  93. /// <summary>
  94. /// Clamps the value between [0, 1].
  95. /// </summary>
  96. /// <param name="value">Value</param>
  97. /// <returns>Clamp Value</returns>
  98. public static int Clamp(int value)
  99. {
  100. return Clamp(value, 0, 1);
  101. }
  102. /// <summary>
  103. /// Clamps the value between the given range [minimum, maximum].
  104. /// </summary>
  105. /// <param name="max">Max</param>
  106. /// <param name="min">Min</param>
  107. /// <param name="value">Value</param>
  108. /// <returns>value between the given range [minimum, maximum]</returns>
  109. public static int Clamp(int value, int min, int max)
  110. {
  111. return Min(Max(value, min), max);
  112. }
  113. /// <summary>
  114. /// Clamps the value between [0.0, 1.0].
  115. /// </summary>
  116. /// <param name="value">Value</param>
  117. /// <returns>value between [0.0, 1.0]</returns>
  118. public static float Clamp(float value)
  119. {
  120. return Clamp(value, 0.0f, 1.0f);
  121. }
  122. /// <summary>
  123. /// Clamps the value between the given range [minimum, maximum].
  124. /// </summary>
  125. /// <param name="max">Max</param>
  126. /// <param name="min">Min</param>
  127. /// <param name="value">Value</param>
  128. /// <returns>value between the given range [minimum, maximum]</returns>
  129. public static float Clamp(float value, float min, float max)
  130. {
  131. return Min(Max(value, min), max);
  132. }
  133. #endregion
  134. #region Wrap (Static)
  135. /// <summary>
  136. /// Wrap the value between the given range [minimun, maximum].
  137. /// </summary>
  138. /// <param name="max">Max</param>
  139. /// <param name="min">Min</param>
  140. /// <param name="value">Value</param>
  141. /// <returns>value between the given range [minimun, maximum]</returns>
  142. public static int Wrap(int value, int min, int max)
  143. {
  144. int delta = max - min;
  145. if (value > delta)
  146. {
  147. value = value / delta;
  148. value = value - (int)Math.Floor((double)value);
  149. value = value * delta;
  150. }
  151. return value;
  152. }
  153. /// <summary>
  154. /// Wrap the value between the given range [minimun, maximum].
  155. /// </summary>
  156. /// <param name="max">Max</param>
  157. /// <param name="min">Min</param>
  158. /// <param name="value">Value</param>
  159. /// <returns>The wrapped Value</returns>
  160. public static float Wrap(float value, float min, float max)
  161. {
  162. float delta = max - min;
  163. if (value > delta)
  164. {
  165. value = value / delta;
  166. value = value - (float)Math.Floor(value);
  167. value = value * delta;
  168. }
  169. return value;
  170. }
  171. #endregion
  172. #region Distance (Static)
  173. /// <summary>
  174. /// Distance between two float values.
  175. /// </summary>
  176. /// <param name="value1">First float value</param>
  177. /// <param name="value2">Second float value</param>
  178. /// <returns>Distance between the two values, always positive</returns>
  179. public static float Distance(float value1, float value2)
  180. {
  181. return Abs(value1 - value2);
  182. }
  183. #endregion
  184. #region Min (Static)
  185. /// <summary>
  186. /// Returns the smaller of two values.
  187. /// </summary>
  188. /// <param name="value1">Value 1</param>
  189. /// <param name="value2">Value 2</param>
  190. /// <returns>the smaller of two values</returns>
  191. public static float Min(float value1, float value2)
  192. {
  193. return
  194. value1 < value2
  195. ? value1
  196. : value2;
  197. }
  198. /// <summary>
  199. /// Returns the smaller of three values.
  200. /// </summary>
  201. /// <param name="value1">Value 1</param>
  202. /// <param name="value2">Value 2</param>
  203. /// <param name="value3">Value 3</param>
  204. /// <returns>Returns the smaller of three values</returns>
  205. public static float Min(float value1, float value2, float value3)
  206. {
  207. return Min(Min(value1, value2), value3);
  208. }
  209. /// <summary>
  210. /// Returns the smaller of two values.
  211. /// </summary>
  212. /// <param name="value1">Value 1</param>
  213. /// <param name="value2">Value 2</param>
  214. /// <returns>Returns the smaller of two values</returns>
  215. public static int Min(int value1, int value2)
  216. {
  217. return
  218. value1 < value2
  219. ? value1
  220. : value2;
  221. }
  222. /// <summary>
  223. /// Returns the smaller of three values.
  224. /// </summary>
  225. /// <param name="value1">Value1</param>
  226. /// <param name="value2">Value2</param>
  227. /// <param name="value3">Value3</param>
  228. /// <returns>eturns the smaller of three values</returns>
  229. public static int Min(int value1, int value2, int value3)
  230. {
  231. return Min(Min(value1, value2), value3);
  232. }
  233. #endregion
  234. #region Max (Static)
  235. /// <summary>
  236. /// Returns the bigger one of the two values.
  237. /// </summary>
  238. /// <param name="value1">Value 1</param>
  239. /// <param name="value2">Value 2</param>
  240. /// <returns>Returns the bigger one of the two values</returns>
  241. public static int Max(int value1, int value2)
  242. {
  243. return
  244. value1 > value2
  245. ? value1
  246. : value2;
  247. }
  248. /// <summary>
  249. /// Returns the bigger one of the three values.
  250. /// </summary>
  251. /// <param name="value1">Value1</param>
  252. /// <param name="value2">Value2</param>
  253. /// <param name="value3">Value3</param>
  254. /// <returns>Returns the bigger one of the three values</returns>
  255. public static int Max(int value1, int value2, int value3)
  256. {
  257. return Max(Max(value1, value2), value3);
  258. }
  259. /// <summary>
  260. /// Returns the bigger one of the two values.
  261. /// </summary>
  262. /// <param name="value1">Value1</param>
  263. /// <param name="value2">Value2</param>
  264. /// <returns>Returns the bigger one of the two values</returns>
  265. public static float Max(float value1, float value2)
  266. {
  267. return
  268. value1 > value2
  269. ? value1
  270. : value2;
  271. }
  272. /// <summary>
  273. /// Returns the bigger one of the three values.
  274. /// </summary>
  275. /// <param name="value1">Value1</param>
  276. /// <param name="value2">Value2</param>
  277. /// <param name="value3">Value3</param>
  278. /// <returns>Returns the bigger one of the three values</returns>
  279. public static float Max(float value1, float value2, float value3)
  280. {
  281. return Max(Max(value1, value2), value3);
  282. }
  283. #endregion
  284. #region Lerp (Static)
  285. /// <summary>
  286. /// Performs a linear interpolation between two values.
  287. /// </summary>
  288. /// <param name="minValue">Value at "percentage = 0"</param>
  289. /// <param name="maxValue">Value at "percentage = 1"</param>
  290. /// <param name="percentage">Percentage in the range [0,1]</param>
  291. /// <returns>Float</returns>
  292. public static float Lerp(float minValue, float maxValue, float percentage)
  293. {
  294. return minValue + (maxValue - minValue) * percentage;
  295. }
  296. /// <summary>
  297. /// Performs a linear interpolation between two values.
  298. /// </summary>
  299. /// <param name="minValue">Value at "percentage = 0"</param>
  300. /// <param name="maxValue">Value at "percentage = 1"</param>
  301. /// <param name="percentage">Percentage in the range [0,1]</param>
  302. /// <returns>Float</returns>
  303. public static int Lerp(int minValue, int maxValue, float percentage)
  304. {
  305. return minValue + Round((maxValue - minValue) * percentage);
  306. }
  307. /// <summary>
  308. /// Performs a linear interpolation between two values.
  309. /// </summary>
  310. /// <param name="minValue">Value at "percentage = 0"</param>
  311. /// <param name="maxValue">Value at "percentage = 1"</param>
  312. /// <param name="percentage">Percentage in the range [0,1]</param>
  313. /// <returns>Float</returns>
  314. public static long Lerp(long minValue, long maxValue, float percentage)
  315. {
  316. return minValue + Round((maxValue - minValue) * percentage);
  317. }
  318. #endregion
  319. #region Sqrt (Static)
  320. /// <summary>
  321. /// Sqrt
  322. /// </summary>
  323. /// <returns>Float</returns>
  324. public static float Sqrt(float value)
  325. {
  326. return (float)Math.Sqrt(value);
  327. }
  328. #endregion
  329. #region Round (Static)
  330. /// <summary>
  331. /// Rounds a value to a given position after the decimal point
  332. /// </summary>
  333. /// <param name="value">Value to round</param>
  334. /// <param name="decimals">Decimals</param>
  335. /// <returns>Float</returns>
  336. public static float Round(float value, int decimals)
  337. {
  338. return (float)Math.Round(value, decimals);
  339. }
  340. /// <summary>
  341. /// Rounds a value to an int
  342. /// </summary>
  343. /// <param name="value">Value to round</param>
  344. /// <returns>Float</returns>
  345. public static int Round(float value)
  346. {
  347. return (int)Math.Round(value);
  348. }
  349. #endregion
  350. #region Ceiling (Static)
  351. /// <summary>
  352. /// Ceiling
  353. /// </summary>
  354. /// <param name="value">Value</param>
  355. /// <returns>Ceiling</returns>
  356. public static int Ceiling(float value)
  357. {
  358. return (int)Math.Ceiling(value);
  359. }
  360. #endregion
  361. #region Abs (Static)
  362. /// <summary>
  363. /// Returns the absolute value of a float
  364. /// </summary>
  365. /// <param name="value">Value</param>
  366. /// <returns>Returns the absolute value of a float</returns>
  367. public static float Abs(float value)
  368. {
  369. return
  370. value < 0f
  371. ? -value
  372. : value;
  373. }
  374. #endregion
  375. #region Pow (Static)
  376. /// <summary>
  377. /// Pow
  378. /// </summary>
  379. /// <param name="power">Power</param>
  380. /// <param name="value">Value</param>
  381. /// <returns>Power</returns>
  382. public static float Pow(float value, float power)
  383. {
  384. return (float)Math.Pow(value, power);
  385. }
  386. #endregion
  387. #region DegreeToRadians (Static)
  388. /// <summary>
  389. /// Degree to radians
  390. /// </summary>
  391. /// <param name="degrees">Degrees</param>
  392. /// <returns>Degree to radians</returns>
  393. public static float DegreeToRadians(this float degrees)
  394. {
  395. return degrees * (Pi / 180.0f); //same: * 0.01745329f;
  396. }
  397. #endregion
  398. #region RadiansToDegrees (Static)
  399. /// <summary>
  400. /// Radians to degrees
  401. /// </summary>
  402. /// <param name="radians">Radians</param>
  403. /// <returns>radians</returns>
  404. public static float RadiansToDegrees(this float radians)
  405. {
  406. return radians * (180.0f / Pi); //same: * 57.29578f;
  407. }
  408. #endregion
  409. #region Sin (Static)
  410. /// <summary>
  411. /// Return the sinus of a degreeValue. Note: Most other math libraries use
  412. /// radians, please provide degrees here (used throughout the engine).
  413. /// </summary>
  414. /// <param name="degreeValue">Degree value for the sinus</param>
  415. /// <returns>Sinus of degreeValue</returns>
  416. public static float Sin(float degreeValue)
  417. {
  418. return (float)Math.Sin(degreeValue * (Pi / 180.0f));
  419. }
  420. #endregion
  421. #region Cos (Static)
  422. /// <summary>
  423. /// Cosinus of a degreeValue, please use degree values here (not radians)
  424. /// </summary>
  425. /// <param name="degreeValue">Degree Value for the cosinus</param>
  426. /// <returns>Cosinus of degreeValue</returns>
  427. public static float Cos(float degreeValue)
  428. {
  429. return (float)Math.Cos(degreeValue * (Pi / 180.0f));
  430. }
  431. #endregion
  432. #region Tan (Static)
  433. /// <summary>
  434. /// Get the tangent value, again using degrees, not radians.
  435. /// </summary>
  436. /// <param name="degreeValue">Degree value for the tagent</param>
  437. /// <returns>Tangent of degreeValue</returns>
  438. public static float Tan(float degreeValue)
  439. {
  440. return (float)Math.Tan(DegreeToRadians(degreeValue));
  441. }
  442. #endregion
  443. #region Asin (Static)
  444. /// <summary>
  445. /// Returns the angle in degrees whose sin value is the specified value.
  446. /// </summary>
  447. /// <param name="value">Value for asin</param>
  448. /// <returns>Asin value in degrees from the value</returns>
  449. public static float Asin(float value)
  450. {
  451. return RadiansToDegrees((float)Math.Asin(value));
  452. }
  453. #endregion
  454. #region Acos (Static)
  455. /// <summary>
  456. /// Returns the angle in degrees whose cos value is the specified value.
  457. /// </summary>
  458. /// <param name="value">Value for acos</param>
  459. /// <returns>Acos value in degrees from the value</returns>
  460. public static float Acos(float value)
  461. {
  462. return RadiansToDegrees((float)Math.Acos(value));
  463. }
  464. #endregion
  465. #region Atan (Static)
  466. /// <summary>
  467. /// Returns the angle in degrees whose tangent is the specified number.
  468. /// Use Atan(x, y) if you do not want to calculate the quotient yourself.
  469. /// </summary>
  470. /// <param name="tangent">Tangent</param>
  471. /// <returns>Atan value in degrees from the tangent value</returns>
  472. public static float Atan(float tangent)
  473. {
  474. return RadiansToDegrees((float)Math.Atan(tangent));
  475. }
  476. /// <summary>
  477. /// Returns the angle in degrees whose tangent is the quotient of two
  478. /// specified numbers. For more help see System.Math.Atan2 (which works in
  479. /// radians however).
  480. /// </summary>
  481. /// <param name="x">X value for atan2</param>
  482. /// <param name="y">Y value for atan2</param>
  483. /// <returns>Atan value in degrees from the x and y values</returns>
  484. public static float Atan(float x, float y)
  485. {
  486. return RadiansToDegrees((float)Math.Atan2(x, y));
  487. }
  488. #endregion
  489. #region GetNextPowerOfTwo (Static)
  490. /// <summary>
  491. /// Get the nearest power of two value that must be bigger or equal to
  492. /// value. Used for making sure textures are power of two. E.g.
  493. /// GetNextPowerOfTwo(128) is 128, GetNextPowerOfTwo(129) is 256, etc.
  494. /// </summary>
  495. /// <param name="value">Value</param>
  496. /// <returns>the nearest power of two value</returns>
  497. public static int GetNextPowerOfTwo(this float value)
  498. {
  499. int logValue = (int)Math.Ceiling(Math.Log(value, 2));
  500. return (int)Math.Pow(2, logValue);
  501. }
  502. #endregion
  503. #region IsPowerOfTwo (Static)
  504. /// <summary>
  505. /// Is power of two
  506. /// </summary>
  507. /// <param name="value">Value</param>
  508. /// <returns>Is power of two</returns>
  509. public static bool IsPowerOfTwo(this float value)
  510. {
  511. return GetNextPowerOfTwo(value) == value;
  512. }
  513. #endregion
  514. #region GetNearestMultiple (Static)
  515. /// <summary>
  516. /// Get the nearest multiple of 'multipleValue' from the value.
  517. /// </summary>
  518. /// <param name="multipleValue">Multiple Value</param>
  519. /// <param name="value">Value</param>
  520. /// <returns>the nearest multiple of 'multipleValue' from the
  521. /// value</returns>
  522. public static int GetNearestMultiple(this int value, int multipleValue)
  523. {
  524. int min =
  525. ((int)(value / (float)multipleValue)) * multipleValue;
  526. int max =
  527. ((int)(value / (float)multipleValue) + 1) * multipleValue;
  528. return max - value < value - min
  529. ? max
  530. : min;
  531. }
  532. #endregion
  533. #region Sign (Static)
  534. /// <summary>
  535. /// System.Math.Sign method, that crashes on the iPad if the value is not
  536. /// valid (e.g. NaN). This method will always return -1, 0 or 1.
  537. /// </summary>
  538. /// <param name="value">Value</param>
  539. /// <returns>-1, 0 or 1</returns>
  540. public static float Sign(float value)
  541. {
  542. //2010-05-28: dummy fix for iPad
  543. if (value == float.NaN)
  544. {
  545. return 0;
  546. }
  547. if (value < 0)
  548. {
  549. return -1;
  550. }
  551. else if (value > 0)
  552. {
  553. return 1;
  554. }
  555. else
  556. {
  557. return 0;
  558. }
  559. }
  560. #endregion
  561. #region ComputePercentageValue (Static)
  562. /// <summary>
  563. /// Computes the percentage value in the range [0 = 0%, 1 = 100%] based on
  564. /// the given value related to the given value range.
  565. /// </summary>
  566. /// <param name="value">
  567. /// The value we want to calculate the percentage for.
  568. /// </param>
  569. /// <param name="minValue">The minimum allowed value.</param>
  570. /// <param name="maxValue">The maximum allowed value.</param>
  571. /// <returns>
  572. /// The percentage value in the range [0 = 0%, 1 = 100%] based on the given
  573. /// value related to the given value range.
  574. /// </returns>
  575. public static float ComputePercentageValue(float value, float minValue,
  576. float maxValue)
  577. {
  578. // Validation
  579. float realMinValue =
  580. maxValue > minValue
  581. ? minValue
  582. : maxValue;
  583. float realMaxValue =
  584. minValue > maxValue
  585. ? minValue
  586. : maxValue;
  587. // Absolute difference between max and min value (should not be 0)
  588. float diff = realMaxValue - realMinValue;
  589. if (diff <= 0.0f)
  590. {
  591. return 0.0f;
  592. }
  593. // Clamp value to always get a result between 0 and 1.
  594. float clampedValue = Clamp(value, realMinValue, realMaxValue);
  595. // Difference from min to desired value in 0-1 range!
  596. return (clampedValue - realMinValue) / diff;
  597. }
  598. #endregion
  599. #region ComputeValue (Static)
  600. /// <summary>
  601. /// Returns the exact value based on the given percentage related to the
  602. /// given value range.
  603. /// </summary>
  604. /// <param name="percentageValue">Percentage value in the range of [0 = 0%,
  605. /// 1 = 100%].</param>
  606. /// <param name="minValue">The minimum allowed value.</param>
  607. /// <param name="maxValue">The maximum allowed value.</param>
  608. /// <returns>Float</returns>
  609. public static float ComputeValue(float percentageValue, float minValue,
  610. float maxValue)
  611. {
  612. // Validation
  613. float realMinValue = (maxValue > minValue)
  614. ? minValue
  615. : maxValue;
  616. float realMaxValue = (minValue > maxValue)
  617. ? minValue
  618. : maxValue;
  619. // clamp value
  620. float clampedPercentageValue = Clamp(percentageValue);
  621. // absolute difference between max and min value
  622. float diff = Abs(realMaxValue - realMinValue) * clampedPercentageValue;
  623. // return how many percent "diffFromMinToValue" is when diff = 100%
  624. return realMinValue + diff;
  625. }
  626. #endregion
  627. #region LineToLineIntersection (Static)
  628. /// <summary>
  629. /// Check if two lines intersect and return the position if occurred.
  630. /// </summary>
  631. /// <param name="a">The start point of line one.</param>
  632. /// <param name="b">The end point of line one.</param>
  633. /// <param name="c">The start point of line two.</param>
  634. /// <param name="d">The end point of line two.</param>
  635. /// <param name="resultX">If they intersect the X value is stored here.
  636. /// </param>
  637. /// <param name="resultY">If they intersect the Y value is stored here.
  638. /// </param>
  639. /// <returns>True if they intersect, otherwise false.</returns>
  640. public static bool LineToLineIntersection(Point a, Point b, Point c,
  641. Point d, out float resultX, out float resultY)
  642. {
  643. resultX = 0f;
  644. resultY = 0f;
  645. float denominator =
  646. ((d.Y - c.Y) * (b.X - a.X)) - ((d.X - c.X) * (b.Y - a.Y));
  647. float ua = (((d.X - c.X) * (a.Y - c.Y)) - ((d.Y - c.Y) * (a.X - c.X))) /
  648. denominator;
  649. float ub = (((b.X - a.X) * (a.Y - c.Y)) - ((b.Y - a.Y) * (a.X - c.X))) /
  650. denominator;
  651. if (ua >= 0f && ua <= 1f && ub >= 0f &&
  652. ub <= 1f)
  653. {
  654. resultX = a.X + (ua * (b.X - a.X));
  655. resultY = a.Y + (ua * (b.Y - a.Y));
  656. return true;
  657. }
  658. return false;
  659. }
  660. /// <summary>
  661. /// Check if two lines intersect and return the position if occurred.
  662. /// </summary>
  663. /// <param name="a">The start point of line one.</param>
  664. /// <param name="b">The end point of line one.</param>
  665. /// <param name="c">The start point of line two.</param>
  666. /// <param name="d">The end point of line two.</param>
  667. /// <returns>True if they intersect, otherwise false.</returns>
  668. public static bool LineToLineIntersection(Point a, Point b, Point c,
  669. Point d)
  670. {
  671. float denominator =
  672. ((d.Y - c.Y) * (b.X - a.X)) - ((d.X - c.X) * (b.Y - a.Y));
  673. float ua = (((d.X - c.X) * (a.Y - c.Y)) - ((d.Y - c.Y) * (a.X - c.X))) /
  674. denominator;
  675. float ub = (((b.X - a.X) * (a.Y - c.Y)) - ((b.Y - a.Y) * (a.X - c.X))) /
  676. denominator;
  677. return ua >= 0f && ua <= 1f && ub >= 0f && ub <= 1f;
  678. }
  679. #endregion
  680. /// <summary>
  681. /// Tests
  682. /// </summary>
  683. internal class MathHelperTests
  684. {
  685. #region NearlyEqual (Static)
  686. /// <summary>
  687. /// Nearly equal
  688. /// </summary>
  689. [Test]
  690. public static void NearlyEqual()
  691. {
  692. Assert.True(0.0f.NearlyEqual(0.0f));
  693. Assert.True(0.000001f.NearlyEqual(0.000002f));
  694. Assert.False(1.0f.NearlyEqual(2.0f));
  695. Assert.True(1.0f.NearlyEqual(1.0f + (Epsilon * 0.9f)));
  696. }
  697. #endregion
  698. #region Clamp (Static)
  699. /// <summary>
  700. /// Clamp
  701. /// </summary>
  702. [Test]
  703. public static void Clamp()
  704. {
  705. // Int's
  706. Assert.Equal(1, MathHelper.Clamp(1, 0, 10));
  707. Assert.Equal(0, MathHelper.Clamp(-1, 0, 10));
  708. Assert.Equal(10, MathHelper.Clamp(111, 0, 10));
  709. Assert.Equal(0, MathHelper.Clamp(2598, 0, 0));
  710. // Float's
  711. Assert.Equal(0.1f, MathHelper.Clamp(0.1f, 0.0f, 1.0f));
  712. Assert.Equal(0.59f, MathHelper.Clamp(0.64f, 0.53f, 0.59f));
  713. Assert.Equal(0.64f, MathHelper.Clamp(0.53f, 0.64f, 0.69f));
  714. //Assert.Equal(new Point(-1, -1),
  715. // MathHelper.Clamp(new Point(-2, -3.5f), new Point(-1, -1),
  716. // new Point(0, 0)));
  717. }
  718. #endregion
  719. #region Min (Static)
  720. /// <summary>
  721. /// Minimum
  722. /// </summary>
  723. [Test]
  724. public static void Min()
  725. {
  726. Assert.Equal(10, MathHelper.Min(10, 20));
  727. Assert.Equal(43, MathHelper.Min(134, 43));
  728. Assert.Equal(-20, MathHelper.Min(-10, -20));
  729. Assert.Equal(-20, MathHelper.Min(-5, -10, -20));
  730. }
  731. #endregion
  732. #region Max (Static)
  733. /// <summary>
  734. /// Maximum
  735. /// </summary>
  736. [Test]
  737. public static void Max()
  738. {
  739. Assert.Equal(20, MathHelper.Max(10, 20));
  740. Assert.Equal(134, MathHelper.Max(134, 43));
  741. Assert.Equal(-10, MathHelper.Max(-10, -20));
  742. Assert.Equal(-5, MathHelper.Max(-5, -10, -20));
  743. }
  744. #endregion
  745. #region Sqrt (Static)
  746. /// <summary>
  747. /// Sqrt
  748. /// </summary>
  749. [Test]
  750. public static void Sqrt()
  751. {
  752. Assert.Equal(0, MathHelper.Sqrt(0));
  753. Assert.Equal(2, MathHelper.Sqrt(4));
  754. Assert.Equal(9, MathHelper.Sqrt(81));
  755. Assert.NotEqual(1, MathHelper.Sqrt(2));
  756. }
  757. #endregion
  758. #region Round (Static)
  759. /// <summary>
  760. /// Round
  761. /// </summary>
  762. [Test]
  763. public static void Round()
  764. {
  765. Assert.Equal(1, MathHelper.Round(1.25f));
  766. Assert.Equal(10, MathHelper.Round(9.68f));
  767. Assert.Equal(1.23f, MathHelper.Round(1.2345f, 2));
  768. }
  769. #endregion
  770. #region Abs (Static)
  771. /// <summary>
  772. /// Absolute
  773. /// </summary>
  774. [Test]
  775. public static void Abs()
  776. {
  777. Assert.Equal(13, MathHelper.Abs(13));
  778. Assert.Equal(13, MathHelper.Abs(-13));
  779. Assert.Equal(13.52f, MathHelper.Abs(-13.52f));
  780. }
  781. #endregion
  782. #region Pow (Static)
  783. /// <summary>
  784. /// Pow
  785. /// </summary>
  786. [Test]
  787. public static void Pow()
  788. {
  789. Assert.Equal(25, MathHelper.Pow(5, 2));
  790. }
  791. #endregion
  792. #region GetNearestMultiple (Static)
  793. /// <summary>
  794. /// Test GetNearestMultiple
  795. /// </summary>
  796. [Test]
  797. public static void GetNearestMultiple()
  798. {
  799. int result = 130.GetNearestMultiple(32);
  800. Assert.Equal(128, result);
  801. result = 157.GetNearestMultiple(32);
  802. Assert.Equal(160, result);
  803. result = 17.GetNearestMultiple(4);
  804. Assert.Equal(16, result);
  805. result = 19.GetNearestMultiple(4);
  806. Assert.Equal(20, result);
  807. }
  808. #endregion
  809. #region Ceiling
  810. /// <summary>
  811. /// Ceiling
  812. /// </summary>
  813. [Test]
  814. public void Ceiling()
  815. {
  816. Assert.Equal(MathHelper.Ceiling(0.0f), 0);
  817. Assert.Equal(MathHelper.Ceiling(4.0f), 4);
  818. Assert.Equal(MathHelper.Ceiling(-2.0f), -2);
  819. Assert.Equal(MathHelper.Ceiling(2.3f), 3);
  820. Assert.Equal(MathHelper.Ceiling(7.8f), 8);
  821. }
  822. #endregion
  823. #region DegreeToRadians
  824. /// <summary>
  825. /// Degree to radians
  826. /// </summary>
  827. [Test]
  828. public void DegreeToRadians()
  829. {
  830. Assert.Equal(0, MathHelper.DegreeToRadians(0));
  831. Assert.True(Pi.NearlyEqual(MathHelper.DegreeToRadians(180)),
  832. "180 degrees is converted to radians nearly pi");
  833. Assert.True(PiHalf.NearlyEqual(MathHelper.DegreeToRadians(90)),
  834. "90 degrees is converted to radians nearly HalfPi");
  835. Assert.True(PiDouble.NearlyEqual(MathHelper.DegreeToRadians(360)),
  836. "360 degrees is converted to radians nearly PiDouble");
  837. Assert.NotEqual(0, MathHelper.DegreeToRadians(-1));
  838. }
  839. #endregion
  840. #region RadiansToDegrees
  841. /// <summary>
  842. /// Radians to degrees
  843. /// </summary>
  844. [Test]
  845. public void RadiansToDegrees()
  846. {
  847. Assert.Equal(0, MathHelper.RadiansToDegrees(0));
  848. Assert.True(MathHelper.NearlyEqual(180,
  849. Pi.RadiansToDegrees()),
  850. "Pi in radians is converted to degrees nearly 180 degree");
  851. Assert.True(MathHelper.NearlyEqual(90,
  852. PiHalf.RadiansToDegrees()),
  853. "HalfPi in radians is converted to degrees nearly 90 degree");
  854. Assert.True(MathHelper.NearlyEqual(360,
  855. PiDouble.RadiansToDegrees()),
  856. "PiDouble in radians is converted to degrees nearly 360 degree");
  857. Assert.NotEqual(0, MathHelper.RadiansToDegrees(-1));
  858. }
  859. #endregion
  860. #region Lerp
  861. /// <summary>
  862. /// Lerp
  863. /// </summary>
  864. [Test]
  865. public void Lerp()
  866. {
  867. Assert.Equal(3, MathHelper.Lerp(5, 3, 1));
  868. }
  869. #endregion
  870. #region TestIntTruncate
  871. /// <summary>
  872. /// Test int truncate
  873. /// </summary>
  874. [Test]
  875. public void TestIntTruncate()
  876. {
  877. Assert.Equal(17, (int)17.7f);
  878. Assert.Equal(17, (int)(17.2f + 0.5f));
  879. }
  880. #endregion
  881. #region Sin
  882. /// <summary>
  883. /// Sin
  884. /// </summary>
  885. [Test]
  886. public void Sin()
  887. {
  888. Assert.Equal(0, MathHelper.Sin(0));
  889. Assert.Equal(1, MathHelper.Sin(90));
  890. Assert.True(MathHelper.NearlyEqual(0, MathHelper.Sin(180)),
  891. "the sin of 180 is nearly zero");
  892. Assert.True(MathHelper.NearlyEqual(0, MathHelper.Sin(360)),
  893. "the sin of 360 is nearly zero");
  894. Assert.NotEqual(0, MathHelper.Sin(32));
  895. }
  896. #endregion
  897. #region Cos
  898. /// <summary>
  899. /// Sin
  900. /// </summary>
  901. [Test]
  902. public void Cos()
  903. {
  904. Assert.Equal(1, MathHelper.Cos(0));
  905. Assert.True(MathHelper.NearlyEqual(0, MathHelper.Cos(90)),
  906. "the cos of 90 is nearly zero");
  907. Assert.True(MathHelper.NearlyEqual(-1, MathHelper.Cos(180)),
  908. "the cos of 180 is nearly minus one");
  909. Assert.True(MathHelper.NearlyEqual(1, MathHelper.Cos(360)),
  910. "the cos of 360 is nearly one");
  911. Assert.NotEqual(0, MathHelper.Cos(32));
  912. }
  913. #endregion
  914. #region Tan
  915. /// <summary>
  916. /// Tan
  917. /// </summary>
  918. [Test]
  919. public void Tan()
  920. {
  921. Assert.Equal(0, MathHelper.Tan(0));
  922. Assert.True(MathHelper.NearlyEqual(0, MathHelper.Tan(180)),
  923. "the tan of 180 is nearly zero");
  924. Assert.True(1.732051f.NearlyEqual(MathHelper.Tan(60)),
  925. "the tan of 60 is nearly 1.732051f");
  926. Assert.True(MathHelper.NearlyEqual(1, MathHelper.Tan(45)),
  927. "the tan of 45 is nearly one");
  928. Assert.True(MathHelper.NearlyEqual(-1, MathHelper.Tan(135)),
  929. "the tan of 135 is nearly minus one");
  930. Assert.NotEqual(0, MathHelper.Tan(32));
  931. }
  932. #endregion
  933. #region Asin
  934. /// <summary>
  935. /// Asin
  936. /// </summary>
  937. [Test]
  938. public void Asin()
  939. {
  940. Assert.Equal(0, MathHelper.Asin(0));
  941. Assert.True(MathHelper.NearlyEqual(90, MathHelper.Asin(1)),
  942. "The Asin of 1 is nearly 90");
  943. Assert.True(MathHelper.NearlyEqual(30, MathHelper.Asin(0.5f)),
  944. "The Asin of 0.5 is nearly 30");
  945. Assert.NotEqual(0, MathHelper.Asin(0.2f));
  946. }
  947. #endregion
  948. #region Acos
  949. /// <summary>
  950. /// Acos
  951. /// </summary>
  952. [Test]
  953. public void Acos()
  954. {
  955. Assert.True(MathHelper.NearlyEqual(90, MathHelper.Acos(0)),
  956. "The Acos of zero is nearly 90");
  957. Assert.True(MathHelper.NearlyEqual(0, MathHelper.Acos(1)),
  958. "The Acos of one is nearly zero");
  959. Assert.True(MathHelper.NearlyEqual(60, MathHelper.Acos(0.5f)),
  960. "The Acos of 0.5 is nearly 60");
  961. Assert.NotEqual(0, MathHelper.Acos(0.2f));
  962. }
  963. #endregion
  964. #region Atan
  965. /// <summary>
  966. /// Atan
  967. /// </summary>
  968. [Test]
  969. public void Atan()
  970. {
  971. Assert.Equal(0, MathHelper.Atan(0));
  972. Assert.True(MathHelper.NearlyEqual(60, MathHelper.Atan(1.732051f)),
  973. "The Atan of 1.732051f is nearly 60");
  974. Assert.NotEqual(0, MathHelper.Atan(0.2f));
  975. Assert.Equal(0, MathHelper.Atan(0, 0));
  976. Assert.Equal(0, MathHelper.Atan(0, 1));
  977. Assert.True(MathHelper.NearlyEqual(90, MathHelper.Atan(1, 0)),
  978. "The Atan of the tangent(of one and zero) is nearly 90");
  979. Assert.True(MathHelper.NearlyEqual(45, MathHelper.Atan(1, 1)),
  980. "The Atan of the tangent(of one and one) is nearly 45");
  981. Assert.True(MathHelper.NearlyEqual(-90, MathHelper.Atan(-1, 0)),
  982. "The Atan of the tangent(of minus one and zero) is nearly minus 90");
  983. // Math.Atan(0, -1));
  984. // Always works:
  985. Assert.Equal("180", MathHelper.Atan(0, -1).ToString());
  986. // Only works if Math.Epsilon for NearlyEqual is not smaller than
  987. // 0.0001
  988. Assert.True(MathHelper.NearlyEqual(180, MathHelper.Atan(0, -1)),
  989. "The Atan of the tangent(of zero and minus one) is nearly 180");
  990. }
  991. #endregion
  992. #region GetNextPowerOfTwo
  993. /// <summary>
  994. /// Get next power of two
  995. /// </summary>
  996. [Test]
  997. public void GetNextPowerOfTwo()
  998. {
  999. Assert.Equal(128, MathHelper.GetNextPowerOfTwo(128));
  1000. Assert.Equal(256, MathHelper.GetNextPowerOfTwo(129));
  1001. Assert.Equal(1024, MathHelper.GetNextPowerOfTwo(529));
  1002. Assert.Equal(2048, MathHelper.GetNextPowerOfTwo(1111));
  1003. Assert.Equal(0, MathHelper.GetNextPowerOfTwo(-1));
  1004. }
  1005. #endregion
  1006. #region IsPowerOfTwo
  1007. /// <summary>
  1008. /// IsPowerOfTwo
  1009. /// </summary>
  1010. [Test]
  1011. public void IsPowerOfTwo()
  1012. {
  1013. Assert.True(MathHelper.IsPowerOfTwo(128));
  1014. Assert.False(MathHelper.IsPowerOfTwo(129));
  1015. Assert.False(MathHelper.IsPowerOfTwo(529));
  1016. Assert.False(MathHelper.IsPowerOfTwo(1111));
  1017. Assert.True(MathHelper.IsPowerOfTwo(1024));
  1018. Assert.False(MathHelper.IsPowerOfTwo(-1));
  1019. Assert.True(MathHelper.IsPowerOfTwo(4));
  1020. }
  1021. #endregion
  1022. #region ComputeValue
  1023. /// <summary>
  1024. /// Compute value
  1025. /// </summary>
  1026. [Test]
  1027. public void ComputeValue()
  1028. {
  1029. Assert.Equal(MathHelper.ComputeValue(0.5f, 10, 20), 15.0f);
  1030. Assert.Equal(MathHelper.ComputeValue(0.5f, 0, 10), 5.0f);
  1031. Assert.Equal(MathHelper.ComputeValue(0.5f, -10, 0), -5.0f);
  1032. Assert.Equal(MathHelper.ComputeValue(0.5f, -10, 10), 0.0f);
  1033. }
  1034. #endregion
  1035. #region ComputePercentageValue
  1036. /// <summary>
  1037. /// Compute percentage value
  1038. /// </summary>
  1039. [Test]
  1040. public void ComputePercentageValue()
  1041. {
  1042. Assert.Equal(MathHelper.ComputePercentageValue(5, 0, 10), 0.5f);
  1043. Assert.Equal(MathHelper.ComputePercentageValue(0, -10, 10), 0.5f);
  1044. Assert.Equal(MathHelper.ComputePercentageValue(0, -360, 360), 0.5f);
  1045. Assert.Equal(MathHelper.ComputePercentageValue(-50, -100, -50), 1.0f);
  1046. Assert.Equal(MathHelper.ComputePercentageValue(-100, -100, -50), 0.0f);
  1047. Assert.Equal(MathHelper.ComputePercentageValue(0, 1000, -1000), 0.5f);
  1048. }
  1049. #endregion
  1050. }
  1051. }
  1052. }