MCPcopy Create free account
hub / github.com/CNCKitchen/stlTexturizer / decimate

Function decimate

js/decimation.js:106–264  ·  view source on GitHub ↗
(geometry, targetTriangles, onProgress, harvestFlat = true, harvestTol = DEFAULT_HARVEST_TOL)

Source from the content-addressed store, hash-verified

104function _shouldYield() {
105 const now = performance.now();
106 if (now - _lastYieldTime < 100) return false;
107 _lastYieldTime = now;
108 return true;
109}
110function _yieldFrame() {
111 return new Promise(r => setTimeout(r, 0));
112}
113
114// ── Public API ───────────────────────────────────────────────────────────────
115
116export async function decimate(geometry, targetTriangles, onProgress, harvestFlat = true, harvestTol = DEFAULT_HARVEST_TOL, lockedFaces = null) {
117 const { positions, faces, vertCount, faceCount } = buildIndexed(geometry);
118
119 // Already at/under the target: nothing to decimate. But if harvesting is on we
120 // still run — there may be flat faces collapsible for free even below the limit.
121 if (faceCount <= targetTriangles && !harvestFlat) return buildOutput(positions, faces, faceCount);
122
123 // Preserve-untextured (beta): a vertex touching any locked (untextured) face
124 // may neither move nor be removed, so edges with a locked endpoint are never
125 // pushed onto the heap. This also pins the textured/untextured boundary ring,
126 // so no T-junctions can open against the locked region. lockedFaces uses the
127 // same face order as the non-indexed input geometry.
128 let lockedVert = null;
129 let lockedFaceCount = 0;
130 if (lockedFaces) {
131 lockedVert = new Uint8Array(vertCount);
132 for (let f = 0; f < faceCount; f++) {
133 if (!lockedFaces[f]) continue;
134 lockedFaceCount++;
135 lockedVert[faces[f * 3]] = 1;
136 lockedVert[faces[f * 3 + 1]] = 1;
137 lockedVert[faces[f * 3 + 2]] = 1;
138 }
139 }
140 // When the locked faces alone meet or exceed the triangle target, the target
141 // is unreachable without touching untextured geometry. Chasing it anyway
142 // would grind the textured region down to its guard limit, so instead drop
143 // straight to error-bounded harvesting (or bail entirely when harvesting is
144 // off) and flag the overrun so the caller can warn the user.
145 const lockedOverBudget = lockedVert !== null && faceCount > targetTriangles
146 && lockedFaceCount >= targetTriangles;
147 if (lockedOverBudget && !harvestFlat) {
148 if (onProgress) onProgress(1);
149 const out = buildOutput(positions, faces, faceCount);
150 out.userData.lockedOverBudget = true;
151 return out;
152 }
153
154 // Per-vertex error quadrics (10 doubles = upper triangle of symmetric 4×4)
155 const quadrics = new Float64Array(vertCount * 10);
156 initQuadrics(quadrics, positions, faces, faceCount);
157 addCreaseQuadrics(quadrics, positions, faces, faceCount);
158
159 // Doubly-linked vertex-face incidence (typed arrays — faster than Set<number>)
160 const { vfHead, slotFace, slotVert, slotNext, slotPrev, faceSlot } =
161 buildLinkedAdj(faces, faceCount, vertCount);
162
163 const active = new Uint8Array(vertCount).fill(1);

Callers 4

diag-cube.mjsFile · 0.90
runCaseFunction · 0.90
diag-pipeline.mjsFile · 0.90
runExportPipelineFunction · 0.90

Calls 15

getOrSetMethod · 0.95
sizeMethod · 0.95
popMethod · 0.95
getCostMethod · 0.95
getV1Method · 0.95
getV2Method · 0.95
getVer1Method · 0.95
getVer2Method · 0.95
getPxMethod · 0.95
getPyMethod · 0.95
getPzMethod · 0.95
buildIndexedFunction · 0.85

Tested by

no test coverage detected