General/BBox2Int.cs
using System;
using System.Collections.Generic;
using System.Text.Json.Serialization;
namespace ExtendedBox.General;
public struct BBox2Int : IEquatable<BBox2Int>
{
[JsonInclude]
public Vector2Int Mins;
[JsonInclude]
public Vector2Int Maxs;
[JsonIgnore]
public IEnumerable<Vector2Int> 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 Vector2Int Size => Maxs - Mins;
[JsonIgnore]
public readonly Vector2 Extents => Size * 0.5f;
[JsonIgnore]
public readonly Vector2 RandomPointInside => Random.Shared.VectorInSquare(this);
[JsonIgnore]
public readonly float Volume
{
get
{
Vector2 vector = Size.Abs();
return vector.x * vector.y;
}
}
#region constructors
public BBox2Int(Vector2Int mins, Vector2Int maxs)
{
Mins = Vector2Int.Min(mins, maxs);
Maxs = Vector2Int.Max(mins, maxs);
}
public static BBox2Int FromRadius(in Vector2Int radius)
{
var mins = new Vector2Int(-radius.x, -radius.y);
var maxs = new Vector2Int(radius.x, radius.y);
return new(mins, maxs);
}
public static BBox2Int FromMinsAndSize(in Vector2Int mins, Vector2Int size = default)
{
BBox2Int result = default;
result.Mins = mins;
result.Maxs = mins + size;
return result;
}
public static BBox2Int FromPositionAndRadius(in Vector2Int center, Vector2Int radius = default)
{
BBox2Int result = default;
result.Mins = center - radius;
result.Maxs = center + radius;
return result;
}
public static BBox2Int FromBoxes(IEnumerable<BBox2Int> boxes)
{
using IEnumerator<BBox2Int> enumerator = boxes.GetEnumerator();
if(!enumerator.MoveNext())
{
return default;
}
BBox2Int result = enumerator.Current;
while(enumerator.MoveNext())
{
BBox2Int bbox = enumerator.Current;
result = result.AddBBox(in bbox);
}
return result;
}
public static BBox2Int FromPoints(IEnumerable<Vector2Int> points)
{
using IEnumerator<Vector2Int> enumerator = points.GetEnumerator();
if(!enumerator.MoveNext())
{
return default;
}
Vector2Int center = enumerator.Current;
BBox2Int result = new(center, center);
while(enumerator.MoveNext())
{
center = enumerator.Current;
result = result.AddPoint(center);
}
return result;
}
public static BBox2Int FromPointsAndRadius(IEnumerable<Vector2Int> points, Vector2Int radius = default)
{
using IEnumerator<Vector2Int> enumerator = points.GetEnumerator();
if(!enumerator.MoveNext())
{
return default;
}
Vector2Int center = enumerator.Current;
BBox2Int result = FromPositionAndRadius(in center, radius);
while(enumerator.MoveNext())
{
center = enumerator.Current;
BBox2Int bbox = FromPositionAndRadius(in center, radius);
result = result.AddBBox(in bbox);
}
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 BBox2Int Translate(in Vector2Int point)
{
BBox2Int 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 BBox2Int 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 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) => other.GetIntersection(this);
public readonly BBox2Int GetIntersection(BBox2Int 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 BBox2Int AddPoint(in Vector2Int point)
{
BBox2Int result = this;
result.Mins = Vector2Int.Min(Mins, point);
result.Maxs = Vector2Int.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 BBox2Int AddBBox(in BBox2Int bbox)
{
BBox2Int result = this;
result.Mins = Vector2Int.Min(Mins, bbox.Mins);
result.Maxs = Vector2Int.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 BBox2Int Grow(in Vector2Int skin)
{
BBox2Int 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 *(BBox2Int c1, Vector2 c2)
{
return new(c1.Mins * c2, c1.Maxs * c2);
}
public static BBox2Int operator *(BBox2Int c1, Vector2Int c2)
{
c1.Mins *= c2;
c1.Maxs *= c2;
return c1;
}
public static BBox2 operator +(BBox2Int c1, Vector2 c2)
{
return new(c1.Mins + c2, c1.Maxs + c2);
}
public static BBox2Int operator +(BBox2Int c1, Vector2Int c2)
{
c1.Mins += c2;
c1.Maxs += c2;
return c1;
}
public static bool operator ==(BBox2Int left, BBox2Int right)
{
return left.Equals(right);
}
public static bool operator !=(BBox2Int left, BBox2Int right)
{
return !(left == right);
}
public static implicit operator BBox2(BBox2Int bBoxInt) => new(bBoxInt.Mins, bBoxInt.Maxs);
public static explicit operator BBox2Int(BBox2 bBoxInt) => new((Vector2Int)bBoxInt.Mins, (Vector2Int)bBoxInt.Maxs);
#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 readonly BBox2Int Snap(int distance)
{
return new BBox2Int(Mins.SnapToGrid(distance), Maxs.SnapToGrid(distance));
}
public override readonly bool Equals(object? obj)
{
if(obj is BBox2Int o)
return Equals(o);
return false;
}
public readonly bool Equals(BBox2Int o)
{
return Mins == o.Mins && Maxs == o.Maxs;
}
public override readonly int GetHashCode()
{
return HashCode.Combine(Mins, Maxs);
}
}