これは古代のスレッドですが、後世に少し参考にしておくとよいと思いました。公式の出典は、Philip J. SchneiderおよびDavid H. EberlyによるGeometric Tools for Computer Graphicsによるものです。本文によると注意すべきこと
四面体V0、V1、V2、V3は、正準1(0、0、0)、(1、0、0)、(0、1、0)、(0、0、1 )。
私が理解しているように同型、ジオメトリで使用する場合、いくつかの異なる意味がある可能性があります。彼がグラフ理論に関して同型であることを意味する場合、四面体のトポロジはすべて同じであるため、次のコードは正しく動作するはずです(K4、完全なグラフ)。正規頂点の順序でさまざまな順列を使用して、wolfram alphaに対する関数の結果をテストしましたが、結果に違いはありませんでした。順序付けが問題であることがわかった場合は、この関数への入力時に頂点V1、V2、V3によって形成される三角形の法線を調べ、点積テストで点を半空間のように扱って理解することをお勧めしますその三角形が正しい方向を向いている場合。そうでない場合、単純なstd::swap
三角形の頂点のいずれか2つを指定すると、法線の方向が反転し、続行できます。しかし、私が言ったように、私はさまざまな順列との違いを見なかった。
以下は、実装の混乱を避けるために行列を使用せずに翻訳したコードです。これはかなり簡単です。
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);
}