@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
108 lines (81 loc) • 3.06 kB
JavaScript
import { solve_linear_system } from "../../../math/linalg/solve_linear_system.js";
import { v3_dot } from "../../vec3/v3_dot.js";
const MAX_FLOAT32 = 3.4028234663852886e+38;
const n12 = new Float64Array(3);
const n13 = new Float64Array(3);
const n14 = new Float64Array(3);
const x12 = new Float64Array(3);
const x13 = new Float64Array(3);
const x14 = new Float64Array(3);
const A = new Float64Array(9);
const rhs = new Float64Array(3);
/**
* Compute the circumcenter (center[3]) and radius squared (method return value) of a tetrahedron defined by the four points x1, x2, x3, and x4.
*
* @see https://github.com/Kitware/VTK/blob/ac3fd8005bce7b3da4423c305f61ffd9df9695ef/Common/DataModel/vtkTetra.cxx
* @param {number[]} result [center_x, center_y, center_z, radius_squared]
* @param {number[]} points
* @param {number} a
* @param {number} b
* @param {number} c
* @param {number} d
*/
export function tetrahedron_compute_circumsphere(
result,
points,
a, b, c, d
) {
// calculate normals and intersection points of bisecting planes.
for (let i = 0; i < 3; i++) {
const v_a = points[a * 3 + i];
const v_b = points[b * 3 + i];
const v_c = points[c * 3 + i];
const v_d = points[d * 3 + i];
n12[i] = v_b - v_a;
n13[i] = v_c - v_a;
n14[i] = v_d - v_a;
x12[i] = (v_b + v_a) * 0.5;
x13[i] = (v_c + v_a) * 0.5;
x14[i] = (v_d + v_a) * 0.5;
}
// Pack A column-major (solve_linear_system expects column-major). The
// math matrix rows are n12, n13, n14, so column j of A holds the j-th
// component of each normal: [n12[j], n13[j], n14[j]].
A[0] = n12[0]; A[1] = n13[0]; A[2] = n14[0];
A[3] = n12[1]; A[4] = n13[1]; A[5] = n14[1];
A[6] = n12[2]; A[7] = n13[2]; A[8] = n14[2];
rhs[0] = v3_dot(n12[0], n12[1], n12[2], x12[0], x12[1], x12[2]);
rhs[1] = v3_dot(n13[0], n13[1], n13[2], x13[0], x13[1], x13[2]);
rhs[2] = v3_dot(n14[0], n14[1], n14[2], x14[0], x14[1], x14[2]);
// Solve system of equations
if (solve_linear_system(A, rhs, 3) === false) {
// failed to solve, fall-back to infinitely-sized sphere centered around origin
result[0] = result[1] = result[2] = 0;
result[3] = MAX_FLOAT32;
return;
} else {
result[0] = rhs[0];
result[1] = rhs[1];
result[2] = rhs[2];
}
let sum = 0;
let diff;
for (let i = 0; i < 3; i++) {
const rhs_offset = rhs[i];
diff = points[a * 3 + i] - rhs_offset;
sum += diff * diff;
diff = points[b * 3 + i] - rhs_offset;
sum += diff * diff;
diff = points[c * 3 + i] - rhs_offset;
sum += diff * diff;
diff = points[d * 3 + i] - rhs_offset;
sum += diff * diff;
}
// divide
sum *= 0.25;
if (sum >= MAX_FLOAT32) {
result[3] = MAX_FLOAT32;
} else {
result[3] = sum;
}
}