XZOrientedEllipse3D.cs 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235
  1. #if UNITY_EDITOR
  2. using UnityEngine;
  3. using System.Collections.Generic;
  4. namespace O3DWB
  5. {
  6. public class XZOrientedEllipse3D
  7. {
  8. #region Private Variables
  9. private float _radiusX = 1.0f;
  10. private float _radiusZ = 1.0f;
  11. private CoordinateSystem _coordinateSystem = new CoordinateSystem();
  12. #endregion
  13. #region Public Static Properties
  14. public static Vector3 ModelSpaceRightAxis { get { return Vector3.right; } }
  15. public static Vector3 ModelSpacePlaneNormal { get { return Vector3.up; } }
  16. public static Vector3 ModelSpaceLookAxis { get { return Vector3.forward; } }
  17. #endregion
  18. #region Public Properties
  19. public float ModelSpaceRadiusX { get { return _radiusX; } set { _radiusX = Mathf.Abs(value); } }
  20. public float ModelSpaceRadiusZ { get { return _radiusZ; } set { _radiusZ = Mathf.Abs(value); } }
  21. public Vector2 ModelSpaceRadii { get { return new Vector2(_radiusX, _radiusZ); } set { ModelSpaceRadiusX = value.x; ModelSpaceRadiusZ = value.y; } }
  22. public float ScaledRadiusX { get { return _radiusX * _coordinateSystem.TransformMatrix.XScale; } }
  23. public float ScaledRadiusZ { get { return _radiusZ * _coordinateSystem.TransformMatrix.ZScale; } }
  24. public Vector2 ScaledRadii { get { return new Vector2(_radiusX * _coordinateSystem.TransformMatrix.XScale, _radiusZ * _coordinateSystem.TransformMatrix.ZScale); } }
  25. public Vector3 Center
  26. {
  27. get { return _coordinateSystem.GetOriginPosition(); }
  28. set { _coordinateSystem.SetOriginPosition(value); }
  29. }
  30. public Plane Plane { get { return new Plane(_coordinateSystem.GetAxisVector(CoordinateSystemAxis.PositiveUp), Center); } }
  31. public Vector3 Normal { get { return Plane.normal; } }
  32. public TransformMatrix TransformMatrix { get { return _coordinateSystem.TransformMatrix; } }
  33. public Quaternion Rotation { get { return _coordinateSystem.GetRotation(); } set { _coordinateSystem.SetRotation(value); } }
  34. #endregion
  35. #region Constructors
  36. public XZOrientedEllipse3D()
  37. {
  38. }
  39. public XZOrientedEllipse3D(Vector3 center)
  40. {
  41. Center = center;
  42. }
  43. public XZOrientedEllipse3D(Vector3 center, float radius)
  44. {
  45. Center = center;
  46. ModelSpaceRadiusX = radius;
  47. ModelSpaceRadiusZ = radius;
  48. }
  49. public XZOrientedEllipse3D(Vector3 center, float radiusX, float radiusZ)
  50. {
  51. Center = center;
  52. ModelSpaceRadiusX = radiusX;
  53. ModelSpaceRadiusZ = radiusZ;
  54. }
  55. public XZOrientedEllipse3D(Vector3 center, float radiusX, float radiusZ, Quaternion rotation)
  56. {
  57. Center = center;
  58. ModelSpaceRadiusX = radiusX;
  59. ModelSpaceRadiusZ = radiusZ;
  60. Rotation = rotation;
  61. }
  62. public XZOrientedEllipse3D(XZOrientedEllipse3D source)
  63. {
  64. Center = source.Center;
  65. ModelSpaceRadiusX = source.ModelSpaceRadiusX;
  66. ModelSpaceRadiusZ = source.ModelSpaceRadiusZ;
  67. Rotation = source.Rotation;
  68. }
  69. #endregion
  70. #region Public Methods
  71. public Vector3 GetRandomPointInside()
  72. {
  73. float randomAngleInRadians = UnityEngine.Random.Range(0.0f, Mathf.PI * 2.0f);
  74. float randomRadiusX = UnityEngine.Random.Range(0.0f, ScaledRadiusX);
  75. float randomRadiusZ = UnityEngine.Random.Range(0.0f, ScaledRadiusZ);
  76. // Searching the net, it seems that using the square root produces a more random distribution :)
  77. return Center + GetLocalAxis(CoordinateSystemAxis.PositiveRight) * Mathf.Sqrt(randomRadiusX) * Mathf.Cos(randomAngleInRadians) +
  78. GetLocalAxis(CoordinateSystemAxis.PositiveLook) * Mathf.Sqrt(randomRadiusZ) * Mathf.Sin(randomAngleInRadians);
  79. }
  80. public void SetScale(float scale)
  81. {
  82. _coordinateSystem.SetScaleOnAllAxes(scale);
  83. }
  84. public bool OverlapsPolygon(Polygon3D polygon)
  85. {
  86. if (ContainsAnyPoint(polygon.PointsOnPolygonPlane)) return true;
  87. if (polygon.ContainsAnyPoint(GetExtentsPoints())) return true;
  88. if (IntersectsAnyRay(polygon.GetEdgeRays())) return true;
  89. return false;
  90. }
  91. public bool IntersectsAnyRay(List<Ray3D> rays)
  92. {
  93. foreach (Ray3D ray in rays)
  94. {
  95. if (IntersectsRay(ray)) return true;
  96. }
  97. return false;
  98. }
  99. public bool IntersectsRay(Ray3D ray, out float t)
  100. {
  101. Ray3D circleSpaceRay = TransformRayInEllipseCircleSpace(ray);
  102. XZOrientedCircle3D circle = TransformToCircleLocalSpace();
  103. return circle.IntersectsRay(circleSpaceRay, out t);
  104. }
  105. public bool IntersectsRay(Ray3D ray)
  106. {
  107. float t;
  108. return IntersectsRay(ray, out t);
  109. }
  110. public bool ContainsAnyPoint(List<Vector3> points)
  111. {
  112. XZOrientedCircle3D circle = TransformToCircleLocalSpace();
  113. foreach (Vector3 point in points)
  114. {
  115. if (circle.ContainsPoint(TransformPointInEllipseCircleLocalSpace(point))) return true;
  116. }
  117. return false;
  118. }
  119. public bool ContainsAllPoints(List<Vector3> points)
  120. {
  121. XZOrientedCircle3D circle = TransformToCircleLocalSpace();
  122. foreach (Vector3 point in points)
  123. {
  124. if (!circle.ContainsPoint(TransformPointInEllipseCircleLocalSpace(point))) return false;
  125. }
  126. return true;
  127. }
  128. public bool ContainsPoint(Vector3 point)
  129. {
  130. XZOrientedCircle3D circle = TransformToCircleLocalSpace();
  131. return circle.ContainsPoint(TransformPointInEllipseCircleLocalSpace(point));
  132. }
  133. public List<Vector3> GetExtentsPoints()
  134. {
  135. // First egenrate the points in model space in the following order: top, right, bottom, left.
  136. List<Vector3> points = new List<Vector3> { Vector3.forward * _radiusZ, Vector3.right * _radiusX, Vector3.forward * -_radiusZ, Vector3 .right * -_radiusX };
  137. // Transform the points and return them
  138. return Vector3Extensions.GetTransformedPoints(points, TransformMatrix.ToMatrix4x4x);
  139. }
  140. public void SetNormal(Vector3 normal)
  141. {
  142. if (normal.magnitude == 0.0f) return;
  143. normal.Normalize();
  144. Vector3 currentNormal = Plane.normal;
  145. bool pointsInSameDirection;
  146. if (normal.IsAlignedWith(currentNormal, out pointsInSameDirection)) Rotate(GetLocalAxis(CoordinateSystemAxis.PositiveRight), 180.0f);
  147. else
  148. {
  149. Vector3 rotationAxis = Vector3.Cross(currentNormal, normal);
  150. Rotate(rotationAxis, currentNormal.AngleWith(normal));
  151. }
  152. }
  153. public void Rotate(Vector3 rotationAxis, float angleInDegrees)
  154. {
  155. rotationAxis.Normalize();
  156. Quaternion rotationQuaternion = Quaternion.AngleAxis(angleInDegrees, rotationAxis);
  157. Rotation = rotationQuaternion * Rotation;
  158. }
  159. public Vector3 GetLocalAxis(CoordinateSystemAxis axis)
  160. {
  161. return _coordinateSystem.GetAxisVector(axis);
  162. }
  163. #endregion
  164. #region Private Methods
  165. private XZOrientedCircle3D TransformToCircleLocalSpace()
  166. {
  167. var circle = new XZOrientedCircle3D();
  168. circle.Rotation = Quaternion.identity;
  169. circle.SetScale(1.0f);
  170. circle.ModelSpaceRadius = 1.0f;
  171. circle.Center = Vector3.zero;
  172. return circle;
  173. }
  174. private Vector3 TransformPointInEllipseCircleLocalSpace(Vector3 vector)
  175. {
  176. TransformMatrix transformMatrix = TransformMatrix;
  177. vector = transformMatrix.MultiplyPointInverse(vector);
  178. vector.x /= _radiusX;
  179. vector.z /= _radiusZ;
  180. return vector;
  181. }
  182. private Vector3 TransformVectorInEllipseCircleLocalSpace(Vector3 vector)
  183. {
  184. TransformMatrix transformMatrix = TransformMatrix;
  185. vector = transformMatrix.MultiplyVectorInverse(vector);
  186. vector.x /= _radiusX;
  187. vector.z /= _radiusZ;
  188. return vector;
  189. }
  190. private Ray3D TransformRayInEllipseCircleSpace(Ray3D ray)
  191. {
  192. return new Ray3D(TransformPointInEllipseCircleLocalSpace(ray.Origin), TransformVectorInEllipseCircleLocalSpace(ray.Direction));
  193. }
  194. #endregion
  195. }
  196. }
  197. #endif