Skip to content

Commit

Permalink
Added visit methods to NativeArray2D
Browse files Browse the repository at this point in the history
  • Loading branch information
BasmanovDaniil committed Jan 9, 2021
1 parent 3f81ad4 commit 55873c8
Showing 1 changed file with 311 additions and 0 deletions.
311 changes: 311 additions & 0 deletions Runtime/NativeArray2D.cs
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,317 @@ public bool IsInBounds(int x, int y)
return x >= 0 && x < LengthX && y >= 0 && y < LengthY;
}

#region FloodVisit4

/// <summary>
/// Visits all connected elements with the same value as the start element
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Flood_fill
/// </remarks>
public void FloodVisit4(Vector2Int start, Action<int, int> visit, IEqualityComparer<T> comparer = null)
{
FloodVisit4(start.x, start.y, visit, comparer);
}

/// <summary>
/// Visits all connected elements with the same value as the start element
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Flood_fill
/// </remarks>
public void FloodVisit4(int startX, int startY, Action<int, int> visit, IEqualityComparer<T> comparer = null)
{
if (visit == null) throw new ArgumentNullException(nameof(visit));

int lengthX = LengthX;
int lengthY = LengthY;

if (startX < 0 || startX >= lengthX) throw new ArgumentOutOfRangeException(nameof(startX));
if (startY < 0 || startY >= lengthY) throw new ArgumentOutOfRangeException(nameof(startY));

if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}

bool[,] processed = new bool[lengthX, lengthY];
T value = this[startX, startY];

var queue = new Queue<Vector2Int>();
queue.Enqueue(new Vector2Int(startX, startY));
processed[startX, startY] = true;

while (queue.Count > 0)
{
Vector2Int cell = queue.Dequeue();

if (cell.x > 0)
{
Process(processed, cell.x - 1, cell.y, comparer, value, queue);
}
if (cell.x + 1 < lengthX)
{
Process(processed, cell.x + 1, cell.y, comparer, value, queue);
}
if (cell.y > 0)
{
Process(processed, cell.x, cell.y - 1, comparer, value, queue);
}
if (cell.y + 1 < lengthY)
{
Process(processed, cell.x, cell.y + 1, comparer, value, queue);
}

visit(cell.x, cell.y);
}
}

private void Process(bool[,] processed, int x, int y, IEqualityComparer<T> comparer, T value, Queue<Vector2Int> queue)
{
if (!processed[x, y])
{
if (comparer.Equals(this[x, y], value))
{
queue.Enqueue(new Vector2Int(x, y));
}
processed[x, y] = true;
}
}

#endregion FloodVisit4

#region FloodVisit8

/// <summary>
/// Visits all connected elements with the same value as the start element
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Flood_fill
/// </remarks>
public void FloodVisit8(Vector2Int start, Action<int, int> visit, IEqualityComparer<T> comparer = null)
{
FloodVisit8(start.x, start.y, visit, comparer);
}

/// <summary>
/// Visits all connected elements with the same value as the start element
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Flood_fill
/// </remarks>
public void FloodVisit8(int startX, int startY, Action<int, int> visit, IEqualityComparer<T> comparer = null)
{
if (visit == null) throw new ArgumentNullException(nameof(visit));

if (startX < 0 || startX >= LengthX) throw new ArgumentOutOfRangeException(nameof(startX));
if (startY < 0 || startY >= LengthY) throw new ArgumentOutOfRangeException(nameof(startY));

if (comparer == null)
{
comparer = EqualityComparer<T>.Default;
}

bool[,] processed = new bool[LengthX, LengthY];
T value = this[startX, startY];

var queue = new Queue<Vector2Int>();
queue.Enqueue(new Vector2Int(startX, startY));
processed[startX, startY] = true;

while (queue.Count > 0)
{
Vector2Int cell = queue.Dequeue();

bool xGreaterThanZero = cell.x > 0;
bool xLessThanWidth = cell.x + 1 < LengthX;

bool yGreaterThanZero = cell.y > 0;
bool yLessThanHeight = cell.y + 1 < LengthY;

if (yGreaterThanZero)
{
if (xGreaterThanZero) Process(processed, cell.x - 1, cell.y - 1, comparer, value, queue);

Process(processed, cell.x, cell.y - 1, comparer, value, queue);

if (xLessThanWidth) Process(processed, cell.x + 1, cell.y - 1, comparer, value, queue);
}

if (xGreaterThanZero) Process(processed, cell.x - 1, cell.y, comparer, value, queue);
if (xLessThanWidth) Process(processed, cell.x + 1, cell.y, comparer, value, queue);

if (yLessThanHeight)
{
if (xGreaterThanZero) Process(processed, cell.x - 1, cell.y + 1, comparer, value, queue);

Process(processed, cell.x, cell.y + 1, comparer, value, queue);

if (xLessThanWidth) Process(processed, cell.x + 1, cell.y + 1, comparer, value, queue);
}

visit(cell.x, cell.y);
}
}

