ZeroVR/ZeroPacientVR/Assets/Octave3D World Builder/Scripts/Math/XZOrientedEllipse3D.cs

235 lines
8.6 KiB
C#

#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