Mặc dù đây là một chủ đề cổ xưa, tôi nghĩ rằng nó có thể tốt cho hậu thế có một chút để tham khảo. Nguồn gốc của công thức là từ Công cụ hình học cho đồ họa máy tính của Philip J. Schneider và David H. Eberly. Một số điều cần lưu ý, theo văn bản
Các tứ diện V0, V1, V2, V3 được sắp xếp sao cho nó đồng hình với chính tắc (0, 0, 0), (1, 0, 0), (0, 1, 0), (0, 0, 1 ).
Theo tôi hiểu đẳng cấu , có thể có một số ý nghĩa khác nhau khi được sử dụng trong hình học. Nếu anh ta có nghĩa là đẳng cấu đối với lý thuyết đồ thị, thì đoạn mã sau sẽ hành xử đúng, vì cấu trúc liên kết của bất kỳ khối tứ diện nào đều giống nhau (K4, một đồ thị hoàn chỉnh). Tôi đã kiểm tra kết quả của hàm chống lại wolfram alpha bằng nhiều hoán vị khác nhau theo thứ tự các đỉnh chính tắc, và tôi thấy không có sự khác biệt nào trong kết quả. Nếu thứ tự chứng tỏ là một vấn đề, tôi khuyên bạn nên kiểm tra mức bình thường của tam giác được hình thành bởi các đỉnh V1, V2, V3 khi nhập vào hàm này và xử lý các điểm như nửa không gian bằng phép thử sản phẩm chấm để tìm ra nếu tam giác đó đang đối mặt đúng cách. Nếu không, đơn giảnstd::swap
bất kỳ hai trong số các đỉnh của tam giác sẽ đảo ngược hướng của bình thường và bạn có thể tiếp tục. Nhưng như tôi đã nói, tôi thấy không có sự khác biệt với các hoán vị khác nhau.
Đây là mã được dịch mà không sử dụng ma trận để tránh bất kỳ sự nhầm lẫn nào khi thực hiện, nó khá đơn giản;
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);
}