123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235 |
- #if UNITY_EDITOR
- using UnityEngine;
- using System.Collections.Generic;
- namespace O3DWB
- {
- public class XZOrientedEllipse3D
- {
- #region Private Variables
- private float _radiusX = 1.0f;
- private float _radiusZ = 1.0f;
- private CoordinateSystem _coordinateSystem = new CoordinateSystem();
- #endregion
- #region Public Static Properties
- public static Vector3 ModelSpaceRightAxis { get { return Vector3.right; } }
- public static Vector3 ModelSpacePlaneNormal { get { return Vector3.up; } }
- public static Vector3 ModelSpaceLookAxis { get { return Vector3.forward; } }
- #endregion
- #region Public Properties
- public float ModelSpaceRadiusX { get { return _radiusX; } set { _radiusX = Mathf.Abs(value); } }
- public float ModelSpaceRadiusZ { get { return _radiusZ; } set { _radiusZ = Mathf.Abs(value); } }
- public Vector2 ModelSpaceRadii { get { return new Vector2(_radiusX, _radiusZ); } set { ModelSpaceRadiusX = value.x; ModelSpaceRadiusZ = value.y; } }
- public float ScaledRadiusX { get { return _radiusX * _coordinateSystem.TransformMatrix.XScale; } }
- public float ScaledRadiusZ { get { return _radiusZ * _coordinateSystem.TransformMatrix.ZScale; } }
- public Vector2 ScaledRadii { get { return new Vector2(_radiusX * _coordinateSystem.TransformMatrix.XScale, _radiusZ * _coordinateSystem.TransformMatrix.ZScale); } }
- public Vector3 Center
- {
- get { return _coordinateSystem.GetOriginPosition(); }
- set { _coordinateSystem.SetOriginPosition(value); }
- }
- public Plane Plane { get { return new Plane(_coordinateSystem.GetAxisVector(CoordinateSystemAxis.PositiveUp), Center); } }
- public Vector3 Normal { get { return Plane.normal; } }
- public TransformMatrix TransformMatrix { get { return _coordinateSystem.TransformMatrix; } }
- public Quaternion Rotation { get { return _coordinateSystem.GetRotation(); } set { _coordinateSystem.SetRotation(value); } }
- #endregion
- #region Constructors
- public XZOrientedEllipse3D()
- {
- }
- public XZOrientedEllipse3D(Vector3 center)
- {
- Center = center;
- }
- public XZOrientedEllipse3D(Vector3 center, float radius)
- {
- Center = center;
- ModelSpaceRadiusX = radius;
- ModelSpaceRadiusZ = radius;
- }
- public XZOrientedEllipse3D(Vector3 center, float radiusX, float radiusZ)
- {
- Center = center;
- ModelSpaceRadiusX = radiusX;
- ModelSpaceRadiusZ = radiusZ;
- }
- public XZOrientedEllipse3D(Vector3 center, float radiusX, float radiusZ, Quaternion rotation)
- {
- Center = center;
- ModelSpaceRadiusX = radiusX;
- ModelSpaceRadiusZ = radiusZ;
- Rotation = rotation;
- }
- public XZOrientedEllipse3D(XZOrientedEllipse3D source)
- {
- Center = source.Center;
- ModelSpaceRadiusX = source.ModelSpaceRadiusX;
- ModelSpaceRadiusZ = source.ModelSpaceRadiusZ;
- Rotation = source.Rotation;
- }
- #endregion
- #region Public Methods
- public Vector3 GetRandomPointInside()
- {
- float randomAngleInRadians = UnityEngine.Random.Range(0.0f, Mathf.PI * 2.0f);
- float randomRadiusX = UnityEngine.Random.Range(0.0f, ScaledRadiusX);
- float randomRadiusZ = UnityEngine.Random.Range(0.0f, ScaledRadiusZ);
- // Searching the net, it seems that using the square root produces a more random distribution :)
- return Center + GetLocalAxis(CoordinateSystemAxis.PositiveRight) * Mathf.Sqrt(randomRadiusX) * Mathf.Cos(randomAngleInRadians) +
- GetLocalAxis(CoordinateSystemAxis.PositiveLook) * Mathf.Sqrt(randomRadiusZ) * Mathf.Sin(randomAngleInRadians);
- }
- public void SetScale(float scale)
- {
- _coordinateSystem.SetScaleOnAllAxes(scale);
- }
- public bool OverlapsPolygon(Polygon3D polygon)
- {
- if (ContainsAnyPoint(polygon.PointsOnPolygonPlane)) return true;
- if (polygon.ContainsAnyPoint(GetExtentsPoints())) return true;
- if (IntersectsAnyRay(polygon.GetEdgeRays())) return true;
- return false;
- }
- public bool IntersectsAnyRay(List<Ray3D> rays)
- {
- foreach (Ray3D ray in rays)
- {
- if (IntersectsRay(ray)) return true;
- }
- return false;
- }
- public bool IntersectsRay(Ray3D ray, out float t)
- {
- Ray3D circleSpaceRay = TransformRayInEllipseCircleSpace(ray);
- XZOrientedCircle3D circle = TransformToCircleLocalSpace();
-
- return circle.IntersectsRay(circleSpaceRay, out t);
- }
- public bool IntersectsRay(Ray3D ray)
- {
- float t;
- return IntersectsRay(ray, out t);
- }
- public bool ContainsAnyPoint(List<Vector3> points)
- {
- XZOrientedCircle3D circle = TransformToCircleLocalSpace();
- foreach (Vector3 point in points)
- {
- if (circle.ContainsPoint(TransformPointInEllipseCircleLocalSpace(point))) return true;
- }
- return false;
- }
- public bool ContainsAllPoints(List<Vector3> points)
- {
- XZOrientedCircle3D circle = TransformToCircleLocalSpace();
- foreach (Vector3 point in points)
- {
- if (!circle.ContainsPoint(TransformPointInEllipseCircleLocalSpace(point))) return false;
- }
- return true;
- }
- public bool ContainsPoint(Vector3 point)
- {
- XZOrientedCircle3D circle = TransformToCircleLocalSpace();
- return circle.ContainsPoint(TransformPointInEllipseCircleLocalSpace(point));
- }
- public List<Vector3> GetExtentsPoints()
- {
- // First egenrate the points in model space in the following order: top, right, bottom, left.
- List<Vector3> points = new List<Vector3> { Vector3.forward * _radiusZ, Vector3.right * _radiusX, Vector3.forward * -_radiusZ, Vector3 .right * -_radiusX };
- // Transform the points and return them
- return Vector3Extensions.GetTransformedPoints(points, TransformMatrix.ToMatrix4x4x);
- }
- public void SetNormal(Vector3 normal)
- {
- if (normal.magnitude == 0.0f) return;
- normal.Normalize();
- Vector3 currentNormal = Plane.normal;
- bool pointsInSameDirection;
- if (normal.IsAlignedWith(currentNormal, out pointsInSameDirection)) Rotate(GetLocalAxis(CoordinateSystemAxis.PositiveRight), 180.0f);
- else
- {
- Vector3 rotationAxis = Vector3.Cross(currentNormal, normal);
- Rotate(rotationAxis, currentNormal.AngleWith(normal));
- }
- }
- public void Rotate(Vector3 rotationAxis, float angleInDegrees)
- {
- rotationAxis.Normalize();
- Quaternion rotationQuaternion = Quaternion.AngleAxis(angleInDegrees, rotationAxis);
- Rotation = rotationQuaternion * Rotation;
- }
- public Vector3 GetLocalAxis(CoordinateSystemAxis axis)
- {
- return _coordinateSystem.GetAxisVector(axis);
- }
- #endregion
- #region Private Methods
- private XZOrientedCircle3D TransformToCircleLocalSpace()
- {
- var circle = new XZOrientedCircle3D();
- circle.Rotation = Quaternion.identity;
- circle.SetScale(1.0f);
- circle.ModelSpaceRadius = 1.0f;
- circle.Center = Vector3.zero;
- return circle;
- }
- private Vector3 TransformPointInEllipseCircleLocalSpace(Vector3 vector)
- {
- TransformMatrix transformMatrix = TransformMatrix;
- vector = transformMatrix.MultiplyPointInverse(vector);
- vector.x /= _radiusX;
- vector.z /= _radiusZ;
- return vector;
- }
- private Vector3 TransformVectorInEllipseCircleLocalSpace(Vector3 vector)
- {
- TransformMatrix transformMatrix = TransformMatrix;
- vector = transformMatrix.MultiplyVectorInverse(vector);
- vector.x /= _radiusX;
- vector.z /= _radiusZ;
- return vector;
- }
- private Ray3D TransformRayInEllipseCircleSpace(Ray3D ray)
- {
- return new Ray3D(TransformPointInEllipseCircleLocalSpace(ray.Origin), TransformVectorInEllipseCircleLocalSpace(ray.Direction));
- }
- #endregion
- }
- }
- #endif
|