Bu eski bir konu olsa da, gelecek nesiller için biraz referans vermenin iyi olabileceğini düşündüm. Formülün kaynağı Philip J. Schneider ve David H. Eberly'nin Bilgisayar Grafikleri için Geometrik Araçlar'dan alınmıştır . Metne göre dikkat edilmesi gereken bir şey
Tetrahedron V0, V1, V2, V3, kanonik olana (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1) izomorfik olacak şekilde sıralanır. ).
İzomorfizmi anladığım gibi , geometride kullanıldığında birkaç farklı anlam olabilir. Grafik teorisi ile ilgili izomorfik anlamına gelirse, herhangi bir tetrahedronun topolojisi aynı olduğu için aşağıdaki kod doğru davranmalıdır (K4, tam bir grafik). Ben volfram alfa karşı işlevinin sonuçlarını test kanonik köşe sıralamada çeşitli permütasyon kullanarak ve ben sonuçlar açısından fark gördük. Sıralamanın bir sorun olduğu kanıtlanırsa, bu fonksiyona girdikten sonra V1, V2, V3 köşelerinin oluşturduğu üçgenin normalini incelemenizi ve noktalara bir nokta-ürün testi ile noktaların bir nokta ürün testi ile muamele edilmesini öneriyorum. eğer o üçgen doğru yöne bakıyorsa. Değilse, basitstd::swap
üçgenin köşelerinden herhangi biri normalin yönünü tersine çevirir ve devam edebilirsiniz. Ama dediğim gibi, çeşitli permütasyonlarla hiçbir fark görmedim.
İşte herhangi bir uygulama karışıklığı önlemek için matrisler kullanmadan çevrilen kod, oldukça basittir;
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);
}