#endregion FloodVisit8

#region Visit4

/// <summary>
/// Visits four cells orthogonally surrounding the center cell
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Von_Neumann_neighborhood
/// </remarks>
public void Visit4(Vector2Int center, Action<int, int> visit)
{
Visit4(center.x, center.y, visit);
}

/// <summary>
/// Visits four cells orthogonally surrounding the center cell
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Von_Neumann_neighborhood
/// </remarks>
public void Visit4(int x, int y, Action<int, int> visit)
{
if (visit == null) throw new ArgumentNullException(nameof(visit));

if (x > 0)
{
visit(x - 1, y);
}
if (x + 1 < LengthX)
{
visit(x + 1, y);
}
if (y > 0)
{
visit(x, y - 1);
}
if (y + 1 < LengthY)
{
visit(x, y + 1);
}
}

/// <summary>
/// Visits four cells orthogonally surrounding the center cell
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Von_Neumann_neighborhood
/// </remarks>
public void Visit4Unbounded(Vector2Int center, Action<int, int> visit)
{
Visit4Unbounded(center.x, center.y, visit);
}

/// <summary>
/// Visits four cells orthogonally surrounding the center cell
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Von_Neumann_neighborhood
/// </remarks>
public void Visit4Unbounded(int x, int y, Action<int, int> visit)
{
if (visit == null) throw new ArgumentNullException(nameof(visit));

visit(x - 1, y);
visit(x + 1, y);
visit(x, y - 1);
visit(x, y + 1);
}

#endregion Visit4

#region Visit8

/// <summary>
/// Visits eight cells surrounding the center cell
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Moore_neighborhood
/// </remarks>
public void Visit8(Vector2Int center, Action<int, int> visit)
{
Visit8(center.x, center.y, visit);
}

/// <summary>
/// Visits eight cells surrounding the center cell
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Moore_neighborhood
/// </remarks>
public void Visit8(int x, int y, Action<int, int> visit)
{
if (visit == null) throw new ArgumentNullException(nameof(visit));

bool xGreaterThanZero = x > 0;
bool xLessThanWidth = x + 1 < LengthX;

bool yGreaterThanZero = y > 0;
bool yLessThanHeight = y + 1 < LengthY;

if (yGreaterThanZero)
{
if (xGreaterThanZero) visit(x - 1, y - 1);

visit(x, y - 1);

if (xLessThanWidth) visit(x + 1, y - 1);
}

if (xGreaterThanZero) visit(x - 1, y);
if (xLessThanWidth) visit(x + 1, y);

if (yLessThanHeight)
{
if (xGreaterThanZero) visit(x - 1, y + 1);

visit(x, y + 1);

if (xLessThanWidth) visit(x + 1, y + 1);
}
}

/// <summary>
/// Visits eight cells surrounding the center cell
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Moore_neighborhood
/// </remarks>
public void Visit8Unbounded(Vector2Int center, Action<int, int> visit)
{
Visit8Unbounded(center.x, center.y, visit);
}

/// <summary>
/// Visits eight cells surrounding the center cell
/// </summary>
/// <remarks>
/// https://en.wikipedia.org/wiki/Moore_neighborhood
/// </remarks>
public void Visit8Unbounded(int x, int y, Action<int, int> visit)
{
if (visit == null) throw new ArgumentNullException(nameof(visit));

visit(x - 1, y - 1);
visit(x, y - 1);
visit(x + 1, y - 1);

visit(x - 1, y);
visit(x + 1, y);

visit(x - 1, y + 1);
visit(x, y + 1);
visit(x + 1, y + 1);
}

#endregion Visit8

public void Dispose() => array.Dispose();
public void Dispose(JobHandle inputDeps) => array.Dispose(inputDeps);
public IEnumerator<T> GetEnumerator() => array.GetEnumerator();
Expand Down

0 comments on commit 55873c8

Please sign in to comment.