BITFALL/Assets/GSpawn - Level Designer/Scripts/Math/AABB.cs

284 lines
9.3 KiB
C#

#if UNITY_EDITOR
using UnityEngine;
using System.Collections.Generic;
namespace GSpawn
{
public struct AABB
{
private Vector3 _center;
private Vector3 _size;
private bool _isValid;
public Vector3 center { get { return _center; } set { _center = value; } }
public Vector3 size { get { return _size; } set { _size = value.abs(); } }
public Vector3 extents { get { return new Vector3(_size.x * 0.5f, _size.y * 0.5f, _size.z * 0.5f); } }
public Vector3 min
{
get { return new Vector3(_center.x - _size.x * 0.5f, _center.y - _size.y * 0.5f, _center.z - _size.z * 0.5f); }
set { refreshCenterAndSize(Vector3.Min(value, max), max); }
}
public Vector3 max
{
get { return new Vector3(_center.x + _size.x * 0.5f, _center.y + _size.y * 0.5f, _center.z + _size.z * 0.5f); }
set { refreshCenterAndSize(min, Vector3.Max(value, min)); }
}
public float volume { get { return _size.x * _size.y * _size.z; } }
public bool isValid { get { return _isValid; } }
public static AABB getInvalid()
{
return new AABB();
}
public AABB(Vector3 center, Vector3 size)
{
_center = center;
_size = size;
_isValid = true;
}
public AABB(Bounds bounds)
{
_center = bounds.center;
_size = bounds.size;
_isValid = true;
}
public AABB(IEnumerable<Vector3> points)
{
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
foreach (Vector3 pt in points)
{
min = Vector3.Min(pt, min);
max = Vector3.Max(pt, max);
}
_center = (min + max) * 0.5f;
_size = max - min;
_isValid = true;
}
public AABB(IEnumerable<Vector2> points)
{
Vector2 min = new Vector2(float.MaxValue, float.MaxValue);
Vector2 max = new Vector2(float.MinValue, float.MinValue);
foreach (Vector2 pt in points)
{
min = Vector2.Min(pt, min);
max = Vector2.Max(pt, max);
}
_center = (min + max) * 0.5f;
_size = max - min;
_isValid = true;
}
public AABB(OBB obb)
{
_center = Vector3.zero;
_size = Vector3.one;
_isValid = true;
transform(obb.transformMatrix);
}
public static AABB createFromMinMax(Vector3 min, Vector3 max)
{
return new AABB()
{
_center = (min + max) * 0.5f,
_size = (max - min),
_isValid = true
};
}
public OBB toOBB()
{
return new OBB(_center, _size, Quaternion.identity);
}
public Bounds toBounds()
{
return new Bounds(center, size);
}
public bool intersects(AABB aabb)
{
Vector3 min0 = min;
Vector3 max0 = max;
Vector3 min1 = aabb.min;
Vector3 max1 = aabb.max;
return (min0.x <= max1.x) && (min0.y <= max1.y) && (min0.z <= max1.z)
&& (max0.x >= min1.x) && (max0.y >= min1.y) && (max0.z >= min1.z);
}
public void enclosePoint(Vector3 point)
{
Vector3 thisMin = min;
Vector3 thisMax = max;
if (point.x < thisMin.x) thisMin.x = point.x;
if (point.x > thisMax.x) thisMax.x = point.x;
if (point.y < thisMin.y) thisMin.y = point.y;
if (point.y > thisMax.y) thisMax.y = point.y;
if (point.z < thisMin.z) thisMin.z = point.z;
if (point.z > thisMax.z) thisMax.z = point.z;
refreshCenterAndSize(thisMin, thisMax);
}
public void enclosePoints(IEnumerable<Vector3> points)
{
foreach (var pt in points)
enclosePoint(pt);
}
public void encloseAABB(AABB aabb)
{
Vector3 thisMin = min;
Vector3 thisMax = max;
Vector3 otherMin = aabb.min;
Vector3 otherMax = aabb.max;
if (otherMin.x < thisMin.x) thisMin.x = otherMin.x;
if (otherMin.y < thisMin.y) thisMin.y = otherMin.y;
if (otherMin.z < thisMin.z) thisMin.z = otherMin.z;
if (otherMax.x > thisMax.x) thisMax.x = otherMax.x;
if (otherMax.y > thisMax.y) thisMax.y = otherMax.y;
if (otherMax.z > thisMax.z) thisMax.z = otherMax.z;
refreshCenterAndSize(thisMin, thisMax);
}
public Sphere getEnclosingSphere()
{
return new Sphere(_center, extents.magnitude);
}
public void inflate(float amount)
{
size += Vector3Ex.create(amount);
}
public void inflate(Vector3 amount)
{
size += amount;
}
public void transform(Matrix4x4 transformMatrix)
{
Box3D.transform(_center, _size, transformMatrix, out _center, out _size);
}
public void calcCenterAndCorners(List<Vector3> centerAndCorners)
{
calcCorners(centerAndCorners);
centerAndCorners.Add(center);
}
public void calcCorners(List<Vector3> cornerPoints)
{
Box3D.calcCorners(_center, _size, Quaternion.identity, cornerPoints, false);
}
public AABB calcInwardFaceExtrusion(Box3DFace face, float extrudeAmount)
{
Box3DFaceDesc faceDesc = Box3D.getFaceDesc(_center, _size, Quaternion.identity, face);
Vector3 size = _size;
if (face == Box3DFace.Left || face == Box3DFace.Right) size.x = extrudeAmount;
else if (face == Box3DFace.Bottom || face == Box3DFace.Top) size.y = extrudeAmount;
else size.z = extrudeAmount;
return new AABB(faceDesc.center - faceDesc.plane.normal * extrudeAmount * 0.5f, size);
}
public bool containsPoint(Vector3 pt)
{
Vector3 boxMin = min;
Vector3 boxMax = max;
return pt.x >= boxMin.x && pt.x <= boxMax.x &&
pt.y >= boxMin.y && pt.y <= boxMax.y &&
pt.z >= boxMin.z && pt.z <= boxMax.z;
}
public bool containsAnyPoint(Vector3 p0, Vector3 p1, Vector3 p2)
{
Vector3 boxMin = min;
Vector3 boxMax = max;
return (p0.x >= boxMin.x && p0.x <= boxMax.x &&
p0.y >= boxMin.y && p0.y <= boxMax.y &&
p0.z >= boxMin.z && p0.z <= boxMax.z) ||
(p1.x >= boxMin.x && p1.x <= boxMax.x &&
p1.y >= boxMin.y && p1.y <= boxMax.y &&
p1.z >= boxMin.z && p1.z <= boxMax.z) ||
(p2.x >= boxMin.x && p2.x <= boxMax.x &&
p2.y >= boxMin.y && p2.y <= boxMax.y &&
p2.z >= boxMin.z && p2.z <= boxMax.z);
}
public bool containsPoints(IEnumerable<Vector3> points)
{
foreach (var pt in points)
if (!containsPoint(pt)) return false;
return true;
}
public Vector3 calcClosestPoint(Vector3 point)
{
Vector3 fromCenterToPt = point - _center;
Vector3 extents = _size * 0.5f;
Vector3 closestPt = _center;
float projection = Vector3.Dot(Vector3.right, fromCenterToPt);
if (projection > extents[0]) projection = extents[0];
else if (projection < -extents[0]) projection = -extents[0];
closestPt += Vector3.right * projection;
projection = Vector3.Dot(Vector3.up, fromCenterToPt);
if (projection > extents[1]) projection = extents[1];
else if (projection < -extents[1]) projection = -extents[1];
closestPt += Vector3.up * projection;
projection = Vector3.Dot(Vector3.forward, fromCenterToPt);
if (projection > extents[2]) projection = extents[2];
else if (projection < -extents[2]) projection = -extents[2];
closestPt += Vector3.forward * projection;
return closestPt;
}
public bool raycast(Ray ray, out float t)
{
t = 0.0f;
Bounds bounds = new Bounds(_center, _size);
return bounds.IntersectRay(ray, out t);
}
public bool raycast(Ray ray)
{
float t;
return raycast(ray, out t);
}
private void refreshCenterAndSize(Vector3 newMin, Vector3 newMax)
{
_center.x = (newMin.x + newMax.x) * 0.5f;
_center.y = (newMin.y + newMax.y) * 0.5f;
_center.z = (newMin.z + newMax.z) * 0.5f;
_size.x = newMax.x - newMin.x;
_size.y = newMax.y - newMin.y;
_size.z = newMax.z - newMin.z;
}
}
}
#endif