@woosh/meep-engine
Version:
Pure JavaScript game engine. Fully featured and production ready.
109 lines (85 loc) • 2.72 kB
JavaScript
import { EPSILON } from "../../../math/EPSILON.js";
import { epsilonEquals } from "../../../math/epsilonEquals.js";
import v3_morton_encode from "../morton/v3_morton_encode.js";
/**
*
* @param {TopoVertex} a
* @param {TopoVertex} b
* @param {number} tolerance
*/
function isPositionEquivalent(a, b, tolerance) {
return epsilonEquals(b.x, a.x, tolerance)
&& epsilonEquals(b.y, a.y, tolerance)
&& epsilonEquals(b.z, a.z, tolerance)
;
}
/**
*
* @param {Map<TopoVertex,TopoVertex[]>} result
* @param {TopoVertex} a
* @param {TopoVertex} b
*/
function recordDuplicate(result, a, b) {
let vertices = result.get(a);
if (vertices === undefined) {
vertices = [];
result.set(a, vertices);
}
vertices.push(b);
}
/**
*
* @param {TopoMesh} mesh
* @param {AABB3} aabb
* @param {number} tolerance
* @returns {Map<TopoVertex, TopoVertex[]>}
*/
export function computeTopoMeshVertexDuplicates(mesh, aabb, tolerance = EPSILON) {
const vertices = mesh.vertices;
const n = vertices.length;
// build spatial index for faster duplicate search
const spatial_hash = [];
/**
*
* @type {Map<TopoVertex, TopoVertex[]>}
*/
const result = new Map();
let i, j;
const x0 = aabb.x0;
const y0 = aabb.y0;
const z0 = aabb.z0;
// 10 bit quantization
const e_x = 1023 / aabb.getExtentsX();
const e_y = 1023 / aabb.getExtentsY();
const e_z = 1023 / aabb.getExtentsZ();
//
for (i = 0; i < n; i++) {
const vertex_a = vertices[i];
const morton_code = v3_morton_encode(
Math.round((vertex_a.x - x0) * e_x),
Math.round((vertex_a.y - y0) * e_y),
Math.round((vertex_a.z - z0) * e_z)
);
let spatial_bucket = spatial_hash[morton_code];
if (spatial_bucket === undefined) {
spatial_bucket = [];
spatial_hash[morton_code] = spatial_bucket;
} else {
// look at others in the bucket
const bucket_size = spatial_bucket.length;
for (j = 0; j < bucket_size; j++) {
/**
* @type {TopoVertex}
*/
const vertex_b = spatial_bucket[j];
if (isPositionEquivalent(vertex_a, vertex_b, tolerance)) {
// same coordinates
recordDuplicate(result, vertex_a, vertex_b);
recordDuplicate(result, vertex_b, vertex_a);
}
}
}
spatial_bucket.push(vertex_a);
}
return result;
}