GraphUpdateShape.cs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143
  1. using UnityEngine;
  2. namespace Pathfinding {
  3. /// <summary>
  4. /// Defines a shape for a Pathfinding.GraphUpdateObject.
  5. /// The shape consists of a number of points which it can either calculate the convex hull of or use as a polygon directly.
  6. ///
  7. /// A shape is essentially a 2D shape however it can be rotated arbitrarily.
  8. /// When a matrix and a list of points is specified in the constructor the matrix decides what direction
  9. /// is the 'up' direction. When checking if a point is contained in the shape, the point will be projected down
  10. /// on a plane where the 'up' direction is the normal and then it will check if the shape contains the point.
  11. ///
  12. /// See: Pathfinding.GraphUpdateObject.shape
  13. /// </summary>
  14. public class GraphUpdateShape {
  15. Vector3[] _points;
  16. Vector3[] _convexPoints;
  17. bool _convex;
  18. Vector3 right = Vector3.right;
  19. Vector3 forward = Vector3.forward;
  20. Vector3 up = Vector3.up;
  21. Vector3 origin;
  22. public float minimumHeight;
  23. /// <summary>
  24. /// Gets or sets the points of the polygon in the shape.
  25. /// These points should be specified in clockwise order.
  26. /// Will automatically calculate the convex hull if <see cref="convex"/> is set to true
  27. /// </summary>
  28. public Vector3[] points {
  29. get {
  30. return _points;
  31. }
  32. set {
  33. _points = value;
  34. if (convex) CalculateConvexHull();
  35. }
  36. }
  37. /// <summary>
  38. /// Sets if the convex hull of the points should be calculated.
  39. /// Convex hulls are faster but non-convex hulls can be used to specify more complicated shapes.
  40. /// </summary>
  41. public bool convex {
  42. get {
  43. return _convex;
  44. }
  45. set {
  46. if (_convex != value && value) {
  47. CalculateConvexHull();
  48. }
  49. _convex = value;
  50. }
  51. }
  52. public GraphUpdateShape () {
  53. }
  54. /// <summary>
  55. /// Construct a shape.
  56. /// See: <see cref="convex"/>
  57. /// </summary>
  58. /// <param name="points">Contour of the shape in local space with respect to the matrix (i.e the shape should be in the XZ plane, the Y coordinate will only affect the bounds)</param>
  59. /// <param name="convex">If true, the convex hull of the points will be calculated.</param>
  60. /// <param name="matrix">local to world space matrix for the points. The matrix determines the up direction of the shape.</param>
  61. /// <param name="minimumHeight">If the points would be in the XZ plane only, the shape would not have a height and then it might not
  62. /// include any points inside it (as testing for inclusion is done in 3D space when updating graphs). This ensures
  63. /// that the shape has at least the minimum height (in the up direction that the matrix specifies).</param>
  64. public GraphUpdateShape (Vector3[] points, bool convex, Matrix4x4 matrix, float minimumHeight) {
  65. this.convex = convex;
  66. this.points = points;
  67. origin = matrix.MultiplyPoint3x4(Vector3.zero);
  68. right = matrix.MultiplyPoint3x4(Vector3.right) - origin;
  69. up = matrix.MultiplyPoint3x4(Vector3.up) - origin;
  70. forward = matrix.MultiplyPoint3x4(Vector3.forward) - origin;
  71. this.minimumHeight = minimumHeight;
  72. }
  73. void CalculateConvexHull () {
  74. _convexPoints = points != null? Polygon.ConvexHullXZ(points) : null;
  75. }
  76. /// <summary>World space bounding box of this shape</summary>
  77. public Bounds GetBounds () {
  78. return GetBounds(convex ? _convexPoints : points, right, up, forward, origin, minimumHeight);
  79. }
  80. public static Bounds GetBounds (Vector3[] points, Matrix4x4 matrix, float minimumHeight) {
  81. var origin = matrix.MultiplyPoint3x4(Vector3.zero);
  82. var right = matrix.MultiplyPoint3x4(Vector3.right) - origin;
  83. var up = matrix.MultiplyPoint3x4(Vector3.up) - origin;
  84. var forward = matrix.MultiplyPoint3x4(Vector3.forward) - origin;
  85. return GetBounds(points, right, up, forward, origin, minimumHeight);
  86. }
  87. static Bounds GetBounds (Vector3[] points, Vector3 right, Vector3 up, Vector3 forward, Vector3 origin, float minimumHeight) {
  88. if (points == null || points.Length == 0) return new Bounds();
  89. float miny = points[0].y, maxy = points[0].y;
  90. for (int i = 0; i < points.Length; i++) {
  91. miny = Mathf.Min(miny, points[i].y);
  92. maxy = Mathf.Max(maxy, points[i].y);
  93. }
  94. var extraHeight = Mathf.Max(minimumHeight - (maxy - miny), 0) * 0.5f;
  95. miny -= extraHeight;
  96. maxy += extraHeight;
  97. Vector3 min = right * points[0].x + up * points[0].y + forward * points[0].z;
  98. Vector3 max = min;
  99. for (int i = 0; i < points.Length; i++) {
  100. var p = right * points[i].x + forward * points[i].z;
  101. var p1 = p + up * miny;
  102. var p2 = p + up * maxy;
  103. min = Vector3.Min(min, p1);
  104. min = Vector3.Min(min, p2);
  105. max = Vector3.Max(max, p1);
  106. max = Vector3.Max(max, p2);
  107. }
  108. return new Bounds((min+max)*0.5F + origin, max-min);
  109. }
  110. public bool Contains (GraphNode node) {
  111. return Contains((Vector3)node.position);
  112. }
  113. public bool Contains (Vector3 point) {
  114. // Transform to local space (shape in the XZ plane)
  115. point -= origin;
  116. var localSpacePoint = new Vector3(Vector3.Dot(point, right)/right.sqrMagnitude, 0, Vector3.Dot(point, forward)/forward.sqrMagnitude);
  117. if (convex) {
  118. if (_convexPoints == null) return false;
  119. for (int i = 0, j = _convexPoints.Length-1; i < _convexPoints.Length; j = i, i++) {
  120. if (VectorMath.RightOrColinearXZ(_convexPoints[i], _convexPoints[j], localSpacePoint)) return false;
  121. }
  122. return true;
  123. } else {
  124. return _points != null && Polygon.ContainsPointXZ(_points, localSpacePoint);
  125. }
  126. }
  127. }
  128. }