Obwohl dies ein uralter Thread ist, dachte ich, dass es für die Nachwelt schön sein könnte, ein bisschen zu referenzieren. Die Quelle der Formel stammt von Geometric Tools for Computer Graphics von Philip J. Schneider und David H. Eberly. Laut Text etwas zu beachten
Das Tetraeder V0, V1, V2, V3 ist so angeordnet, dass es isomorph zu dem kanonischen (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1) ist ).
Nach meinem Verständnis des Isomorphismus kann es in der Geometrie verschiedene Bedeutungen geben. Wenn er in Bezug auf die Graphentheorie isomorph bedeutet, sollte sich der folgende Code korrekt verhalten, da die Topologie eines Tetraeders dieselbe ist (K4, ein vollständiger Graph). Ich habe die Ergebnisse der Funktion gegen Wolfram Alpha unter Verwendung verschiedener Permutationen in der Reihenfolge der kanonischen Eckpunkte getestet und keinen Unterschied im Ergebnis festgestellt. Wenn sich die Reihenfolge als Problem herausstellt, schlage ich vor, die Normalen des Dreiecks, das durch die Eckpunkte V1, V2, V3 bei Eingabe dieser Funktion gebildet wird, zu untersuchen und die Punkte wie einen Halbraum mit einem Punktprodukttest zu behandeln, um dies herauszufinden wenn dieses Dreieck in die richtige Richtung zeigt. Wenn nicht, einfachstd::swap
von zwei beliebigen Eckpunkten des Dreiecks wird die Richtung der Normalen umgekehrt, und Sie können fortfahren. Aber wie gesagt, ich sah keinen Unterschied bei verschiedenen Permutationen.
Hier ist der übersetzte Code ohne Verwendung von Matrizen, um Implementierungsverwirrungen zu vermeiden. Er ist ziemlich einfach.
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);
}