@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
106 lines (79 loc) • 2.87 kB
JavaScript
import { array_copy } from "../../../collection/array/array_copy.js";
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;
}
array_copy(n12, 0, A, 0, 3);
array_copy(n13, 0, A, 3, 3);
array_copy(n14, 0, A, 6, 3);
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;
}
}