/// <summary>
/// Create a convex hull from the given array of points.
/// The count must be in the range [3, Settings.maxPolygonVertices].
/// This method takes an arraypool for pooling
/// </summary>
/// <warning>the points may be re-ordered, even if they form a convex polygon</warning>
/// <warning>collinear points are handled but not removed. Collinear points may lead to poor stacking behavior.</warning>
public void Set(Vec2[] verts, int num, Vec2Array vecPool, IntArray intPool)
{
Debug.Assert(3 <= num && num <= Settings.MAX_POLYGON_VERTICES);
if (num < 3)
{
SetAsBox(1.0f, 1.0f);
return;
}
int n = MathUtils.Min(num, Settings.MAX_POLYGON_VERTICES);
// Copy the vertices into a local buffer
Vec2[] ps = (vecPool != null) ? vecPool.Get(n) : new Vec2[n];
for (int i = 0; i < n; ++i)
{
ps[i] = verts[i];
}
// Create the convex hull using the Gift wrapping algorithm
// http://en.wikipedia.org/wiki/Gift_wrapping_algorithm
// Find the right most point on the hull
int i0 = 0;
float x0 = ps[0].X;
for (int i = 1; i < num; ++i)
{
float x = ps[i].X;
if (x > x0 || (x == x0 && ps[i].Y < ps[i0].Y))
{
i0 = i;
x0 = x;
}
}
int[] hull = (intPool != null) ? intPool.Get(Settings.MAX_POLYGON_VERTICES) : new int[Settings.MAX_POLYGON_VERTICES];
int m = 0;
int ih = i0;
while (true)
{
hull[m] = ih;
int ie = 0;
for (int j = 1; j < n; ++j)
{
if (ie == ih)
{
ie = j;
continue;
}
Vec2 r = pool1.Set(ps[ie]).SubLocal(ps[hull[m]]);
Vec2 v = pool2.Set(ps[j]).SubLocal(ps[hull[m]]);
float c = Vec2.Cross(r, v);
if (c < 0.0f)
{
ie = j;
}
// Collinearity check
if (c == 0.0f && v.LengthSquared() > r.LengthSquared())
{
ie = j;
}
}
++m;
ih = ie;
if (ie == i0)
{
break;
}
}
VertexCount = m;
// Copy vertices.
for (int i = 0; i < VertexCount; ++i)
{
if (Vertices[i] == null)
{
Vertices[i] = new Vec2();
}
Vertices[i].Set(ps[hull[i]]);
}
Vec2 edge = pool1;
// Compute normals. Ensure the edges have non-zero length.
for (int i = 0; i < VertexCount; ++i)
{
int i1 = i;
int i2 = i + 1 < VertexCount ? i + 1 : 0;
edge.Set(Vertices[i2]).SubLocal(Vertices[i1]);
Debug.Assert(edge.LengthSquared() > Settings.EPSILON * Settings.EPSILON);
Vec2.CrossToOutUnsafe(edge, 1f, Normals[i]);
Normals[i].Normalize();
}
// Compute the polygon centroid.
ComputeCentroidToOut(Vertices, VertexCount, Centroid);
}