/Utilities/Math/Range.cs
C# | 338 lines | 211 code | 33 blank | 94 comment | 11 complexity | b033a521589d9d2b7d40d09cd1fe452a MD5 | raw file
Possible License(s): Apache-2.0
- using System.Diagnostics;
- using System.IO;
- using System.Runtime.InteropServices;
- using Delta.Utilities.Helpers;
- using NUnit.Framework;
-
- namespace Delta.Utilities.Math
- {
- /// <summary>
- /// The Range object is used to store one or two values, which result in a
- /// range. Getting the value of a range object, will give you a random
- /// value between Start and End.
- /// </summary>
- [StructLayout(LayoutKind.Sequential)]
- [DebuggerDisplay("Range(Start={Start}, End={End})")]
- public struct Range : ISaveLoadBinary
- {
- #region Constants
- /// <summary>
- /// Zero range, will always return 0.
- /// </summary>
- public static readonly Range Zero = new Range(0, 0);
-
- /// <summary>
- /// One range, will always return 1.
- /// </summary>
- public static readonly Range One = new Range(1, 1);
-
- /// <summary>
- /// Zero to One range, will return a random values between 0 and 1.
- /// </summary>
- public static readonly Range ZeroToOne = new Range(0, 1);
- #endregion
-
- #region Start (Public)
- /// <summary>
- /// Start value of the range.
- /// </summary>
- public float Start
- {
- get
- {
- return internalStart;
- }
- set
- {
- if (value != internalStart)
- {
- internalStart = value;
- Difference = internalEnd -
- internalStart;
- }
- }
- }
- #endregion
-
- #region End (Public)
- /// <summary>
- /// End value of the range.
- /// </summary>
- public float End
- {
- get
- {
- return internalEnd;
- }
- set
- {
- if (value != internalEnd)
- {
- internalEnd = value;
- Difference = internalEnd -
- internalStart;
- }
- }
- }
- #endregion
-
- #region Difference (Public)
- /// <summary>
- /// Difference between Start and End, always a positive value because
- /// Max is always bigger than Min.
- /// </summary>
- public float Difference
- {
- get;
- private set;
- }
- #endregion
-
- #region RandomValue (Public)
- /// <summary>
- /// Returns a random value between Start and End.
- /// </summary>
- /// <returns>Float</returns>
- public float RandomValue
- {
- get
- {
- // Note: We do not need to randomize if start is the same value as end
- return (Start != End)
- ? RandomHelper.RandomFloat(Start, End)
- : Start;
- }
- }
- #endregion
-
- #region Private
-
- #region internalStart (Private)
- private float internalStart;
- #endregion
-
- #region internalEnd (Private)
- private float internalEnd;
- #endregion
-
- #endregion
-
- #region Constructors
- /// <summary>
- /// Create range with fixed value.
- /// </summary>
- /// <param name="setStartAndEndValue">Set start and end value</param>
- public Range(float setStartAndEndValue)
- : this()
- {
- Start = setStartAndEndValue;
- End = setStartAndEndValue;
- }
-
- /// <summary>
- /// Create range with given minimum and maximum values.
- /// </summary>
- /// <param name="setStartValue">Set start value</param>
- /// <param name="setEndValue">Set end value</param>
- public Range(float setStartValue, float setEndValue)
- : this()
- {
- Start = setStartValue;
- End = setEndValue;
- }
- #endregion
-
- #region ISaveLoadBinary Members
- /// <summary>
- /// Loads Range from a stream (just Start and End).
- /// </summary>
- /// <param name="reader">The stream that will be used.</param>
- public void Load(BinaryReader reader)
- {
- Start = reader.ReadSingle();
- End = reader.ReadSingle();
- }
-
- /// <summary>
- /// Saves Range to a stream (just Start and End).
- /// </summary>
- /// <param name="writer">The stream that will be used.</param>
- public void Save(BinaryWriter writer)
- {
- writer.Write(Start);
- writer.Write(End);
- }
- #endregion
-
- #region op_Implicit (Operator)
- /// <summary>
- /// Operator to assign rango from float value.
- /// </summary>
- public static implicit operator Range(float value)
- {
- return new Range(value);
- }
- #endregion
-
- #region op_Equality (Operator)
- /// <summary>
- /// Operator to check for equality
- /// </summary>
- /// <param name="a">First value of the comparison.</param>
- /// <param name="b">Second value of the comparison.</param>
- public static bool operator ==(Range a, Range b)
- {
- return b.Start == a.Start &&
- b.End == a.End;
- }
- #endregion
-
- #region op_Inequality (Operator)
- /// <summary>
- /// Operator to check for inequality
- /// </summary>
- /// <param name="a">First value of the comparison.</param>
- /// <param name="b">Second value of the comparison.</param>
- public static bool operator !=(Range a, Range b)
- {
- return b.Start != a.Start ||
- b.End != a.End;
- }
- #endregion
-
- #region GetValue (Public)
- /// <summary>
- /// Get value
- /// </summary>
- /// <param name="percentageFactor">Percentage (in the range of [0,1]) to
- /// get the value based of the set Start and End. E.g. a factor of "0.5"
- /// will return "3" for a range of [2,4].</param>
- public float GetValue(float percentageFactor)
- {
- return Start + (Difference * percentageFactor);
- }
- #endregion
-
- #region GetHashCode (Public)
- /// <summary>
- /// GetHashCode
- /// </summary>
- public override int GetHashCode()
- {
- return Start.GetHashCode() ^ End.GetHashCode();
- }
- #endregion
-
- #region Equals (Public)
- /// <summary>
- /// Equals
- /// </summary>
- /// <param name="obj">Object</param>
- public override bool Equals(object obj)
- {
- return (obj is Range)
- ? this == (Range)obj
- : base.Equals(obj);
- }
- #endregion
-
- #region ToString (Public)
- /// <summary>
- /// To string
- /// </summary>
- public override string ToString()
- {
- return "Range(Start=" + Start + ", End=" + End + ")";
- }
- #endregion
-
- /// <summary>
- /// Tests
- /// </summary>
- internal class RangeTests
- {
- #region TestConstructor
- /// <summary>
- /// Test constructor
- /// </summary>
- [Test]
- public void TestConstructor()
- {
- Range testRange = new Range(10, 1);
- Assert.Equal(testRange.Start, 10);
- Assert.Equal(testRange.End, 1);
-
- testRange = new Range(1, 2);
- Assert.Equal(testRange.Start, 1);
- Assert.Equal(testRange.End, 2);
- }
- #endregion
-
- #region TestNegativeRanges
- /// <summary>
- /// Test negative ranges
- /// </summary>
- [Test]
- public void TestNegativeRanges()
- {
- Range negativeRange = new Range(-100, 50);
- Assert.Equal(negativeRange.Start, -100);
- Assert.Equal(negativeRange.End, 50);
-
- Assert.Equal(negativeRange.GetValue(0.0f), -100);
- Assert.Equal(negativeRange.GetValue(0.5f), -25);
- Assert.Equal(negativeRange.GetValue(1.0f), 50);
-
- Assert.Between(negativeRange.RandomValue, -100, 50);
- }
- #endregion
-
- #region TestRanges
- /// <summary>
- /// Test different ranges
- /// </summary>
- [Test]
- public void TestRanges()
- {
- // Min and Max value both are assigned the given value
- Range singleRange = new Range(2);
- Assert.True(singleRange.Start == singleRange.End);
- Assert.Equal(2, singleRange.Start);
-
- // Test the implicit conversion from float
- singleRange = 4.3f;
- Assert.Equal(singleRange, new Range(4.3f));
-
- // Both values assigned still work normally too
- Range range = new Range
- {
- Start = 4,
- End = 6,
- };
- Assert.NearlyEqual(range.Start, 4);
- Assert.NearlyEqual(range.End, 6);
-
- // Test if the random value is between the boundaries
- Assert.Between(range.RandomValue, range.Start, range.End);
- Assert.Between(range.RandomValue, range.Start, range.End);
- Assert.Between(range.RandomValue, range.Start, range.End);
- }
- #endregion
-
- #region GetValue
- /// <summary>
- /// Get value
- /// </summary>
- [Test]
- public void GetValue()
- {
- Range range = new Range(10, 0);
-
- Assert.Equal(range.GetValue(0.0f), 10);
- Assert.Equal(range.GetValue(1.0f), 0);
- Assert.Equal(range.GetValue(0.5f), 5);
- }
- #endregion
- }
- }
- }