/* 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 { // default nearby table size private const int DefaultNearbySize = 50; private List _table; private List _voidList = new List(1); private List[][] _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((_row * _column) / 2); _nearby = new List[_column][]; for (int i = 0; i < _column; ++i) { _nearby[i] = new List[_row]; for (int j = 0; j < _row; ++j) { _nearby[i][j] = new List(DefaultNearbySize); } } _initialized = true; } /// /// Append value to the table and identify its position in the space. /// Don't need to rehash table after append operation. /// 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 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; } /// /// Updates the spatial relationships of objects. Rehash function /// needed if elements change their position in the space. /// 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); } } /// /// Add element to its position and neighbor cells. /// /// 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); } } } /// /// Check if a position is out of the spatial range /// /// /// /// true if position is in range. private bool InRange(float x, float y) { return (x > 0 && x < _column && y > 0 && y < _row); } public IEnumerator GetEnumerator() { return _table.GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } } }