mirror of
https://github.com/CNCKitchen/stlTexturizer.git
synced 2026-04-07 22:11:32 +00:00
perf: replace string-key maps with numeric flat arrays in hot paths
Displacement, subdivision and exclusion all used template-string keys for vertex dedup and edge lookup maps. Replaced with a single numeric dedup pass + flat typed arrays (Float64Array / Uint8Array), cutting displacement time by ~2.5x and subdivision by ~2.4x on a 68k tri STL. - displacement.js: vertex dedup → flat arrays for smooth normals, zone areas, masked fractions, displacement cache, excluded set - subdivision.js: numeric edge keys (a*maxV+b) instead of template strings - exclusion.js: numeric edge keys, BFS queue.shift() → index pointer, adjacency Map → Array, TypedArray.set() for overlay copy - mapping.js: Math.pow(x,4) → x²·x², cos/sin cached per computeUV call, applyTransform signature changed to accept precomputed cos/sin
This commit is contained in:
+10
-8
@@ -119,13 +119,17 @@ export async function subdivide(geometry, maxEdgeLength, onProgress, faceWeights
|
||||
function subdividePass(positions, normals, weights, indices, maxEdgeLength, safetyCap, faceExcluded = null, canonIdx = null, posCanonMap = null, faceParentId = null) {
|
||||
const maxSq = maxEdgeLength * maxEdgeLength;
|
||||
const midCache = new Map();
|
||||
midCache._maxV = positions.length / 3; // set before any getMidpoint calls
|
||||
|
||||
// When canonIdx is available (accurate/export mode), use position-canonical
|
||||
// edge keys so split-vertex faces on both sides of a sharp edge see the same
|
||||
// split decision. Otherwise (fast/preview mode) use simple index-based keys.
|
||||
// NOTE: _maxV is computed once at pass start. During the pass, positions grows
|
||||
// via getMidpoint, but splitEdges and midCache only use indices < _maxV.
|
||||
const _maxV = positions.length / 3;
|
||||
const _edgeKey = canonIdx
|
||||
? (a, b) => { const ca = canonIdx[a], cb = canonIdx[b]; return ca < cb ? `${ca}:${cb}` : `${cb}:${ca}`; }
|
||||
: (a, b) => a < b ? `${a}:${b}` : `${b}:${a}`;
|
||||
? (a, b) => { const ca = canonIdx[a], cb = canonIdx[b]; return ca < cb ? ca * _maxV + cb : cb * _maxV + ca; }
|
||||
: (a, b) => a < b ? a * _maxV + b : b * _maxV + a;
|
||||
|
||||
// ── Step 1: globally mark edges that need splitting ─────────────────────
|
||||
// Excluded triangles do NOT proactively mark their own edges – their
|
||||
@@ -264,11 +268,6 @@ function subdividePass(positions, normals, weights, indices, maxEdgeLength, safe
|
||||
|
||||
// ── Helpers ──────────────────────────────────────────────────────────────────
|
||||
|
||||
/** Canonical order key for an undirected edge – matches the getMidpoint cache key. */
|
||||
function edgeKey(a, b) {
|
||||
return a < b ? `${a}:${b}` : `${b}:${a}`;
|
||||
}
|
||||
|
||||
function edgeLenSq(pos, a, b) {
|
||||
const dx = pos[a*3] - pos[b*3];
|
||||
const dy = pos[a*3+1] - pos[b*3+1];
|
||||
@@ -277,7 +276,10 @@ function edgeLenSq(pos, a, b) {
|
||||
}
|
||||
|
||||
function getMidpoint(positions, normals, weights, cache, a, b, canonIdx, posCanonMap) {
|
||||
const key = a < b ? `${a}:${b}` : `${b}:${a}`;
|
||||
// Numeric edge key: uses _maxV set on the cache by subdividePass at pass start.
|
||||
// All lookups use indices < _maxV, so this is safe even as positions grows.
|
||||
const _mv = cache._maxV;
|
||||
const key = a < b ? a * _mv + b : b * _mv + a;
|
||||
if (cache.has(key)) return cache.get(key);
|
||||
|
||||
// Midpoint position
|
||||
|
||||
Reference in New Issue
Block a user