XZOrientedCircle3D.cs 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. #if UNITY_EDITOR
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. namespace O3DWB
  5. {
  6. public class XZOrientedCircle3D
  7. {
  8. #region Private Variables
  9. private float _radius = 1.0f;
  10. private CoordinateSystem _coordinateSystem = new CoordinateSystem();
  11. #endregion
  12. #region Public Static Properties
  13. public static Vector3 ModelSpaceRightAxis { get { return Vector3.right; } }
  14. public static Vector3 ModelSpacePlaneNormal { get { return Vector3.up; } }
  15. public static Vector3 ModelSpaceLookAxis { get { return Vector3.forward; } }
  16. #endregion
  17. #region Public Properties
  18. public float ModelSpaceRadius { get { return _radius; } set { _radius = Mathf.Abs(value); } }
  19. public float ScaledRadius { get { return _radius * _coordinateSystem.TransformMatrix.XScale; } }
  20. public Vector3 Center
  21. {
  22. get { return _coordinateSystem.GetOriginPosition(); }
  23. set { _coordinateSystem.SetOriginPosition(value); }
  24. }
  25. public Plane Plane { get { return new Plane(_coordinateSystem.GetAxisVector(CoordinateSystemAxis.PositiveUp), Center); } }
  26. public Vector3 Normal { get { return Plane.normal; } }
  27. public TransformMatrix TransformMatrix { get { return _coordinateSystem.TransformMatrix; } }
  28. public Quaternion Rotation { get { return _coordinateSystem.GetRotation(); } set { _coordinateSystem.SetRotation(value); } }
  29. #endregion
  30. #region Constructors
  31. public XZOrientedCircle3D()
  32. {
  33. }
  34. public XZOrientedCircle3D(Vector3 center)
  35. {
  36. Center = center;
  37. }
  38. public XZOrientedCircle3D(Vector3 center, float radius)
  39. {
  40. Center = center;
  41. ModelSpaceRadius = radius;
  42. }
  43. public XZOrientedCircle3D(Vector3 center, float radius, Quaternion rotation)
  44. {
  45. Center = center;
  46. ModelSpaceRadius = radius;
  47. Rotation = rotation;
  48. }
  49. public XZOrientedCircle3D(XZOrientedCircle3D source)
  50. {
  51. Center = source.Center;
  52. ModelSpaceRadius = source.ModelSpaceRadius;
  53. Rotation = source.Rotation;
  54. }
  55. #endregion
  56. #region Public Methods
  57. public void SetScale(float scale)
  58. {
  59. _coordinateSystem.SetScaleOnAllAxes(scale);
  60. }
  61. public bool ContainsAnyPoint(List<Vector3> points)
  62. {
  63. foreach (Vector2 point in points)
  64. {
  65. if (ContainsPoint(point)) return true;
  66. }
  67. return false;
  68. }
  69. public bool ContainsPoint(Vector3 point)
  70. {
  71. if (!Plane.IsPointOnPlane(point)) return false;
  72. return (point - Center).magnitude <= _radius;
  73. }
  74. public List<Vector3> GetExtentsPoints()
  75. {
  76. Vector3 center = Center;
  77. Vector3 localRight = GetLocalAxis(CoordinateSystemAxis.PositiveRight);
  78. Vector3 localLook = GetLocalAxis(CoordinateSystemAxis.PositiveLook);
  79. float scaledRadius = ScaledRadius;
  80. // Return the extent points in the following format: top, right, bottom, left.
  81. return new List<Vector3>
  82. {
  83. center + localLook * scaledRadius,
  84. center + localRight * scaledRadius,
  85. center - localLook * scaledRadius,
  86. center - localRight * scaledRadius,
  87. };
  88. }
  89. public bool IntersectsRay(Ray3D ray, out float t)
  90. {
  91. Plane circlePlane = Plane;
  92. Vector3 circleCenter = Center;
  93. float scaledRadius = ScaledRadius;
  94. // Note: 'IntersectsPlane' not enough. Also check for containment????
  95. if (ray.IntersectsPlane(circlePlane, out t)) return true;
  96. else
  97. if (ray.Direction.IsPerpendicularTo(circlePlane.normal))
  98. {
  99. // Project the circle center onto the ray direction segment. If the distance between the circle center
  100. // and the projected center is <= the circle's radius, the ray might intersect the circle. Otherwise,
  101. // the ray can not possibly intersect the circle.
  102. Segment3D segment = new Segment3D(ray);
  103. Vector3 centerProjectedOnRayDir = circleCenter.CalculateProjectionPointOnSegment(segment.StartPoint, segment.EndPoint);
  104. Vector3 fromCenterToProjectedCenter = centerProjectedOnRayDir - circleCenter;
  105. float triAdjSideLength1 = fromCenterToProjectedCenter.magnitude;
  106. if (triAdjSideLength1 > scaledRadius) return false;
  107. // At this point it is possible that the ray might intersect the circle. Calcluate how much
  108. // we have to move from the center projection to a point on the circle along the reverse of
  109. // the ray direction vector. We will store this amount in 'triAdjSideLength2'.
  110. float triAdjSideLength2 = Mathf.Sqrt(scaledRadius * scaledRadius - triAdjSideLength1 * triAdjSideLength1);
  111. // Now check if moving from the projected center along the reverse ray direction by an amount equal to
  112. // 'triAdjSideLength2', we end up on a point which resides on the ray direction segment.
  113. Vector3 normalizedRayDirection = ray.Direction;
  114. normalizedRayDirection.Normalize();
  115. Vector3 targetPoint = centerProjectedOnRayDir - triAdjSideLength2 * normalizedRayDirection;
  116. if (targetPoint.IsOnSegment(segment.StartPoint, segment.EndPoint))
  117. {
  118. // The point sits on the segment, which means that the ray intersects the circle.
  119. // Now we need to calculate the intersection offset.
  120. t = (targetPoint - ray.Origin).magnitude / ray.Direction.magnitude;
  121. return true;
  122. }
  123. }
  124. return false;
  125. }
  126. public bool IntersectsAnyRay(List<Ray3D> rays)
  127. {
  128. foreach (Ray3D ray in rays)
  129. {
  130. if (IntersectsRay(ray)) return true;
  131. }
  132. return false;
  133. }
  134. public bool IntersectsRay(Ray3D ray)
  135. {
  136. float t;
  137. return IntersectsRay(ray, out t);
  138. }
  139. public void SetNormal(Vector3 normal)
  140. {
  141. normal.Normalize();
  142. Vector3 currentNormal = Plane.normal;
  143. bool pointsInSameDirection;
  144. if (normal.IsAlignedWith(currentNormal, out pointsInSameDirection)) Rotate(GetLocalAxis(CoordinateSystemAxis.PositiveRight), 180.0f);
  145. else
  146. {
  147. Vector3 rotationAxis = Vector3.Cross(currentNormal, normal);
  148. Rotate(rotationAxis, currentNormal.AngleWith(normal));
  149. }
  150. }
  151. public void Rotate(Vector3 rotationAxis, float angleInDegrees)
  152. {
  153. rotationAxis.Normalize();
  154. Quaternion rotationQuaternion = Quaternion.AngleAxis(angleInDegrees, rotationAxis);
  155. Rotation = rotationQuaternion * Rotation;
  156. }
  157. public Vector3 GetLocalAxis(CoordinateSystemAxis axis)
  158. {
  159. return _coordinateSystem.GetAxisVector(axis);
  160. }
  161. #endregion
  162. }
  163. }
  164. #endif