// -----------------------------------------------------------------------
//
// Triangle.NET code by Christian Woltering, http://triangle.codeplex.com/
//
// -----------------------------------------------------------------------
namespace UnityEngine.U2D.Animation.TriangleNet
{
using System;
using System.Collections.Generic;
using Animation.TriangleNet.Geometry;
using Animation.TriangleNet.Topology;
internal class TrianglePool : ICollection
{
// Determines the size of each block in the pool.
private const int BLOCKSIZE = 1024;
// The total number of currently allocated triangles.
int size;
// The number of triangles currently used.
int count;
// The pool.
Triangle[][] pool;
// A stack of free triangles.
Stack stack;
public TrianglePool()
{
size = 0;
// On startup, the pool should be able to hold 2^16 triangles.
int n = Math.Max(1, 65536 / BLOCKSIZE);
pool = new Triangle[n][];
pool[0] = new Triangle[BLOCKSIZE];
stack = new Stack(BLOCKSIZE);
}
///
/// Gets a triangle from the pool.
///
///
public Triangle Get()
{
Triangle triangle;
if (stack.Count > 0)
{
triangle = stack.Pop();
triangle.hash = -triangle.hash - 1;
Cleanup(triangle);
}
else if (count < size)
{
triangle = pool[count / BLOCKSIZE][count % BLOCKSIZE];
triangle.id = triangle.hash;
Cleanup(triangle);
count++;
}
else
{
triangle = new Triangle();
triangle.hash = size;
triangle.id = triangle.hash;
int block = size / BLOCKSIZE;
if (pool[block] == null)
{
pool[block] = new Triangle[BLOCKSIZE];
// Check if the pool has to be resized.
if (block + 1 == pool.Length)
{
Array.Resize(ref pool, 2 * pool.Length);
}
}
// Add triangle to pool.
pool[block][size % BLOCKSIZE] = triangle;
count = ++size;
}
return triangle;
}
public void Release(Triangle triangle)
{
stack.Push(triangle);
// Mark the triangle as free (used by enumerator).
triangle.hash = -triangle.hash - 1;
}
///
/// Restart the triangle pool.
///
public TrianglePool Restart()
{
foreach (var triangle in stack)
{
// Reset hash to original value.
triangle.hash = -triangle.hash - 1;
}
stack.Clear();
count = 0;
return this;
}
///
/// Samples a number of triangles from the pool.
///
/// The number of triangles to sample.
///
///
internal IEnumerable Sample(int k, Random random)
{
int i, count = this.Count;
if (k > count)
{
// TODO: handle Sample special case.
k = count;
}
Triangle t;
// TODO: improve sampling code (to ensure no duplicates).
while (k > 0)
{
i = random.Next(0, count);
t = pool[i / BLOCKSIZE][i % BLOCKSIZE];
if (t.hash >= 0)
{
k--;
yield return t;
}
}
}
private void Cleanup(Triangle triangle)
{
triangle.label = 0;
triangle.area = 0.0;
triangle.infected = false;
for (int i = 0; i < 3; i++)
{
triangle.vertices[i] = null;
triangle.subsegs[i] = default(Osub);
triangle.neighbors[i] = default(Otri);
}
}
public void Add(Triangle item)
{
throw new NotImplementedException();
}
public void Clear()
{
stack.Clear();
int blocks = (size / BLOCKSIZE) + 1;
for (int i = 0; i < blocks; i++)
{
var block = pool[i];
// Number of triangles in current block:
int length = (size - i * BLOCKSIZE) % BLOCKSIZE;
for (int j = 0; j < length; j++)
{
block[j] = null;
}
}
size = count = 0;
}
public bool Contains(Triangle item)
{
int i = item.hash;
if (i < 0 || i > size)
{
return false;
}
return pool[i / BLOCKSIZE][i % BLOCKSIZE].hash >= 0;
}
public void CopyTo(Triangle[] array, int index)
{
var enumerator = GetEnumerator();
while (enumerator.MoveNext())
{
array[index] = enumerator.Current;
index++;
}
}
public int Count
{
get { return count - stack.Count; }
}
public bool IsReadOnly
{
get { return true; }
}
public bool Remove(Triangle item)
{
throw new NotImplementedException();
}
public IEnumerator GetEnumerator()
{
return new Enumerator(this);
}
System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
class Enumerator : IEnumerator
{
// TODO: enumerator should be able to tell if collection changed.
int count;
Triangle[][] pool;
Triangle current;
int index, offset;
internal Enumerator(TrianglePool pool)
{
this.count = pool.Count;
this.pool = pool.pool;
index = 0;
offset = 0;
}
public Triangle Current
{
get { return current; }
}
public void Dispose()
{
}
object System.Collections.IEnumerator.Current
{
get { return current; }
}
public bool MoveNext()
{
while (index < count)
{
current = pool[offset / BLOCKSIZE][offset % BLOCKSIZE];
offset++;
if (current.hash >= 0)
{
index++;
return true;
}
}
return false;
}
public void Reset()
{
index = offset = 0;
}
}
}
}