Code/General/BBox2.cs
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace ExtendedBox.General;
public struct BBox2 : IEquatable<BBox2>
{
[JsonInclude]
public Vector2 Mins;
[JsonInclude]
public Vector2 Maxs;
[JsonIgnore]
public IEnumerable<Vector2> Corners
{
get
{
yield return new(Mins.x, Mins.y);
yield return new(Maxs.x, Mins.y);
yield return new(Maxs.x, Maxs.y);
yield return new(Mins.x, Maxs.y);
}
}
[JsonIgnore]
public readonly Vector2 Center => Mins + Size * 0.5f;
[JsonIgnore]
public readonly Vector2 Size => Maxs - Mins;
[JsonIgnore]
public readonly Vector2 Extents => Size * 0.5f;
[JsonIgnore]
public readonly Vector2 RandomPointInside => Random.Shared.VectorInSquare(in this);
[JsonIgnore]
public readonly float Volume
{
get
{
Vector2 vector = Size.Abs();
return vector.x * vector.y;
}
}
#region constructors
public BBox2(Vector2 mins, Vector2 maxs)
{
Mins = Vector2.Min(mins, maxs);
Maxs = Vector2.Max(mins, maxs);
}
public static BBox2 FromRadius(float height, Vector2 radius)
{
var mins = new Vector2(-radius.x, -radius.y);
var maxs = new Vector2(radius.x, radius.y);
return new(mins, maxs);
}
public static BBox2 FromPositionAndSize(in Vector2 center, Vector2 size = default)
{
BBox2 result = default;
result.Mins = center - size * 0.5f;
result.Maxs = center + size * 0.5f;
return result;
}
public static BBox2 FromBoxes(IEnumerable<BBox2> boxes)
{
using IEnumerator<BBox2> enumerator = boxes.GetEnumerator();
if(!enumerator.MoveNext())
{
return default;
}
BBox2 result = enumerator.Current;
while(enumerator.MoveNext())
{
BBox2 point = enumerator.Current;
result = result.AddBBox(in point);
}
return result;
}
public static BBox2 FromPoints(IEnumerable<Vector2> points, Vector2 size = default)
{
using IEnumerator<Vector2> enumerator = points.GetEnumerator();
if(!enumerator.MoveNext())
{
return default;
}
Vector2 center = enumerator.Current;
BBox2 result = FromPositionAndSize(in center, size);
while(enumerator.MoveNext())
{
center = enumerator.Current;
BBox2 point = FromPositionAndSize(in center, size);
result = result.AddBBox(in point);
}
return result;
}
#endregion
#region convertation methods
public readonly BBox2 Translate(in Vector2 point)
{
BBox2 result = this;
result.Mins += point;
result.Maxs += point;
return result;
}
public readonly BBox2 Rotate(in float rotation) // TODO: optimize
{
BBox bbox = new(new Vector3(Mins.x, Mins.y, 0), new Vector3(Maxs.x, Maxs.y, 0));
bbox = bbox.Rotate(Rotation.FromYaw(rotation));
return new(new Vector2(bbox.Mins.x, bbox.Mins.y), new Vector2(bbox.Maxs.x, bbox.Maxs.y));
}
public readonly BBox2 Transform(Vector2 position, float rotation, Vector2 scale)
{
return Scale(in scale).Rotate(in rotation).Translate(in position);
}
public readonly BBox2 Scale(in Vector2 scale)
{
var mins = -scale * Extents + Center;
var maxs = scale * Extents + Center;
return new(mins, maxs);
}
public readonly bool Contains(in BBox2 b, bool includeMaxs = false)
{
if(includeMaxs)
{
return b.Mins.x >= Mins.x && b.Maxs.x <= Maxs.x &&
b.Mins.y >= Mins.y && b.Maxs.y <= Maxs.y;
}
return b.Mins.x >= Mins.x && b.Maxs.x < Maxs.x &&
b.Mins.y >= Mins.y && b.Maxs.y < Maxs.y;
}
public readonly bool Contains(in Vector2 b, bool includeMaxs = false)
{
if(includeMaxs)
{
return b.x >= Mins.x && b.x <= Maxs.x &&
b.y >= Mins.y && b.y <= Maxs.y;
}
return b.x >= Mins.x && b.x < Maxs.x &&
b.y >= Mins.y && b.y < Maxs.y;
}
public readonly bool Overlaps(in BBox2 b)
{
return Mins.x < b.Maxs.x && b.Mins.x < Maxs.x &&
Mins.y < b.Maxs.y && b.Mins.y < Maxs.y;
}
public readonly BBox2 GetIntersection(BBox2 other)
{
if(!Overlaps(other))
return new(Vector2Int.Zero, Vector2Int.Zero);
return new(Mins.ComponentMax(other.Mins), Maxs.ComponentMin(other.Maxs));
}
public readonly BBox2 AddPoint(in Vector2 point)
{
BBox2 result = this;
result.Mins = Vector2.Min(Mins, point);
result.Maxs = Vector2.Max(Maxs, point);
return result;
}
public readonly BBox2 AddBBox(in BBox2 bbox)
{
BBox2 result = this;
result.Mins = Vector2.Min(Mins, bbox.Mins);
result.Maxs = Vector2.Max(Maxs, bbox.Maxs);
return result;
}
public readonly BBox2 Grow(in Vector2 skin)
{
BBox2 result = this;
result.Mins -= skin;
result.Maxs += skin;
return result;
}
public readonly Vector2 ClosestPoint(in Vector2 point)
{
return point.Clamp(Mins, Maxs);
}
#endregion
#region operators
public static BBox2 operator *(BBox2 c1, Vector2 c2)
{
c1.Mins *= c2;
c1.Maxs *= c2;
return c1;
}
public static BBox2 operator +(BBox2 c1, Vector2 c2)
{
c1.Mins += c2;
c1.Maxs += c2;
return c1;
}
public static bool operator ==(BBox2 left, BBox2 right)
{
return left.Equals(right);
}
public static bool operator !=(BBox2 left, BBox2 right)
{
return !(left == right);
}
#endregion
public override readonly string ToString()
{
return $"mins {Mins}, maxs {Maxs}";
}
public readonly BBox2 Snap(float distance)
{
return new BBox2(Mins.SnapToGrid(distance), Maxs.SnapToGrid(distance));
}
public override readonly bool Equals(object? obj)
{
if(obj is BBox2 o)
return Equals(o);
return false;
}
public readonly bool Equals(BBox2 o)
{
return Mins == o.Mins && Maxs == o.Maxs;
}
public override readonly int GetHashCode()
{
return HashCode.Combine(Mins, Maxs);
}
}