private static void ComputeInitialTetrahedron(RawList<Vector3> points, RawList<int> outsidePoints, RawList<int> triangleIndices, out Vector3 centroid)
{
//Find four points on the hull.
//We'll start with using the x axis to identify two points on the hull.
int a, b, c, d;
Vector3 direction;
//Find the extreme points along the x axis.
float minimumX = float.MaxValue, maximumX = -float.MaxValue;
int minimumXIndex = 0, maximumXIndex = 0;
for (int i = 0; i < points.Count; ++i)
{
var v = points.Elements[i];
if (v.X > maximumX)
{
maximumX = v.X;
maximumXIndex = i;
}
else if (v.X < minimumX)
{
minimumX = v.X;
minimumXIndex = i;
}
}
a = minimumXIndex;
b = maximumXIndex;
//Check for redundancies..
if (a == b)
throw new Exception("Point set is degenerate; convex hulls must have volume.");
//Now, use a second axis perpendicular to the two points we found.
Vector3 ab;
Vector3.Subtract(ref points.Elements[b], ref points.Elements[a], out ab);
Vector3.Cross(ref ab, ref Toolbox.UpVector, out direction);
if (direction.LengthSquared() < Toolbox.Epsilon)
Vector3.Cross(ref ab, ref Toolbox.RightVector, out direction);
float minimumDot, maximumDot;
int minimumIndex, maximumIndex;
GetExtremePoints(ref direction, points, out maximumDot, out minimumDot, out maximumIndex, out minimumIndex);
//Compare the location of the extreme points to the location of the axis.
float dot;
Vector3.Dot(ref direction, ref points.Elements[a], out dot);
//Use the point further from the axis.
if (Math.Abs(dot - minimumDot) > Math.Abs(dot - maximumDot))
{
//In this case, we should use the minimum index.
c = minimumIndex;
}
else
{
//In this case, we should use the maximum index.
c = maximumIndex;
}
//Check for redundancies..
if (a == c || b == c)
throw new Exception("Point set is degenerate; convex hulls must have volume.");
//Use a third axis perpendicular to the plane defined by the three unique points a, b, and c.
Vector3 ac;
Vector3.Subtract(ref points.Elements[c], ref points.Elements[a], out ac);
Vector3.Cross(ref ab, ref ac, out direction);
GetExtremePoints(ref direction, points, out maximumDot, out minimumDot, out maximumIndex, out minimumIndex);
//Compare the location of the extreme points to the location of the plane.
Vector3.Dot(ref direction, ref points.Elements[a], out dot);
//Use the point further from the plane.
if (Math.Abs(dot - minimumDot) > Math.Abs(dot - maximumDot))
{
//In this case, we should use the minimum index.
d = minimumIndex;
}
else
{
//In this case, we should use the maximum index.
d = maximumIndex;
}
//Check for redundancies..
if (a == d || b == d || c == d)
throw new Exception("Point set is degenerate; convex hulls must have volume.");
//Add the triangles.
triangleIndices.Add(a);
triangleIndices.Add(b);
triangleIndices.Add(c);
triangleIndices.Add(a);
triangleIndices.Add(b);
triangleIndices.Add(d);
triangleIndices.Add(a);
triangleIndices.Add(c);
triangleIndices.Add(d);
triangleIndices.Add(b);
triangleIndices.Add(c);
triangleIndices.Add(d);
//The centroid is guaranteed to be within the convex hull. It will be used to verify the windings of triangles throughout the hull process.
Vector3.Add(ref points.Elements[a], ref points.Elements[b], out centroid);
Vector3.Add(ref centroid, ref points.Elements[c], out centroid);
Vector3.Add(ref centroid, ref points.Elements[d], out centroid);
Vector3.Multiply(ref centroid, 0.25f, out centroid);
for (int i = 0; i < triangleIndices.Count; i += 3)
{
var vA = points.Elements[triangleIndices.Elements[i]];
var vB = points.Elements[triangleIndices.Elements[i + 1]];
var vC = points.Elements[triangleIndices.Elements[i + 2]];
//Check the signed volume of a parallelepiped with the edges of this triangle and the centroid.
Vector3 cross;
Vector3.Subtract(ref vB, ref vA, out ab);
Vector3.Subtract(ref vC, ref vA, out ac);
Vector3.Cross(ref ac, ref ab, out cross);
Vector3 offset;
Vector3.Subtract(ref vA, ref centroid, out offset);
float volume;
Vector3.Dot(ref offset, ref cross, out volume);
//This volume/cross product could also be used to check for degeneracy, but we already tested for that.
if (Math.Abs(volume) < Toolbox.BigEpsilon)
{
throw new Exception("Point set is degenerate; convex hulls must have volume.");
}
if (volume < 0)
{
//If the signed volume is negative, that means the triangle's winding is opposite of what we want.
//Flip it around!
var temp = triangleIndices.Elements[i];
triangleIndices.Elements[i] = triangleIndices.Elements[i + 1];
triangleIndices.Elements[i + 1] = temp;
}
}
}