PageRenderTime 176ms CodeModel.GetById 46ms app.highlight 55ms RepoModel.GetById 51ms app.codeStats 1ms

/Utilities/Math/VectorRange.cs

#
C# | 361 lines | 234 code | 34 blank | 93 comment | 13 complexity | 0c645acea9ab5e364a6e0f75c86bf8ea MD5 | raw file
  1using System;
  2using System.Diagnostics;
  3using System.IO;
  4using System.Runtime.InteropServices;
  5using Delta.Utilities.Datatypes;
  6using Delta.Utilities.Helpers;
  7using NUnit.Framework;
  8
  9namespace Delta.Utilities.Math
 10{
 11	/// <summary>
 12	/// The VectorRange object is used to store one or two vectors, which
 13	/// result in a 3D range.
 14	/// </summary>
 15	[StructLayout(LayoutKind.Sequential)]
 16	[DebuggerDisplay("VectorRange(Start={Start}, End={End})")]
 17	public struct VectorRange : ISaveLoadBinary
 18	{
 19		#region Constants
 20		/// <summary>
 21		/// Zero range, will always return 0.
 22		/// </summary>
 23		public static readonly VectorRange Zero = new VectorRange(Vector.Zero);
 24
 25		/// <summary>
 26		/// One range, will always return 1.
 27		/// </summary>
 28		public static readonly VectorRange One = new VectorRange(Vector.One);
 29
 30		/// <summary>
 31		/// Zero to One range, will return a random values between 0 and 1.
 32		/// </summary>
 33		public static readonly VectorRange ZeroToOne =
 34			new VectorRange(Vector.Zero, Vector.One);
 35		#endregion
 36
 37		#region Start (Public)
 38		/// <summary>
 39		/// Start value of the range.
 40		/// </summary>
 41		public Vector Start
 42		{
 43			get
 44			{
 45				return internalStart;
 46			}
 47			set
 48			{
 49				if (internalStart != value)
 50				{
 51					internalStart = value;
 52					Difference = End - Start;
 53				}
 54			}
 55		}
 56		#endregion
 57
 58		#region End (Public)
 59		/// <summary>
 60		/// End value of the range.
 61		/// </summary>
 62		public Vector End
 63		{
 64			get
 65			{
 66				return internalEnd;
 67			}
 68			set
 69			{
 70				if (internalEnd != value)
 71				{
 72					internalEnd = value;
 73					Difference = End - Start;
 74				}
 75			}
 76		}
 77		#endregion
 78
 79		#region Difference (Public)
 80		/// <summary>
 81		/// Difference between Start and End.
 82		/// </summary>
 83		public Vector Difference
 84		{
 85			get;
 86			private set;
 87		}
 88		#endregion
 89
 90		#region RandomValue (Public)
 91		/// <summary>
 92		/// Returns a random value between Start and End.
 93		/// </summary>
 94		/// <returns>Float</returns>
 95		public Vector RandomValue
 96		{
 97			get
 98			{
 99				// Note: We do not need to randomize if start is the same value as end
100				if (Start == End)
101				{
102					return Start;
103				}
104
105				return new Vector(RandomHelper.RandomFloat(Start.X, End.X),
106					RandomHelper.RandomFloat(Start.Y, End.Y),
107					RandomHelper.RandomFloat(Start.Z, End.Z));
108			}
109		}
110		#endregion
111
112		#region Private
113
114		#region internalStart (Private)
115		private Vector internalStart;
116		#endregion
117
118		#region internalEnd (Private)
119		private Vector internalEnd;
120		#endregion
121
122		#endregion
123
124		#region Constructors
125		/// <summary>
126		/// Create range with fixed value.
127		/// </summary>
128		/// <param name="setStartAndEndValue">Set start and end value</param>
129		public VectorRange(Vector setStartAndEndValue)
130			: this()
131		{
132			Start = setStartAndEndValue;
133			End = setStartAndEndValue;
134		}
135
136		/// <summary>
137		/// Create range with given minimum and maximum values.
138		/// </summary>
139		/// <param name="setStartValue">Set start value</param>
140		/// <param name="setEndValue">Set end value</param>
141		public VectorRange(Vector setStartValue, Vector setEndValue)
142			: this()
143		{
144			Start = setStartValue;
145			End = setEndValue;
146		}
147		#endregion
148
149		#region ISaveLoadBinary Members
150		/// <summary>
151		/// Loads VectorRange from a stream (just Start and End).
152		/// </summary>
153		/// <param name="reader">The stream that will be used.</param>
154		public void Load(BinaryReader reader)
155		{
156			Start.Load(reader);
157			End.Load(reader);
158		}
159
160		/// <summary>
161		/// Saves VectorRange to a stream (just Start and End).
162		/// </summary>
163		/// <param name="writer">The stream that will be used.</param>
164		public void Save(BinaryWriter writer)
165		{
166			Start.Save(writer);
167			End.Save(writer);
168		}
169		#endregion
170
171		#region op_Implicit (Operator)
172		/// <summary>
173		/// Operator to assign a vector range from vector value.
174		/// </summary>
175		public static implicit operator VectorRange(Vector value)
176		{
177			return new VectorRange(value);
178		}
179		#endregion
180
181		#region op_Equality (Operator)
182		/// <summary>
183		/// Operator to check for equality
184		/// </summary>
185		/// <param name="a">First value of the comparison.</param>
186		/// <param name="b">Second value of the comparison.</param>
187		public static bool operator ==(VectorRange a, VectorRange b)
188		{
189			return b.Start == a.Start &&
190			       b.End == a.End;
191		}
192		#endregion
193
194		#region op_Inequality (Operator)
195		/// <summary>
196		/// Operator to check for inequality
197		/// </summary>
198		/// <param name="a">First value of the comparison.</param>
199		/// <param name="b">Second value of the comparison.</param>
200		public static bool operator !=(VectorRange a, VectorRange b)
201		{
202			return b.Start != a.Start ||
203			       b.End != a.End;
204		}
205		#endregion
206
207		#region GetValue (Public)
208		/// <summary>
209		/// Get value
210		/// </summary>
211		/// <param name="percentageFactor">Percentage (in the range of [0,1]) to
212		/// get the value based of the set Start and End. E.g. a factor of "0.5"
213		/// will return "3" for a range of [2,4].</param>
214		public Vector GetValue(float percentageFactor)
215		{
216			return Start + (Difference * percentageFactor);
217		}
218		#endregion
219
220		#region GetHashCode (Public)
221		/// <summary>
222		/// GetHashCode
223		/// </summary>
224		public override int GetHashCode()
225		{
226			return Start.GetHashCode() ^ End.GetHashCode();
227		}
228		#endregion
229
230		#region Equals (Public)
231		/// <summary>
232		/// Equals
233		/// </summary>
234		/// <param name="obj">Object</param>
235		public override bool Equals(object obj)
236		{
237			return (obj is VectorRange)
238			       	? this == (VectorRange)obj
239			       	: base.Equals(obj);
240		}
241		#endregion
242
243		#region ToString (Public)
244		/// <summary>
245		/// To string
246		/// </summary>
247		public override string ToString()
248		{
249			return "Vector(Start=" + Start + ", End=" + End + ")";
250		}
251		#endregion
252
253		/// <summary>
254		/// Tests
255		/// </summary>
256		internal class VectorRangeTests
257		{
258			#region TestConstructor
259			/// <summary>
260			/// Test constructor
261			/// </summary>
262			[Test]
263			public void TestConstructor()
264			{
265				VectorRange testRange = new VectorRange(
266					new Vector(10, 5, 4),
267					new Vector(1, 6, 3));
268				Assert.Equal(testRange.Start.X, 10);
269				Assert.Equal(testRange.Start.Y, 5);
270				Assert.Equal(testRange.Start.Z, 4);
271				Assert.Equal(testRange.End.X, 1);
272				Assert.Equal(testRange.End.Y, 6);
273				Assert.Equal(testRange.End.Z, 3);
274
275				testRange = new VectorRange(new Vector(10, 5, 4));
276				Assert.Equal(testRange.Start.X, 10);
277				Assert.Equal(testRange.Start.Y, 5);
278				Assert.Equal(testRange.Start.Z, 4);
279				Assert.Equal(testRange.End.X, 10);
280				Assert.Equal(testRange.End.Y, 5);
281				Assert.Equal(testRange.End.Z, 4);
282			}
283			#endregion
284
285			#region TestNegativeRanges
286			/// <summary>
287			/// Test negative ranges
288			/// </summary>
289			[Test]
290			public void TestNegativeRanges()
291			{
292				Vector start = new Vector(-10f, -20f, -5f);
293				Vector end = new Vector(10f, 20f, 5f);
294				VectorRange negativeRange = new VectorRange(start, end);
295
296				Assert.Equal(negativeRange.GetValue(0.0f), start);
297				Assert.Equal(negativeRange.GetValue(0.5f), new Vector(0f, 0f, 0f));
298				Assert.Equal(negativeRange.GetValue(1.0f), end);
299
300				Vector randomValue = negativeRange.RandomValue;
301				Assert.Between(randomValue.X, start.X, end.X);
302				Assert.Between(randomValue.Y, start.Y, end.Y);
303				Assert.Between(randomValue.Z, start.Z, end.Z);
304			}
305			#endregion
306
307			#region TestRanges
308			/// <summary>
309			/// Test different ranges
310			/// </summary>
311			[Test]
312			public void TestRanges()
313			{
314				// Min and Max value both are assigned the given value
315				VectorRange singleRange = new VectorRange(new Vector(2, 5, 4));
316				Assert.True(singleRange.Start == singleRange.End);
317				Assert.Equal(new Vector(2, 5, 4), singleRange.Start);
318
319				// Test the implicit conversion from vector
320				singleRange = new Vector(4.3f, 1.2f, 4f);
321				Assert.Equal(singleRange, new VectorRange(new Vector(4.3f, 1.2f, 4f)));
322			}
323			#endregion
324
325			#region GetValue
326			/// <summary>
327			/// Get value
328			/// </summary>
329			[Test]
330			public void GetValue()
331			{
332				VectorRange range = new VectorRange(
333					new Vector(10, 5, 12), Vector.Zero);
334
335				Assert.Equal(range.GetValue(0f), new Vector(10, 5, 12));
336				Assert.Equal(range.GetValue(0.5f), new Vector(5f, 2.5f, 6f));
337				Assert.Equal(range.GetValue(1f), new Vector(0, 0, 0));
338			}
339			#endregion
340
341			#region GetValueLogging
342			/// <summary>
343			/// Get value logging test
344			/// </summary>
345			[Test]
346			public void GetValueLogging()
347			{
348				Vector start = new Vector(-10f, -20f, -5f);
349				Vector end = new Vector(10f, 20f, 5f);
350				VectorRange negativeRange = new VectorRange(start, end);
351
352				for (float pos = 0.0f; pos <= 1.01f; pos += 0.1f)
353				{
354					Console.WriteLine(pos.ToString("0.0") + " > " +
355					                  negativeRange.GetValue(pos));
356				}
357			}
358			#endregion
359		}
360	}
361}