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

133 lines
3.9 KiB
C#

#if UNITY_EDITOR
using UnityEngine;
using System.Collections.Generic;
namespace O3DWB
{
public struct Sphere
{
#region Private Variables
private float _radius;
private Vector3 _center;
#endregion
#region Constructors
public Sphere(Vector3 center)
{
_radius = 1.0f;
_center = center;
}
public Sphere(float radius)
{
_radius = radius;
_center = Vector3.zero;
}
public Sphere(Vector3 center, float radius)
{
_radius = radius;
_center = center;
}
public Sphere(Sphere source)
{
_radius = source._radius;
_center = source._center;
}
#endregion
#region Public Properties
public float Radius { get { return _radius; } set { _radius = value; } }
public Vector3 Center { get { return _center; } set { _center = value; } }
#endregion
#region Public Methods
public bool Raycast(Ray ray)
{
float t;
return Raycast(ray, out t);
}
public bool Raycast(Ray ray, out float t)
{
t = 0.0f;
// Calculate the coefficients of the quadratic equation
Vector3 sphereCenterToRayOrigin = ray.origin - _center;
float a = Vector3.SqrMagnitude(ray.direction);
float b = 2.0f * Vector3.Dot(ray.direction, sphereCenterToRayOrigin);
float c = Vector3.SqrMagnitude(sphereCenterToRayOrigin) - _radius * _radius;
// If we have a solution to the equation, the ray most likely intersects the sphere.
float t1, t2;
if (Equation.SolveQuadratic(a, b, c, out t1, out t2))
{
// Make sure the ray doesn't intersect the sphere only from behind
if (t1 < 0.0f && t2 < 0.0f) return false;
// Make sure we are using the smallest positive t value
if (t1 < 0.0f)
{
float temp = t1;
t1 = t2;
t2 = temp;
}
t = t1;
return true;
}
// If we reach this point it means the ray does not intersect the sphere in any way
return false;
}
public float GetDistanceBetweenCenters(Sphere sphere)
{
return (_center - sphere.Center).magnitude;
}
public float GetDistanceBetweenCentersSq(Sphere sphere)
{
return (Center - sphere.Center).sqrMagnitude;
}
public bool FullyOverlaps(Sphere sphere)
{
return GetDistanceBetweenCenters(sphere) + sphere.Radius <= _radius;
}
public bool OverlapsFullyOrPartially(Sphere sphere)
{
float distanceBetweenCenters = GetDistanceBetweenCenters(sphere);
// Fully?
if (distanceBetweenCenters + sphere.Radius <= _radius) return true;
// Partially?
return distanceBetweenCenters - sphere.Radius <= _radius;
}
public bool OverlapsFullyOrPartially(OrientedBox orientedBox)
{
Vector3 closestPointToSphereCenter = orientedBox.GetClosestPointToPoint(_center);
return (closestPointToSphereCenter - _center).sqrMagnitude <= _radius * _radius;
}
public Sphere Encapsulate(Sphere sphere)
{
float distanceBetweenCenters = GetDistanceBetweenCenters(sphere);
float newDiameter = distanceBetweenCenters + _radius + sphere.Radius;
float newRadius = newDiameter * 0.5f;
Vector3 fromThisToOther = sphere.Center - Center;
fromThisToOther.Normalize();
Vector3 newCenter = Center - fromThisToOther * _radius + fromThisToOther * newRadius;
return new Sphere(newCenter, newRadius);
}
#endregion
}
}
#endif