CtrEditor/Simulacion/Fluids/2/SpartialTable.cs

180 lines
4.8 KiB
C#

/* Original source Farseer Physics Engine:
* Copyright (c) 2014 Ian Qvist, http://farseerphysics.codeplex.com
* Microsoft Permissive License (Ms-PL) v1.1
*/
using System.Collections;
using System.Collections.Generic;
namespace tainicom.Aether.Physics2D.Fluids
{
public class SpatialTable : IEnumerable<Particle>
{
// default nearby table size
private const int DefaultNearbySize = 50;
private List<Particle> _table;
private List<Particle> _voidList = new List<Particle>(1);
private List<Particle>[][] _nearby;
bool _initialized;
private int _row;
private int _column;
private int _cellSize;
public SpatialTable(int column, int row, int cellSize)
{
_row = row;
_cellSize = cellSize;
_column = column;
}
public void Initialize()
{
_table = new List<Particle>((_row * _column) / 2);
_nearby = new List<Particle>[_column][];
for (int i = 0; i < _column; ++i)
{
_nearby[i] = new List<Particle>[_row];
for (int j = 0; j < _row; ++j)
{
_nearby[i][j] = new List<Particle>(DefaultNearbySize);
}
}
_initialized = true;
}
/// <summary>
/// Append value to the table and identify its position in the space.
/// Don't need to rehash table after append operation.</summary>
/// <param name="value"></param>
public void Add(Particle value)
{
if (!_initialized)
Initialize();
AddInterRadius(value);
_table.Add(value);
}
public Particle this[int i]
{
get { return _table[i]; }
set { _table[i] = value; }
}
public void Remove(Particle value)
{
_table.Remove(value);
}
public void Clear()
{
for (int i = 0; i < _column; ++i)
{
for (int j = 0; j < _row; ++j)
{
_nearby[i][j].Clear();
_nearby[i][j] = null;
}
}
_table.Clear();
}
public int Count
{
get { return (_table == null)? 0 : _table.Count; }
}
public List<Particle> GetNearby(Particle value)
{
int x = posX(value);
int y = posY(value);
if (!InRange(x, y))
return _voidList;
return _nearby[x][y];
}
private int posX(Particle value)
{
return (int)((value.Position.X + (_column / 2) + 0.3f) / _cellSize);
}
private int posY(Particle value)
{
return (int)((value.Position.Y + 0.3f) / _cellSize);
}
public int CountNearBy(Particle value)
{
return GetNearby(value).Count;
}
/// <summary>
/// Updates the spatial relationships of objects. Rehash function
/// needed if elements change their position in the space.
/// </summary>
public void Rehash()
{
if (_table == null || _table.Count == 0)
return;
for (int i = 0; i < _column; i++)
{
for (int j = 0; j < _row; j++)
{
if (_nearby[i][j] != null)
_nearby[i][j].Clear();
}
}
foreach (Particle particle in _table)
{
AddInterRadius(particle);
}
}
/// <summary>
/// Add element to its position and neighbor cells.
/// </summary>
/// <param name="value"></param>
private void AddInterRadius(Particle value)
{
for (int i = -1; i < 2; ++i)
{
for (int j = -1; j < 2; ++j)
{
int x = posX(value) + i;
int y = posY(value) + j;
if (InRange(x, y))
_nearby[x][y].Add(value);
}
}
}
/// <summary>
/// Check if a position is out of the spatial range
/// </summary>
/// <param name="x"></param>
/// <param name="y"></param>
/// <returns>true if position is in range.</returns>
private bool InRange(float x, float y)
{
return (x > 0 && x < _column && y > 0 && y < _row);
}
public IEnumerator<Particle> GetEnumerator()
{
return _table.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
}