PageRenderTime 81ms CodeModel.GetById 46ms RepoModel.GetById 0ms app.codeStats 0ms

/Utilities/Math/VectorRange.cs

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