Meskipun ini adalah utas kuno, saya pikir mungkin baik bagi anak cucu untuk memiliki sedikit referensi. Sumber rumus adalah dari Geometric Tools for Computer Graphics oleh Philip J. Schneider dan David H. Eberly. Sesuatu yang perlu diperhatikan, menurut teks
Tetrahedron V0, V1, V2, V3 dipesan sehingga isomorfis dengan yang kanonik (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1 ).
Seperti yang saya pahami isomorfisme , bisa ada beberapa arti berbeda ketika digunakan dalam geometri. Jika ia berarti isomorfik berkaitan dengan teori grafik, maka kode berikut harus berperilaku dengan benar, karena topologi tetrahedron apa pun adalah sama (K4, grafik lengkap). Saya menguji hasil fungsi terhadap wolfram alpha menggunakan berbagai permutasi dalam pemesanan simpul kanonik, dan saya tidak melihat perbedaan dalam hasilnya. Jika pemesanan terbukti menjadi masalah, saya sarankan memeriksa normal segitiga yang dibentuk oleh simpul V1, V2, V3 pada input ke fungsi ini, dan memperlakukan titik-titik seperti setengah ruang dengan tes titik-produk untuk mencari tahu jika segitiga itu menghadap ke jalan yang benar. Jika tidak, sederhanastd::swap
dari setiap dua dari simpul segitiga akan membalikkan arah normal dan Anda dapat melanjutkan. Tapi seperti yang saya katakan, saya tidak melihat perbedaan dengan berbagai permutasi.
Berikut adalah kode yang diterjemahkan tanpa menggunakan matriks untuk menghindari kebingungan implementasi, ini cukup mudah;
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);
}