Si bien este es un hilo antiguo, pensé que sería bueno para la posteridad tener un poco de referencia. La fuente de la fórmula es de Herramientas geométricas para gráficos por computadora de Philip J. Schneider y David H. Eberly. Algo a tener en cuenta, según el texto.
El tetraedro V0, V1, V2, V3 se ordena de modo que sea isomorfo al canónico (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1 )
Según entiendo el isomorfismo , puede haber varios significados diferentes cuando se usa en geometría. Si quiere decir isomorfo con respecto a la teoría de grafos, entonces el siguiente código debería comportarse correctamente, ya que la topología de cualquier tetraedro es la misma (K4, un gráfico completo). I probaron los resultados de la función contra wolfram alpha utilizando diversas permutaciones en el orden de los vértices canónicas, y vi ninguna diferencia en el resultado. Si el orden demuestra ser un problema, sugiero examinar la normalidad del triángulo formado por los vértices V1, V2, V3 al ingresar a esta función, y tratar los puntos como un medio espacio con una prueba de producto de punto para descubrir si ese triángulo está orientado en la dirección correcta. Si no es así, un simplestd::swap
de cualquiera de los dos vértices del triángulo invertirá la dirección de lo normal y puede continuar. Pero como dije, no vi diferencia con varias permutaciones.
Aquí está el código traducido sin usar matrices para evitar confusiones de implementación, es bastante sencillo;
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);
}