Vector2.cs 33 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249
  1. #region --- License ---
  2. /*
  3. Copyright (c) 2006 - 2008 The Open Toolkit library.
  4. Permission is hereby granted, free of charge, to any person obtaining a copy of
  5. this software and associated documentation files (the "Software"), to deal in
  6. the Software without restriction, including without limitation the rights to
  7. use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
  8. of the Software, and to permit persons to whom the Software is furnished to do
  9. so, subject to the following conditions:
  10. The above copyright notice and this permission notice shall be included in all
  11. copies or substantial portions of the Software.
  12. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  13. IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  14. FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  15. AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  16. LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  17. OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
  18. SOFTWARE.
  19. */
  20. #endregion --- License ---
  21. using System;
  22. using System.Collections.Generic;
  23. using System.ComponentModel;
  24. using System.Globalization;
  25. using System.Linq;
  26. using System.Runtime.InteropServices;
  27. namespace MatterHackers.VectorMath
  28. {
  29. /// <summary>Represents a 2D vector using two double-precision floating-point numbers.</summary>
  30. [Serializable]
  31. [StructLayout(LayoutKind.Sequential)]
  32. [TypeConverter(typeof(Vector2Converter))]
  33. public struct Vector2 : IEquatable<Vector2>
  34. {
  35. /// <summary>
  36. /// Defines an instance with all components set to positive infinity.
  37. /// </summary>
  38. public static readonly Vector2 PositiveInfinity = new Vector2(double.PositiveInfinity, double.PositiveInfinity);
  39. /// <summary>
  40. /// Defines an instance with all components set to negative infinity.
  41. /// </summary>
  42. public static readonly Vector2 NegativeInfinity = new Vector2(double.NegativeInfinity, double.NegativeInfinity);
  43. #region Fields
  44. /// <summary>The X coordinate of this instance.</summary>
  45. public double X;
  46. /// <summary>The Y coordinate of this instance.</summary>
  47. public double Y;
  48. /// <summary>
  49. /// Defines a unit-length Vector2d that points towards the X-axis.
  50. /// </summary>
  51. public static Vector2 UnitX = new Vector2(1, 0);
  52. /// <summary>
  53. /// Defines a unit-length Vector2d that points towards the Y-axis.
  54. /// </summary>
  55. public static Vector2 UnitY = new Vector2(0, 1);
  56. /// <summary>
  57. /// Defines a zero-length Vector2d.
  58. /// </summary>
  59. public static Vector2 Zero = new Vector2(0, 0);
  60. /// <summary>
  61. /// Defines an instance with all components set to 1.
  62. /// </summary>
  63. public static readonly Vector2 One = new Vector2(1, 1);
  64. /// <summary>
  65. /// Defines the size of the Vector2d struct in bytes.
  66. /// </summary>
  67. public static readonly int SizeInBytes = Marshal.SizeOf(new Vector2());
  68. #endregion Fields
  69. #region Constructors
  70. /// <summary>Constructs left vector with the given coordinates.</summary>
  71. /// <param name="x">The X coordinate.</param>
  72. /// <param name="y">The Y coordinate.</param>
  73. public Vector2(double x, double y)
  74. {
  75. this.X = x;
  76. this.Y = y;
  77. }
  78. public Vector2(Vector3 vector)
  79. {
  80. this.X = vector.X;
  81. this.Y = vector.Y;
  82. }
  83. public Vector2(Vector3Float vector)
  84. {
  85. this.X = vector.X;
  86. this.Y = vector.Y;
  87. }
  88. #endregion Constructors
  89. #region Properties
  90. public double this[int index]
  91. {
  92. get
  93. {
  94. switch (index)
  95. {
  96. case 0:
  97. return X;
  98. case 1:
  99. return Y;
  100. default:
  101. return 0;
  102. }
  103. }
  104. set
  105. {
  106. switch (index)
  107. {
  108. case 0:
  109. X = value;
  110. break;
  111. case 1:
  112. Y = value;
  113. break;
  114. default:
  115. throw new Exception();
  116. }
  117. }
  118. }
  119. /// <summary>
  120. /// return a 64 bit hash code proposed by Jon Skeet
  121. // http://stackoverflow.com/questions/8094867/good-gethashcode-override-for-list-of-foo-objects-respecting-the-order
  122. /// </summary>
  123. /// <returns></returns>
  124. public ulong GetLongHashCode(ulong hash = 14695981039346656037)
  125. {
  126. hash = Vector4.GetLongHashCode(X, hash);
  127. hash = Vector4.GetLongHashCode(Y, hash);
  128. return hash;
  129. }
  130. /// <summary>
  131. /// Get the delta angle from start to end relative to this
  132. /// </summary>
  133. /// <param name="startPosition"></param>
  134. /// <param name="endPosition"></param>
  135. public double GetDeltaAngle(Vector2 startPosition, Vector2 endPosition)
  136. {
  137. startPosition -= this;
  138. var startAngle = Math.Atan2(startPosition.Y, startPosition.X);
  139. startAngle = startAngle < 0 ? startAngle + MathHelper.Tau : startAngle;
  140. endPosition -= this;
  141. var endAngle = Math.Atan2(endPosition.Y, endPosition.X);
  142. endAngle = endAngle < 0 ? endAngle + MathHelper.Tau : endAngle;
  143. return endAngle - startAngle;
  144. }
  145. #endregion Properties
  146. #region Public Members
  147. #region Instance
  148. #region public double Length
  149. /// <summary>
  150. /// Gets the length (magnitude) of the vector.
  151. /// </summary>
  152. /// <seealso cref="LengthSquared"/>
  153. public double Length
  154. {
  155. get
  156. {
  157. return System.Math.Sqrt(X * X + Y * Y);
  158. }
  159. }
  160. public double Distance(Vector2 p)
  161. {
  162. return (this - p).Length;
  163. }
  164. #endregion public double Length
  165. #region public double LengthSquared
  166. /// <summary>
  167. /// Gets the square of the vector length (magnitude).
  168. /// </summary>
  169. /// <remarks>
  170. /// This property avoids the costly square root operation required by the Length property. This makes it more suitable
  171. /// for comparisons.
  172. /// </remarks>
  173. /// <see cref="Length"/>
  174. public double LengthSquared
  175. {
  176. get
  177. {
  178. return X * X + Y * Y;
  179. }
  180. }
  181. #endregion public double LengthSquared
  182. public void Rotate(double radians)
  183. {
  184. this = Vector2.Rotate(this, radians);
  185. }
  186. public Vector2 GetRotated(double radians)
  187. {
  188. return Vector2.Rotate(this, radians);
  189. }
  190. public double GetAngle()
  191. {
  192. return System.Math.Atan2(Y, X);
  193. }
  194. public double GetAngle0To2PI()
  195. {
  196. return MathHelper.Range0ToTau(GetAngle());
  197. }
  198. #region public Vector2d PerpendicularRight
  199. /// <summary>
  200. /// Gets the perpendicular vector on the right side of this vector.
  201. /// </summary>
  202. public Vector2 GetPerpendicularRight()
  203. {
  204. return new Vector2(Y, -X);
  205. }
  206. #endregion public Vector2d PerpendicularRight
  207. #region public Vector2d PerpendicularLeft
  208. /// <summary>
  209. /// Gets the perpendicular vector on the left side of this vector.
  210. /// </summary>
  211. public Vector2 GetPerpendicularLeft()
  212. {
  213. return new Vector2(-Y, X);
  214. }
  215. #endregion public Vector2d PerpendicularLeft
  216. #region public void Normalize()
  217. /// <summary>
  218. /// Returns a normalized Vector of this.
  219. /// </summary>
  220. /// <returns></returns>
  221. public Vector2 GetNormal()
  222. {
  223. Vector2 temp = this;
  224. temp.Normalize();
  225. return temp;
  226. }
  227. /// <summary>
  228. /// Scales the Vector2 to unit length.
  229. /// </summary>
  230. public void Normalize()
  231. {
  232. double scale = 1.0 / Length;
  233. X *= scale;
  234. Y *= scale;
  235. }
  236. #endregion public void Normalize()
  237. public bool IsValid()
  238. {
  239. if (double.IsNaN(X) || double.IsInfinity(X)
  240. || double.IsNaN(Y) || double.IsInfinity(Y))
  241. {
  242. return false;
  243. }
  244. return true;
  245. }
  246. #endregion Instance
  247. #region Static
  248. #region Add
  249. /// <summary>
  250. /// Adds two vectors.
  251. /// </summary>
  252. /// <param name="a">Left operand.</param>
  253. /// <param name="b">Right operand.</param>
  254. /// <returns>Result of operation.</returns>
  255. public static Vector2 Add(Vector2 a, Vector2 b)
  256. {
  257. Add(ref a, ref b, out a);
  258. return a;
  259. }
  260. /// <summary>
  261. /// Adds two vectors.
  262. /// </summary>
  263. /// <param name="a">Left operand.</param>
  264. /// <param name="b">Right operand.</param>
  265. /// <param name="result">Result of operation.</param>
  266. public static void Add(ref Vector2 a, ref Vector2 b, out Vector2 result)
  267. {
  268. result = new Vector2(a.X + b.X, a.Y + b.Y);
  269. }
  270. #endregion Add
  271. #region Subtract
  272. /// <summary>
  273. /// Subtract one Vector from another
  274. /// </summary>
  275. /// <param name="a">First operand</param>
  276. /// <param name="b">Second operand</param>
  277. /// <returns>Result of subtraction</returns>
  278. public static Vector2 Subtract(Vector2 a, Vector2 b)
  279. {
  280. Subtract(ref a, ref b, out a);
  281. return a;
  282. }
  283. /// <summary>
  284. /// Subtract one Vector from another
  285. /// </summary>
  286. /// <param name="a">First operand</param>
  287. /// <param name="b">Second operand</param>
  288. /// <param name="result">Result of subtraction</param>
  289. public static void Subtract(ref Vector2 a, ref Vector2 b, out Vector2 result)
  290. {
  291. result = new Vector2(a.X - b.X, a.Y - b.Y);
  292. }
  293. #endregion Subtract
  294. #region Multiply
  295. /// <summary>
  296. /// Multiplies a vector by a scalar.
  297. /// </summary>
  298. /// <param name="vector">Left operand.</param>
  299. /// <param name="scale">Right operand.</param>
  300. /// <returns>Result of the operation.</returns>
  301. public static Vector2 Multiply(Vector2 vector, double scale)
  302. {
  303. Multiply(ref vector, scale, out vector);
  304. return vector;
  305. }
  306. /// <summary>
  307. /// Multiplies a vector by a scalar.
  308. /// </summary>
  309. /// <param name="vector">Left operand.</param>
  310. /// <param name="scale">Right operand.</param>
  311. /// <param name="result">Result of the operation.</param>
  312. public static void Multiply(ref Vector2 vector, double scale, out Vector2 result)
  313. {
  314. result = new Vector2(vector.X * scale, vector.Y * scale);
  315. }
  316. /// <summary>
  317. /// Multiplies a vector by the components a vector (scale).
  318. /// </summary>
  319. /// <param name="vector">Left operand.</param>
  320. /// <param name="scale">Right operand.</param>
  321. /// <returns>Result of the operation.</returns>
  322. public static Vector2 Multiply(Vector2 vector, Vector2 scale)
  323. {
  324. Multiply(ref vector, ref scale, out vector);
  325. return vector;
  326. }
  327. /// <summary>
  328. /// Multiplies a vector by the components of a vector (scale).
  329. /// </summary>
  330. /// <param name="vector">Left operand.</param>
  331. /// <param name="scale">Right operand.</param>
  332. /// <param name="result">Result of the operation.</param>
  333. public static void Multiply(ref Vector2 vector, ref Vector2 scale, out Vector2 result)
  334. {
  335. result = new Vector2(vector.X * scale.X, vector.Y * scale.Y);
  336. }
  337. #endregion Multiply
  338. #region Divide
  339. /// <summary>
  340. /// Divides a vector by a scalar.
  341. /// </summary>
  342. /// <param name="vector">Left operand.</param>
  343. /// <param name="scale">Right operand.</param>
  344. /// <returns>Result of the operation.</returns>
  345. public static Vector2 Divide(Vector2 vector, double scale)
  346. {
  347. Divide(ref vector, scale, out vector);
  348. return vector;
  349. }
  350. /// <summary>
  351. /// Divides a vector by a scalar.
  352. /// </summary>
  353. /// <param name="vector">Left operand.</param>
  354. /// <param name="scale">Right operand.</param>
  355. /// <param name="result">Result of the operation.</param>
  356. public static void Divide(ref Vector2 vector, double scale, out Vector2 result)
  357. {
  358. Multiply(ref vector, 1 / scale, out result);
  359. }
  360. /// <summary>
  361. /// Divides a vector by the components of a vector (scale).
  362. /// </summary>
  363. /// <param name="vector">Left operand.</param>
  364. /// <param name="scale">Right operand.</param>
  365. /// <returns>Result of the operation.</returns>
  366. public static Vector2 Divide(Vector2 vector, Vector2 scale)
  367. {
  368. Divide(ref vector, ref scale, out vector);
  369. return vector;
  370. }
  371. /// <summary>
  372. /// Divide a vector by the components of a vector (scale).
  373. /// </summary>
  374. /// <param name="vector">Left operand.</param>
  375. /// <param name="scale">Right operand.</param>
  376. /// <param name="result">Result of the operation.</param>
  377. public static void Divide(ref Vector2 vector, ref Vector2 scale, out Vector2 result)
  378. {
  379. result = new Vector2(vector.X / scale.X, vector.Y / scale.Y);
  380. }
  381. #endregion Divide
  382. #region Min
  383. /// <summary>
  384. /// Calculate the component-wise minimum of two vectors
  385. /// </summary>
  386. /// <param name="a">First operand</param>
  387. /// <param name="b">Second operand</param>
  388. /// <returns>The component-wise minimum</returns>
  389. public static Vector2 Min(Vector2 a, Vector2 b)
  390. {
  391. a.X = a.X < b.X ? a.X : b.X;
  392. a.Y = a.Y < b.Y ? a.Y : b.Y;
  393. return a;
  394. }
  395. public static Vector2 Parse(string s)
  396. {
  397. var result = Vector2.Zero;
  398. var values = s.Split(',').Select(sValue =>
  399. {
  400. double number = 0;
  401. if (double.TryParse(sValue, out number))
  402. {
  403. return double.Parse(sValue);
  404. }
  405. return 0;
  406. }).ToArray();
  407. for (int i = 0; i < Math.Min(2, values.Length); i++)
  408. {
  409. result[i] = values[i];
  410. }
  411. return result;
  412. }
  413. /// <summary>
  414. /// Calculate the component-wise minimum of two vectors
  415. /// </summary>
  416. /// <param name="a">First operand</param>
  417. /// <param name="b">Second operand</param>
  418. /// <param name="result">The component-wise minimum</param>
  419. public static void Min(ref Vector2 a, ref Vector2 b, out Vector2 result)
  420. {
  421. result.X = a.X < b.X ? a.X : b.X;
  422. result.Y = a.Y < b.Y ? a.Y : b.Y;
  423. }
  424. #endregion Min
  425. #region Max
  426. /// <summary>
  427. /// Calculate the component-wise maximum of two vectors
  428. /// </summary>
  429. /// <param name="a">First operand</param>
  430. /// <param name="b">Second operand</param>
  431. /// <returns>The component-wise maximum</returns>
  432. public static Vector2 Max(Vector2 a, Vector2 b)
  433. {
  434. a.X = a.X > b.X ? a.X : b.X;
  435. a.Y = a.Y > b.Y ? a.Y : b.Y;
  436. return a;
  437. }
  438. /// <summary>
  439. /// Calculate the component-wise maximum of two vectors
  440. /// </summary>
  441. /// <param name="a">First operand</param>
  442. /// <param name="b">Second operand</param>
  443. /// <param name="result">The component-wise maximum</param>
  444. public static void Max(ref Vector2 a, ref Vector2 b, out Vector2 result)
  445. {
  446. result.X = a.X > b.X ? a.X : b.X;
  447. result.Y = a.Y > b.Y ? a.Y : b.Y;
  448. }
  449. #endregion Max
  450. #region Clamp
  451. /// <summary>
  452. /// Clamp a vector to the given minimum and maximum vectors
  453. /// </summary>
  454. /// <param name="vec">Input vector</param>
  455. /// <param name="min">Minimum vector</param>
  456. /// <param name="max">Maximum vector</param>
  457. /// <returns>The clamped vector</returns>
  458. public static Vector2 Clamp(Vector2 vec, Vector2 min, Vector2 max)
  459. {
  460. vec.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
  461. vec.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
  462. return vec;
  463. }
  464. /// <summary>
  465. /// Clamp a vector to the given minimum and maximum vectors
  466. /// </summary>
  467. /// <param name="vec">Input vector</param>
  468. /// <param name="min">Minimum vector</param>
  469. /// <param name="max">Maximum vector</param>
  470. /// <param name="result">The clamped vector</param>
  471. public static void Clamp(ref Vector2 vec, ref Vector2 min, ref Vector2 max, out Vector2 result)
  472. {
  473. result.X = vec.X < min.X ? min.X : vec.X > max.X ? max.X : vec.X;
  474. result.Y = vec.Y < min.Y ? min.Y : vec.Y > max.Y ? max.Y : vec.Y;
  475. }
  476. #endregion Clamp
  477. #region Normalize
  478. /// <summary>
  479. /// Scale a vector to unit length
  480. /// </summary>
  481. /// <param name="vec">The input vector</param>
  482. /// <returns>The normalized vector</returns>
  483. public static Vector2 Normalize(Vector2 vec)
  484. {
  485. double scale = 1.0 / vec.Length;
  486. vec.X *= scale;
  487. vec.Y *= scale;
  488. return vec;
  489. }
  490. /// <summary>
  491. /// Scale a vector to unit length
  492. /// </summary>
  493. /// <param name="vec">The input vector</param>
  494. /// <param name="result">The normalized vector</param>
  495. public static void Normalize(ref Vector2 vec, out Vector2 result)
  496. {
  497. double scale = 1.0 / vec.Length;
  498. result.X = vec.X * scale;
  499. result.Y = vec.Y * scale;
  500. }
  501. #endregion Normalize
  502. /// <summary>
  503. /// Get the distance from a point to a line. Calculate the distance to both ends and to the
  504. /// line legment and return the smallest value.
  505. /// </summary>
  506. /// <param name="point">The point to consider</param>
  507. /// <param name="lineStart">The start of the line segment to consider</param>
  508. /// <param name="lineEnd">The end of the line segment to consider</param>
  509. /// <returns>The distance from the point to the line</returns>
  510. public static double DistancePointToLine(Vector2 point, Vector2 lineStart, Vector2 lineEnd)
  511. {
  512. if (point == lineStart || point == lineEnd)
  513. {
  514. return 0;
  515. }
  516. if (lineStart == lineEnd)
  517. {
  518. return (point - lineStart).Length;
  519. }
  520. var lineDelta = lineEnd - lineStart;
  521. var lineLength = lineDelta.Length;
  522. var lineNormal = lineDelta.GetNormal();
  523. var deltaFromStart = point - lineStart;
  524. var distanceFromStart = lineNormal.Dot(deltaFromStart);
  525. // if we are within the cone of the line
  526. if (distanceFromStart >= 0 && distanceFromStart <= lineLength)
  527. {
  528. var perpendicularNormal = lineNormal.GetPerpendicularLeft();
  529. var distanceToLine = perpendicularNormal.Dot(deltaFromStart);
  530. return Math.Abs(distanceToLine);
  531. }
  532. if (distanceFromStart < 0)
  533. {
  534. return deltaFromStart.Length;
  535. }
  536. var deltaFromEnd = point - lineEnd;
  537. return deltaFromEnd.Length;
  538. }
  539. #region Dot
  540. /// <summary>
  541. /// Calculate the dot (scalar) product of two vectors
  542. /// </summary>
  543. /// <param name="left">First operand</param>
  544. /// <param name="right">Second operand</param>
  545. /// <returns>The dot product of the two inputs</returns>
  546. public static double Dot(Vector2 left, Vector2 right)
  547. {
  548. return left.X * right.X + left.Y * right.Y;
  549. }
  550. public double Dot(Vector2 b)
  551. {
  552. return X * b.X + Y * b.Y;
  553. }
  554. /// <summary>
  555. /// Calculate the dot (scalar) product of two vectors
  556. /// </summary>
  557. /// <param name="left">First operand</param>
  558. /// <param name="right">Second operand</param>
  559. /// <param name="result">The dot product of the two inputs</param>
  560. public static void Dot(ref Vector2 left, ref Vector2 right, out double result)
  561. {
  562. result = left.X * right.X + left.Y * right.Y;
  563. }
  564. #endregion Dot
  565. #region Cross
  566. /// <summary>
  567. /// Calculate the cross product of two vectors
  568. /// </summary>
  569. /// <param name="left">First operand</param>
  570. /// <param name="right">Second operand</param>
  571. /// <returns>The cross product of the two inputs</returns>
  572. public static double Cross(Vector2 left, Vector2 right)
  573. {
  574. return left.X * right.Y - left.Y * right.X;
  575. }
  576. public double Cross(Vector2 right)
  577. {
  578. return this.X * right.Y - this.Y * right.X;
  579. }
  580. #endregion Cross
  581. #region Rotate
  582. public static Vector2 Rotate(Vector2 toRotate, double radians)
  583. {
  584. Vector2 temp;
  585. Rotate(ref toRotate, radians, out temp);
  586. return temp;
  587. }
  588. public static void Rotate(ref Vector2 input, double radians, out Vector2 output)
  589. {
  590. double Cos, Sin;
  591. Cos = (double)System.Math.Cos(radians);
  592. Sin = (double)System.Math.Sin(radians);
  593. output.X = input.X * Cos - input.Y * Sin;
  594. output.Y = input.Y * Cos + input.X * Sin;
  595. }
  596. #endregion Rotate
  597. #region Lerp
  598. /// <summary>
  599. /// Returns a new Vector that is the linear blend of the 2 given Vectors
  600. /// </summary>
  601. /// <param name="a">First input vector</param>
  602. /// <param name="b">Second input vector</param>
  603. /// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
  604. /// <returns>a when blend=0, b when blend=1, and a linear combination otherwise</returns>
  605. public static Vector2 Lerp(Vector2 a, Vector2 b, double blend)
  606. {
  607. a.X = blend * (b.X - a.X) + a.X;
  608. a.Y = blend * (b.Y - a.Y) + a.Y;
  609. return a;
  610. }
  611. /// <summary>
  612. /// Returns a new Vector that is the linear blend of the 2 given Vectors
  613. /// </summary>
  614. /// <param name="a">First input vector</param>
  615. /// <param name="b">Second input vector</param>
  616. /// <param name="blend">The blend factor. a when blend=0, b when blend=1.</param>
  617. /// <param name="result">a when blend=0, b when blend=1, and a linear combination otherwise</param>
  618. public static void Lerp(ref Vector2 a, ref Vector2 b, double blend, out Vector2 result)
  619. {
  620. result.X = blend * (b.X - a.X) + a.X;
  621. result.Y = blend * (b.Y - a.Y) + a.Y;
  622. }
  623. #endregion Lerp
  624. #region Barycentric
  625. /// <summary>
  626. /// Interpolate 3 Vectors using Barycentric coordinates
  627. /// </summary>
  628. /// <param name="a">First input Vector</param>
  629. /// <param name="b">Second input Vector</param>
  630. /// <param name="c">Third input Vector</param>
  631. /// <param name="u">First Barycentric Coordinate</param>
  632. /// <param name="v">Second Barycentric Coordinate</param>
  633. /// <returns>a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</returns>
  634. public static Vector2 BaryCentric(Vector2 a, Vector2 b, Vector2 c, double u, double v)
  635. {
  636. return a + u * (b - a) + v * (c - a);
  637. }
  638. /// <summary>Interpolate 3 Vectors using Barycentric coordinates</summary>
  639. /// <param name="a">First input Vector.</param>
  640. /// <param name="b">Second input Vector.</param>
  641. /// <param name="c">Third input Vector.</param>
  642. /// <param name="u">First Barycentric Coordinate.</param>
  643. /// <param name="v">Second Barycentric Coordinate.</param>
  644. /// <param name="result">Output Vector. a when u=v=0, b when u=1,v=0, c when u=0,v=1, and a linear combination of a,b,c otherwise</param>
  645. public static void BaryCentric(ref Vector2 a, ref Vector2 b, ref Vector2 c, double u, double v, out Vector2 result)
  646. {
  647. result = a; // copy
  648. Vector2 temp = b; // copy
  649. Subtract(ref temp, ref a, out temp);
  650. Multiply(ref temp, u, out temp);
  651. Add(ref result, ref temp, out result);
  652. temp = c; // copy
  653. Subtract(ref temp, ref a, out temp);
  654. Multiply(ref temp, v, out temp);
  655. Add(ref result, ref temp, out result);
  656. }
  657. #endregion Barycentric
  658. #region Transform
  659. /// <summary>
  660. /// Transforms a vector by a quaternion rotation.
  661. /// </summary>
  662. /// <param name="vec">The vector to transform.</param>
  663. /// <param name="quat">The quaternion to rotate the vector by.</param>
  664. /// <returns>The result of the operation.</returns>
  665. public static Vector2 Transform(Vector2 vec, Quaternion quat)
  666. {
  667. Vector2 result;
  668. Transform(ref vec, ref quat, out result);
  669. return result;
  670. }
  671. /// <summary>
  672. /// Transforms a vector by a quaternion rotation.
  673. /// </summary>
  674. /// <param name="vec">The vector to transform.</param>
  675. /// <param name="quat">The quaternion to rotate the vector by.</param>
  676. /// <param name="result">The result of the operation.</param>
  677. public static void Transform(ref Vector2 vec, ref Quaternion quat, out Vector2 result)
  678. {
  679. Quaternion v = new Quaternion(vec.X, vec.Y, 0, 0), i, t;
  680. Quaternion.Invert(ref quat, out i);
  681. Quaternion.Multiply(ref quat, ref v, out t);
  682. Quaternion.Multiply(ref t, ref i, out v);
  683. result = new Vector2(v.X, v.Y);
  684. }
  685. #endregion Transform
  686. #region ComponentMin
  687. /// <summary>
  688. /// Calculate the component-wise minimum of two vectors
  689. /// </summary>
  690. /// <param name="a">First operand</param>
  691. /// <param name="b">Second operand</param>
  692. /// <returns>The component-wise minimum</returns>
  693. public static Vector2 ComponentMin(Vector2 a, Vector2 b)
  694. {
  695. a.X = a.X < b.X ? a.X : b.X;
  696. a.Y = a.Y < b.Y ? a.Y : b.Y;
  697. return a;
  698. }
  699. /// <summary>
  700. /// Calculate the component-wise minimum of two vectors
  701. /// </summary>
  702. /// <param name="a">First operand</param>
  703. /// <param name="b">Second operand</param>
  704. /// <param name="result">The component-wise minimum</param>
  705. public static void ComponentMin(ref Vector2 a, ref Vector2 b, out Vector2 result)
  706. {
  707. result.X = a.X < b.X ? a.X : b.X;
  708. result.Y = a.Y < b.Y ? a.Y : b.Y;
  709. }
  710. #endregion ComponentMin
  711. #region ComponentMax
  712. /// <summary>
  713. /// Calculate the component-wise maximum of two vectors
  714. /// </summary>
  715. /// <param name="a">First operand</param>
  716. /// <param name="b">Second operand</param>
  717. /// <returns>The component-wise maximum</returns>
  718. public static Vector2 ComponentMax(Vector2 a, Vector2 b)
  719. {
  720. a.X = a.X > b.X ? a.X : b.X;
  721. a.Y = a.Y > b.Y ? a.Y : b.Y;
  722. return a;
  723. }
  724. /// <summary>
  725. /// Calculate the component-wise maximum of two vectors
  726. /// </summary>
  727. /// <param name="a">First operand</param>
  728. /// <param name="b">Second operand</param>
  729. /// <param name="result">The component-wise maximum</param>
  730. public static void ComponentMax(ref Vector2 a, ref Vector2 b, out Vector2 result)
  731. {
  732. result.X = a.X > b.X ? a.X : b.X;
  733. result.Y = a.Y > b.Y ? a.Y : b.Y;
  734. }
  735. #endregion ComponentMax
  736. #endregion Static
  737. #region Operators
  738. /// <summary>
  739. /// Adds two instances.
  740. /// </summary>
  741. /// <param name="left">The left instance.</param>
  742. /// <param name="right">The right instance.</param>
  743. /// <returns>The result of the operation.</returns>
  744. public static Vector2 operator +(Vector2 left, Vector2 right)
  745. {
  746. left.X += right.X;
  747. left.Y += right.Y;
  748. return left;
  749. }
  750. /// <summary>
  751. /// Subtracts two instances.
  752. /// </summary>
  753. /// <param name="left">The left instance.</param>
  754. /// <param name="right">The right instance.</param>
  755. /// <returns>The result of the operation.</returns>
  756. public static Vector2 operator -(Vector2 left, Vector2 right)
  757. {
  758. left.X -= right.X;
  759. left.Y -= right.Y;
  760. return left;
  761. }
  762. /// <summary>
  763. /// Negates an instance.
  764. /// </summary>
  765. /// <param name="vec">The instance.</param>
  766. /// <returns>The result of the operation.</returns>
  767. public static Vector2 operator -(Vector2 vec)
  768. {
  769. vec.X = -vec.X;
  770. vec.Y = -vec.Y;
  771. return vec;
  772. }
  773. /// <summary>
  774. /// Multiplies an instance by a scalar.
  775. /// </summary>
  776. /// <param name="vec">The instance.</param>
  777. /// <param name="f">The scalar.</param>
  778. /// <returns>The result of the operation.</returns>
  779. public static Vector2 operator *(Vector2 vec, double f)
  780. {
  781. vec.X *= f;
  782. vec.Y *= f;
  783. return vec;
  784. }
  785. /// <summary>
  786. /// Multiply an instance by a scalar.
  787. /// </summary>
  788. /// <param name="f">The scalar.</param>
  789. /// <param name="vec">The instance.</param>
  790. /// <returns>The result of the operation.</returns>
  791. public static Vector2 operator *(double f, Vector2 vec)
  792. {
  793. vec.X *= f;
  794. vec.Y *= f;
  795. return vec;
  796. }
  797. /// <summary>
  798. /// Divides an instance by a scalar.
  799. /// </summary>
  800. /// <param name="vec">The instance.</param>
  801. /// <param name="f">The scalar.</param>
  802. /// <returns>The result of the operation.</returns>
  803. public static Vector2 operator /(Vector2 vec, double f)
  804. {
  805. double mult = 1.0 / f;
  806. vec.X *= mult;
  807. vec.Y *= mult;
  808. return vec;
  809. }
  810. /// <summary>
  811. /// Divides a scaler by an instance components wise.
  812. /// </summary>
  813. /// <param name="vec">The scalar.</param>
  814. /// <param name="f">The instance.</param>
  815. /// <returns>The result of the operation.</returns>
  816. public static Vector2 operator /(double f, Vector2 vec)
  817. {
  818. vec.X = f / vec.X;
  819. vec.Y = f / vec.Y;
  820. return vec;
  821. }
  822. /// <summary>
  823. /// Compares two instances for equality.
  824. /// </summary>
  825. /// <param name="left">The left instance.</param>
  826. /// <param name="right">The right instance.</param>
  827. /// <returns>True, if both instances are equal; false otherwise.</returns>
  828. public static bool operator ==(Vector2 left, Vector2 right)
  829. {
  830. return left.Equals(right);
  831. }
  832. /// <summary>
  833. /// Compares two instances for ienquality.
  834. /// </summary>
  835. /// <param name="left">The left instance.</param>
  836. /// <param name="right">The right instance.</param>
  837. /// <returns>True, if the instances are not equal; false otherwise.</returns>
  838. public static bool operator !=(Vector2 left, Vector2 right)
  839. {
  840. return !left.Equals(right);
  841. }
  842. #endregion Operators
  843. #region Overrides
  844. #region public override string ToString()
  845. /// <summary>
  846. /// Returns a System.String that represents the current instance.
  847. /// </summary>
  848. /// <returns></returns>
  849. public override string ToString()
  850. {
  851. return String.Format("({0}, {1})", X, Y);
  852. }
  853. #endregion public override string ToString()
  854. #region public override int GetHashCode()
  855. /// <summary>
  856. /// Returns the hashcode for this instance.
  857. /// </summary>
  858. /// <returns>A System.Int32 containing the unique hashcode for this instance.</returns>
  859. public override int GetHashCode()
  860. {
  861. return new { X, Y }.GetHashCode();
  862. }
  863. #endregion public override int GetHashCode()
  864. #region public override bool Equals(object obj)
  865. /// <summary>
  866. /// Indicates whether this instance and a specified object are equal.
  867. /// </summary>
  868. /// <param name="obj">The object to compare to.</param>
  869. /// <returns>True if the instances are equal; false otherwise.</returns>
  870. public override bool Equals(object obj)
  871. {
  872. if (!(obj is Vector2))
  873. return false;
  874. return this.Equals((Vector2)obj);
  875. }
  876. #endregion public override bool Equals(object obj)
  877. #endregion Overrides
  878. #endregion Public Members
  879. #region IEquatable<Vector2d> Members
  880. /// <summary>Indicates whether the current vector is equal to another vector.</summary>
  881. /// <param name="other">A vector to compare with this vector.</param>
  882. /// <returns>true if the current vector is equal to the vector parameter; otherwise, false.</returns>
  883. public bool Equals(Vector2 other)
  884. {
  885. return
  886. X == other.X &&
  887. Y == other.Y;
  888. }
  889. /// <summary>Indicates whether the current vector is equal to another vector.</summary>
  890. /// <param name="other">A vector to compare with this vector.</param>
  891. /// <returns>true if the current vector is equal to the vector parameter; otherwise, false.</returns>
  892. public bool Equals(Vector2 other, double errorRange)
  893. {
  894. if ((X < other.X + errorRange && X > other.X - errorRange) &&
  895. (Y < other.Y + errorRange && Y > other.Y - errorRange))
  896. {
  897. return true;
  898. }
  899. return false;
  900. }
  901. #endregion IEquatable<Vector2d> Members
  902. }
  903. public static class Vector2Ex
  904. {
  905. public static double PolygonLength(this List<Vector2> polygon, bool isClosed = true)
  906. {
  907. var length = 0.0;
  908. if (polygon.Count > 1)
  909. {
  910. var previousPoint = polygon[0];
  911. if (isClosed)
  912. {
  913. previousPoint = polygon[polygon.Count - 1];
  914. }
  915. for (int i = isClosed ? 0 : 1; i < polygon.Count; i++)
  916. {
  917. var currentPoint = polygon[i];
  918. length += (previousPoint - currentPoint).Length;
  919. previousPoint = currentPoint;
  920. }
  921. }
  922. return length;
  923. }
  924. public static double LengthTo(this List<Vector2> polygon, int index, bool isClosed = true)
  925. {
  926. var length = 0.0;
  927. index = Math.Max(0, Math.Min(polygon.Count - 1, index));
  928. for (int i = 1; i <= index; i++)
  929. {
  930. length += (polygon[i] - polygon[i - 1]).Length;
  931. }
  932. return length;
  933. }
  934. /// <summary>
  935. /// Get the position of a point that is lengthFromStart distance around the perimeter.
  936. /// </summary>
  937. /// <param name="polygon">The polygon to find the position on</param>
  938. /// <param name="lengthFromStart">The distance around the perimeter form the start</param>
  939. /// <param name="closed">The polygon loops back on itself. There is a segment between the
  940. /// last and the first point, if they are not the same</param>
  941. /// <returns>The position on the perimeter</returns>
  942. public static Vector2 GetPositionAt(this List<Vector2> polygon, double lengthFromStart, bool closed = true)
  943. {
  944. var totalLength = polygon.PolygonLength();
  945. if (lengthFromStart > totalLength)
  946. {
  947. if (closed)
  948. {
  949. var ratio = lengthFromStart / totalLength;
  950. var times = (int)ratio;
  951. var remainder = ratio - times;
  952. lengthFromStart = remainder * totalLength;
  953. }
  954. else
  955. {
  956. return polygon[polygon.Count - 1];
  957. }
  958. }
  959. else if (lengthFromStart <= 0)
  960. {
  961. if (closed)
  962. {
  963. var ratio = lengthFromStart / totalLength;
  964. var times = (int)ratio;
  965. var remainder = ratio - times;
  966. lengthFromStart = (1 + remainder) * totalLength;
  967. }
  968. else
  969. {
  970. return polygon[0];
  971. }
  972. }
  973. var position = new Vector2();
  974. var length = 0.0;
  975. if (polygon.Count > 1)
  976. {
  977. position = polygon[0];
  978. var currentPoint = polygon[0];
  979. int polygonCount = polygon.Count;
  980. for (int i = 1; i < (closed ? polygonCount + 1 : polygonCount); i++)
  981. {
  982. var nextPoint = polygon[(polygonCount + i) % polygonCount];
  983. var segmentLength = (nextPoint - currentPoint).Length;
  984. if (length + segmentLength > lengthFromStart)
  985. {
  986. // return the distance along this segment
  987. var distanceAlongThisSegment = lengthFromStart - length;
  988. var delteFromCurrent = (nextPoint - currentPoint) * distanceAlongThisSegment / segmentLength;
  989. return currentPoint + delteFromCurrent;
  990. }
  991. position = nextPoint;
  992. length += segmentLength;
  993. currentPoint = nextPoint;
  994. }
  995. }
  996. return position;
  997. }
  998. public static double GetTurnAmount(this Vector2 currentPoint, Vector2 prevPoint, Vector2 nextPoint)
  999. {
  1000. if (prevPoint != currentPoint
  1001. && currentPoint != nextPoint
  1002. && nextPoint != prevPoint)
  1003. {
  1004. prevPoint = currentPoint - prevPoint;
  1005. nextPoint -= currentPoint;
  1006. double prevAngle = Math.Atan2(prevPoint.Y, prevPoint.X);
  1007. Vector2 rotatedPrev = prevPoint.GetRotated(-prevAngle);
  1008. // undo the rotation
  1009. nextPoint = nextPoint.GetRotated(-prevAngle);
  1010. double angle = Math.Atan2(nextPoint.Y, nextPoint.X);
  1011. return angle;
  1012. }
  1013. return 0;
  1014. }
  1015. }
  1016. public class Vector2Converter : TypeConverter
  1017. {
  1018. public override bool CanConvertFrom(ITypeDescriptorContext context, Type sourceType)
  1019. {
  1020. return sourceType == typeof(string) || base.CanConvertFrom(context, sourceType);
  1021. }
  1022. public override object ConvertFrom(ITypeDescriptorContext context, CultureInfo culture, object value)
  1023. {
  1024. string stringValue = value as string;
  1025. if (!string.IsNullOrEmpty(stringValue)
  1026. && stringValue.Length > 3)
  1027. {
  1028. stringValue = stringValue.Substring(1, stringValue.Length - 2);
  1029. var values = stringValue.Split(',').Select(s =>
  1030. {
  1031. double.TryParse(s, out double result);
  1032. return result;
  1033. }).ToArray();
  1034. switch (values.Length)
  1035. {
  1036. case 1:
  1037. return new Vector2(values[0], values[0]);
  1038. case 2:
  1039. return new Vector2(values[0], values[1]);
  1040. default:
  1041. return 0;
  1042. }
  1043. }
  1044. return base.ConvertFrom(context, culture, value);
  1045. }
  1046. }
  1047. }