General/BBoxExtensions.cs
using System.Collections.Generic;
using System.Linq;

namespace ExtendedBox.General;

public static class BBoxExtensions
{
    public static BBox Grow(this BBox bbox, float value, bool clampAtCenter = false) =>
        bbox.Grow(new Vector3(value), clampAtCenter);

    public static BBox Grow(this BBox bbox, in Vector3 value, bool clampAtCenter = false)
    {
        var result = bbox;
        result.Mins -= value;
        result.Maxs += value;

        if(clampAtCenter)
        {
            var center = bbox.Center;
            result.Mins = result.Mins.ComponentMin(center);
            result.Maxs = result.Maxs.ComponentMax(center);
        }

        return result;
    }

    public static BBox Shrink(this BBox bbox, float value, bool clampAtCenter = false) =>
        bbox.Shrink(new Vector3(value), clampAtCenter);

    public static BBox Shrink(this BBox bbox, in Vector3 value, bool clampAtCenter = false)
    {
        var result = bbox;
        result.Mins += value;
        result.Maxs -= value;

        if(clampAtCenter)
        {
            var center = bbox.Center;
            result.Mins = result.Mins.ComponentMin(center);
            result.Maxs = result.Maxs.ComponentMax(center);
        }

        return result;
    }

    public static BBox AddOrCreate(this BBox? @this, Vector3 point)
    {
        if(@this.HasValue)
            return @this.Value.AddPoint(point);
        return new(point, point);
    }

    public static BBox AddOrCreate(this BBox? @this, BBox bbox)
    {
        if(@this.HasValue)
            return @this.Value.AddBBox(bbox);
        return bbox;
    }

    public static BBox? AddOrCreate(this BBox? @this, IEnumerable<Vector3> points)
    {
        if(!points.Any())
            return @this;

        return @this.AddOrCreate(BBox.FromPoints(points));
    }

    public static BBox? AddOrCreate(this BBox? @this, IEnumerable<BBox> boxes)
    {
        if(!boxes.Any())
            return @this;

        return @this.AddOrCreate(BBox.FromBoxes(boxes));
    }

    public static BBox GetIntersection(this BBox @this, BBox other)
    {
        if([email protected](other))
            return new(Vector3Int.Zero, Vector3Int.Zero);

        BBox result = new()
        {
            Mins = @this.Mins.ComponentMax(other.Mins),
            Maxs = @this.Maxs.ComponentMin(other.Maxs)
        };
        return result;
    }

    public static bool AlmostEqual(this BBox @this, in BBox other, float delta = 0.0001f) =>
        @this.Mins.AlmostEqual(other.Mins, delta) && @this.Maxs.AlmostEqual(other.Maxs, delta);

    public static BBoxInt FloorToInt(this BBox bbox) => new(bbox.Mins.FloorToInt(), bbox.Maxs.FloorToInt());
    public static BBoxInt RoundToInt(this BBox bbox) => new(bbox.Mins.RoundToInt(), bbox.Maxs.RoundToInt());
    public static BBoxInt CeilToInt(this BBox bbox) => new(bbox.Mins.CeilToInt(), bbox.Maxs.CeilToInt());
    public static BBoxInt ExpandToInt(this BBox bbox) => new(bbox.Mins.FloorToInt(), bbox.Maxs.CeilToInt());
}