// MIT License - Copyright (c) 2025 wallstop
// Full license text: https://github.com/wallstop/unity-helpers/blob/main/LICENSE
// ReSharper disable once CheckNamespace
namespace WallstopStudios.UnityHelpers.Core.Extension
{
using System.Collections.Generic;
using UnityEngine;
using WallstopStudios.UnityHelpers.Core.DataStructure.Adapters;
///
/// Grid traversal and BoundsInt utility helpers that operate on discretized space.
///
public static partial class UnityExtensions
{
///
/// Creates a new BoundsInt with additional padding in the X and Y directions.
///
/// The source bounds to add padding to.
/// The padding to add to both left and right sides.
/// The padding to add to both top and bottom sides.
/// A new BoundsInt expanded by the specified padding amounts.
///
/// Thread Safety: Thread-safe, no Unity API calls.
/// Null Handling: Not applicable for value types.
/// Performance: O(1) - Simple arithmetic.
/// Allocations: None - returns value type.
/// Unity Behavior: Z dimension remains unchanged.
/// Edge Cases: Negative padding shrinks the bounds. Size increases by 2*padding in each direction.
///
public static BoundsInt WithPadding(this BoundsInt bounds, int xPadding, int yPadding)
{
Vector3Int size = bounds.size;
return new BoundsInt(
bounds.xMin - xPadding,
bounds.yMin - yPadding,
bounds.zMin,
size.x + 2 * xPadding,
size.y + 2 * yPadding,
size.z
);
}
///
/// Enumerates all FastVector3Int positions within the bounds.
///
/// The bounds to enumerate positions within.
/// An enumerable of all FastVector3Int positions within the bounds.
///
/// Thread Safety: Thread-safe, no Unity API calls.
/// Null Handling: Not applicable for value types.
/// Performance: O(volume) where volume is the number of cells in the bounds.
/// Allocations: Uses yield return, allocates enumerator. Each FastVector3Int is a value type.
/// Unity Behavior: Uses half-open interval [min, max) consistent with BoundsInt.
/// Edge Cases: Zero or negative size bounds yield no positions.
/// Iteration order is X (innermost), then Y, then Z (outermost).
///
public static IEnumerable AllFastPositionsWithin(this BoundsInt bounds)
{
Vector3Int min = bounds.min;
Vector3Int max = bounds.max;
for (int x = min.x; x < max.x; ++x)
{
for (int y = min.y; y < max.y; ++y)
{
for (int z = min.z; z < max.z; ++z)
{
yield return new FastVector3Int(x, y, z);
}
}
}
}
///
/// Fills a list with all FastVector3Int positions within the bounds.
///
/// The bounds to get positions from.
/// The list to clear and fill with positions.
/// The buffer list containing all positions.
///
/// Thread Safety: Thread-safe if buffer is not accessed concurrently.
/// Null Handling: Throws NullReferenceException if buffer is null.
/// Performance: O(volume) where volume is the number of cells in the bounds.
/// Allocations: May allocate if buffer capacity is insufficient. Clears buffer first.
/// Unity Behavior: Uses half-open interval [min, max) consistent with BoundsInt.
/// Edge Cases: Zero or negative size bounds result in an empty buffer.
/// Iteration order is X (innermost), then Y, then Z (outermost).
///
public static List AllFastPositionsWithin(
this BoundsInt bounds,
List buffer
)
{
buffer.Clear();
Vector3Int min = bounds.min;
Vector3Int max = bounds.max;
for (int x = min.x; x < max.x; ++x)
{
for (int y = min.y; y < max.y; ++y)
{
for (int z = min.z; z < max.z; ++z)
{
FastVector3Int position = new(x, y, z);
buffer.Add(position);
}
}
}
return buffer;
}
///
/// Determines if a BoundsInt contains a FastVector3Int position.
///
/// The bounds to test containment in.
/// The position to test.
/// True if the position is within the bounds; otherwise, false.
///
/// Thread Safety: Thread-safe, no Unity API calls.
/// Null Handling: Not applicable for value types.
/// Performance: O(1) - Delegates to BoundsInt.Contains via implicit conversion.
/// Allocations: None.
/// Unity Behavior: Uses half-open interval [min, max) for containment test.
/// Edge Cases: Points on the max boundary are NOT contained.
///
public static bool Contains(this BoundsInt bounds, FastVector3Int position)
{
return bounds.Contains(position);
}
///
/// Determines if a FastVector3Int position is on the 2D edge of a BoundsInt (ignores Z axis).
///
/// The position to test.
/// The bounds to test against.
/// True if the position is on the 2D boundary of the bounds; otherwise, false.
///
/// Thread Safety: Thread-safe, no Unity API calls.
/// Null Handling: Not applicable for value types.
/// Performance: O(1) - Simple comparisons.
/// Allocations: None.
/// Unity Behavior: Tests if position is on the min or max-1 boundary in X or Y.
/// Edge Cases: Position must be within bounds AND on an edge to return true.
/// Uses max-1 because BoundsInt uses half-open intervals. Z axis is ignored.
///
public static bool IsOnEdge2D(this FastVector3Int position, BoundsInt bounds)
{
if (bounds.xMin == position.x || bounds.xMax - 1 == position.x)
{
return bounds.yMin <= position.y && position.y < bounds.yMax;
}
if (bounds.yMin == position.y || bounds.yMax - 1 == position.y)
{
return bounds.xMin <= position.x && position.x < bounds.xMax;
}
return false;
}
}
}