尽管这是一条古老的线索,但我认为后代可以参考一下。公式的来源来自Philip J. Schneider和David H. Eberly的“ 用于计算机图形学的几何工具”。根据文本需要注意的事情
四面体V0,V1,V2,V3的顺序使其与规范的(0,0,0),(1,0,0),(0,1,0),(0,0,1)同构)。
据我了解,同构性在几何中使用时可能有几种不同的含义。如果他表示图论是同构的,则以下代码应正确运行,因为任何四面体的拓扑都是相同的(K4,完整的图)。我使用规范顶点的顺序中的各种排列来测试针对Wolfram alpha的函数结果,但结果没有差异。如果顺序证明有问题,建议您在输入此函数后检查由顶点V1,V2,V3形成的三角形的法线,并通过点积检验将这些点视为半空间,以找出如果那个三角形朝向正确的方向。如果不是,那么简单std::swap
三角形的任意两个顶点中的一个会颠倒法线的方向,您可以继续。但是就像我说的那样,我发现各种排列没有区别。
这是经过翻译的代码,没有使用矩阵来避免实现上的混淆,这很简单。
void Circumsphere(const Vec3& v0, const Vec3& v1, const Vec3& v2, const Vec3& v3, Vec3* center, float* radius)
{
//Create the rows of our "unrolled" 3x3 matrix
Vec3 Row1 = v1 - v0;
float sqLength1 = length2(Row1);
Vec3 Row2 = v2 - v0;
float sqLength2 = length2(Row2);
Vec3 Row3 = v3 - v0;
float sqLength3 = length2(Row3);
//Compute the determinant of said matrix
const float determinant = Row1.x * (Row2.y * Row3.z - Row3.y * Row2.z)
- Row2.x * (Row1.y * Row3.z - Row3.y * Row1.z)
+ Row3.x * (Row1.y * Row2.z - Row2.y * Row1.z);
// Compute the volume of the tetrahedron, and precompute a scalar quantity for re-use in the formula
const float volume = determinant / 6.f;
const float iTwelveVolume = 1.f / (volume * 12.f);
center->x = v0.x + iTwelveVolume * ( ( Row2.y * Row3.z - Row3.y * Row2.z) * sqLength1 - (Row1.y * Row3.z - Row3.y * Row1.z) * sqLength2 + (Row1.y * Row2.z - Row2.y * Row1.z) * sqLength3 );
center->y = v0.y + iTwelveVolume * (-( Row2.x * Row3.z - Row3.x * Row2.z) * sqLength1 + (Row1.x * Row3.z - Row3.x * Row1.z) * sqLength2 - (Row1.x * Row2.z - Row2.x * Row1.z) * sqLength3 );
center->z = v0.z + iTwelveVolume * ( ( Row2.x * Row3.y - Row3.x * Row2.y) * sqLength1 - (Row1.x * Row3.y - Row3.x * Row1.y) * sqLength2 + (Row1.x * Row2.y - Row2.x * Row1.y) * sqLength3 );
//Once we know the center, the radius is clearly the distance to any vertex
*radius = length(*center - v0);
}