public static VoronoiRegion GetClosestPointOnTriangleToPoint(ref Vector3 a, ref Vector3 b, ref Vector3 c, ref Vector3 p, out Vector3 closestPoint)
{
float v, w;
Vector3 ab;
Vector3.Subtract(ref b, ref a, out ab);
Vector3 ac;
Vector3.Subtract(ref c, ref a, out ac);
//Vertex region A?
Vector3 ap;
Vector3.Subtract(ref p, ref a, out ap);
float d1;
Vector3.Dot(ref ab, ref ap, out d1);
float d2;
Vector3.Dot(ref ac, ref ap, out d2);
if (d1 <= 0 && d2 < 0)
{
closestPoint = a;
return VoronoiRegion.A;
}
//Vertex region B?
Vector3 bp;
Vector3.Subtract(ref p, ref b, out bp);
float d3;
Vector3.Dot(ref ab, ref bp, out d3);
float d4;
Vector3.Dot(ref ac, ref bp, out d4);
if (d3 >= 0 && d4 <= d3)
{
closestPoint = b;
return VoronoiRegion.B;
}
//Edge region AB?
float vc = d1 * d4 - d3 * d2;
if (vc <= 0 && d1 >= 0 && d3 <= 0)
{
v = d1 / (d1 - d3);
Vector3.Multiply(ref ab, v, out closestPoint);
Vector3.Add(ref closestPoint, ref a, out closestPoint);
return VoronoiRegion.AB;
}
//Vertex region C?
Vector3 cp;
Vector3.Subtract(ref p, ref c, out cp);
float d5;
Vector3.Dot(ref ab, ref cp, out d5);
float d6;
Vector3.Dot(ref ac, ref cp, out d6);
if (d6 >= 0 && d5 <= d6)
{
closestPoint = c;
return VoronoiRegion.C;
}
//Edge region AC?
float vb = d5 * d2 - d1 * d6;
if (vb <= 0 && d2 >= 0 && d6 <= 0)
{
w = d2 / (d2 - d6);
Vector3.Multiply(ref ac, w, out closestPoint);
Vector3.Add(ref closestPoint, ref a, out closestPoint);
return VoronoiRegion.AC;
}
//Edge region BC?
float va = d3 * d6 - d5 * d4;
if (va <= 0 && (d4 - d3) >= 0 && (d5 - d6) >= 0)
{
w = (d4 - d3) / ((d4 - d3) + (d5 - d6));
Vector3.Subtract(ref c, ref b, out closestPoint);
Vector3.Multiply(ref closestPoint, w, out closestPoint);
Vector3.Add(ref closestPoint, ref b, out closestPoint);
return VoronoiRegion.BC;
}
//Inside triangle?
float denom = 1 / (va + vb + vc);
v = vb * denom;
w = vc * denom;
Vector3 abv;
Vector3.Multiply(ref ab, v, out abv);
Vector3 acw;
Vector3.Multiply(ref ac, w, out acw);
Vector3.Add(ref a, ref abv, out closestPoint);
Vector3.Add(ref closestPoint, ref acw, out closestPoint);
return VoronoiRegion.ABC;
}