PrimitivesHelper.cs 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Runtime.CompilerServices;
  4. using Microsoft.Xna.Framework;
  5. namespace MonoGame.Extended
  6. {
  7. internal class PrimitivesHelper
  8. {
  9. // Used by Ray2 and Segment2
  10. internal static bool IntersectsSlab(float positionCoordinate, float directionCoordinate, float slabMinimum,
  11. float slabMaximum, ref float rayMinimumDistance, ref float rayMaximumDistance)
  12. {
  13. // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 5.3; Basic Primitive Tests - Intersecting Lines, Rays, and (Directed Segments). pg 179-181
  14. if (Math.Abs(directionCoordinate) < float.Epsilon)
  15. return (positionCoordinate >= slabMinimum) && (positionCoordinate <= slabMaximum);
  16. // Compute intersection values of ray with near and far plane of slab
  17. var rayNearDistance = (slabMinimum - positionCoordinate)/directionCoordinate;
  18. var rayFarDistance = (slabMaximum - positionCoordinate)/directionCoordinate;
  19. if (rayNearDistance > rayFarDistance)
  20. {
  21. // Swap near and far distance
  22. var temp = rayNearDistance;
  23. rayNearDistance = rayFarDistance;
  24. rayFarDistance = temp;
  25. }
  26. // Compute the intersection of slab intersection intervals
  27. rayMinimumDistance = rayNearDistance > rayMinimumDistance ? rayNearDistance : rayMinimumDistance;
  28. rayMaximumDistance = rayFarDistance < rayMaximumDistance ? rayFarDistance : rayMaximumDistance;
  29. // Exit with no collision as soon as slab intersection becomes empty
  30. return rayMinimumDistance <= rayMaximumDistance;
  31. }
  32. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  33. internal static void CreateRectangleFromPoints(IReadOnlyList<Vector2> points, out Vector2 minimum, out Vector2 maximum)
  34. {
  35. // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 82-84
  36. if (points == null || points.Count == 0)
  37. {
  38. minimum = Vector2.Zero;
  39. maximum = Vector2.Zero;
  40. return;
  41. }
  42. minimum = maximum = points[0];
  43. // ReSharper disable once ForCanBeConvertedToForeach
  44. for (var index = points.Count - 1; index > 0; --index)
  45. {
  46. var point = points[index];
  47. minimum = MathExtended.CalculateMinimumVector2(minimum, point);
  48. maximum = MathExtended.CalculateMaximumVector2(maximum, point);
  49. }
  50. }
  51. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  52. internal static void TransformRectangle(ref Vector2 center, ref Vector2 halfExtents, ref Matrix3x2 transformMatrix)
  53. {
  54. // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.2; Bounding Volumes - Axis-aligned Bounding Boxes (AABBs). pg 86-87
  55. center = transformMatrix.Transform(center);
  56. var xRadius = halfExtents.X;
  57. var yRadius = halfExtents.Y;
  58. halfExtents.X = xRadius * Math.Abs(transformMatrix.M11) + yRadius * Math.Abs(transformMatrix.M12);
  59. halfExtents.Y = xRadius * Math.Abs(transformMatrix.M21) + yRadius * Math.Abs(transformMatrix.M22);
  60. }
  61. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  62. internal static void TransformOrientedRectangle(
  63. ref Vector2 center,
  64. ref Matrix3x2 orientation,
  65. ref Matrix3x2 transformMatrix)
  66. {
  67. // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 4.4; Oriented Bounding Boxes (OBBs), pg 101-105.
  68. center = transformMatrix.Transform(center);
  69. orientation *= transformMatrix;
  70. // Reset the translation since orientation is only about rotation
  71. orientation.M31 = 0;
  72. orientation.M32 = 0;
  73. }
  74. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  75. internal static float SquaredDistanceToPointFromRectangle(Vector2 minimum, Vector2 maximum, Vector2 point)
  76. {
  77. // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 5.1.3.1; Basic Primitive Tests - Closest-point Computations - Distance of Point to AABB. pg 130-131
  78. var squaredDistance = 0.0f;
  79. // for each axis add up the excess distance outside the box
  80. // x-axis
  81. if (point.X < minimum.X)
  82. {
  83. var distance = minimum.X - point.X;
  84. squaredDistance += distance * distance;
  85. }
  86. else if (point.X > maximum.X)
  87. {
  88. var distance = maximum.X - point.X;
  89. squaredDistance += distance * distance;
  90. }
  91. // y-axis
  92. if (point.Y < minimum.Y)
  93. {
  94. var distance = minimum.Y - point.Y;
  95. squaredDistance += distance * distance;
  96. }
  97. else if (point.Y > maximum.Y)
  98. {
  99. var distance = maximum.Y - point.Y;
  100. squaredDistance += distance * distance;
  101. }
  102. return squaredDistance;
  103. }
  104. [MethodImpl(MethodImplOptions.AggressiveInlining)]
  105. internal static void ClosestPointToPointFromRectangle(Vector2 minimum, Vector2 maximum, Vector2 point, out Vector2 result)
  106. {
  107. // Real-Time Collision Detection, Christer Ericson, 2005. Chapter 5.1.2; Basic Primitive Tests - Closest-point Computations. pg 130-131
  108. result = point;
  109. // For each coordinate axis, if the point coordinate value is outside box, clamp it to the box, else keep it as is
  110. if (result.X < minimum.X)
  111. result.X = minimum.X;
  112. else if (result.X > maximum.X)
  113. result.X = maximum.X;
  114. if (result.Y < minimum.Y)
  115. result.Y = minimum.Y;
  116. else if (result.Y > maximum.Y)
  117. result.Y = maximum.Y;
  118. }
  119. }
  120. }