private static void From3Points( Vector3D v1, Vector3D v2, Vector3D v3,
out Vector3D center, out double radius )
{
// Circumcenter/Circumradius of triangle (circle from 3 points)
// http://mathworld.wolfram.com/Circumcenter.html
// http://mathworld.wolfram.com/Circumradius.html
// http://mathworld.wolfram.com/BarycentricCoordinates.html
// side lengths and their squares
double a = ( v3 - v2 ).Abs(); // Opposite v1
double b = ( v1 - v3 ).Abs(); // Opposite v2
double c = ( v2 - v1 ).Abs(); // Opposite v3
double a2 = a * a;
double b2 = b * b;
double c2 = c * c;
Vector3D circumCenterBary = new Vector3D(
a2 * ( b2 + c2 - a2 ),
b2 * ( c2 + a2 - b2 ),
c2 * ( a2 + b2 - c2 ) );
circumCenterBary /= (circumCenterBary.X + circumCenterBary.Y + circumCenterBary.Z); // Normalize.
center = BaryToCartesian( v1, v2, v3, circumCenterBary );
double s = (a + b + c) / 2; // semiperimeter
radius = a * b * c / ( 4 * Math.Sqrt( s * ( a + b - s ) * ( a + c - s ) * ( b + c - s ) ) );
}