mirror of
https://github.com/CNCKitchen/stlTexturizer.git
synced 2026-04-07 22:11:32 +00:00
feat: increase triangle safety cap to 20M and enhance progress reporting during subdivision
This commit is contained in:
+2
-2
@@ -328,11 +328,11 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="form-row slider-row">
|
<div class="form-row slider-row">
|
||||||
<label for="max-triangles" data-i18n="labels.outputTriangles" data-i18n-title="tooltips.outputTriangles" title="Mesh is fully subdivided first, then decimated down to this count">Output Triangles</label>
|
<label for="max-triangles" data-i18n="labels.outputTriangles" data-i18n-title="tooltips.outputTriangles" title="Mesh is fully subdivided first, then decimated down to this count">Output Triangles</label>
|
||||||
<input type="range" id="max-triangles" min="10000" max="10000000" step="10000" value="1000000" />
|
<input type="range" id="max-triangles" min="10000" max="20000000" step="10000" value="1000000" />
|
||||||
<span class="val" id="max-triangles-val">1.0 M</span>
|
<span class="val" id="max-triangles-val">1.0 M</span>
|
||||||
</div>
|
</div>
|
||||||
<div id="tri-limit-warning" class="tri-limit-warning hidden" data-i18n="warnings.safetyCapHit">
|
<div id="tri-limit-warning" class="tri-limit-warning hidden" data-i18n="warnings.safetyCapHit">
|
||||||
⚠ 10M-triangle safety cap hit during subdivision — result may still be coarser than requested edge length.
|
⚠ 20M-triangle safety cap hit during subdivision — result may still be coarser than requested edge length.
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div id="export-progress" class="export-progress hidden">
|
<div id="export-progress" class="export-progress hidden">
|
||||||
|
|||||||
+4
-2
@@ -120,11 +120,12 @@ export const TRANSLATIONS = {
|
|||||||
'tooltips.resolution': 'Edges longer than this value will be split during export',
|
'tooltips.resolution': 'Edges longer than this value will be split during export',
|
||||||
'labels.outputTriangles': 'Output Triangles',
|
'labels.outputTriangles': 'Output Triangles',
|
||||||
'tooltips.outputTriangles': 'Mesh is fully subdivided first, then decimated down to this count',
|
'tooltips.outputTriangles': 'Mesh is fully subdivided first, then decimated down to this count',
|
||||||
'warnings.safetyCapHit': '\u26a0 10M-triangle safety cap hit during subdivision \u2014 result may still be coarser than requested edge length.',
|
'warnings.safetyCapHit': '\u26a0 20M-triangle safety cap hit during subdivision \u2014 result may still be coarser than requested edge length.',
|
||||||
'ui.exportStl': 'Export STL',
|
'ui.exportStl': 'Export STL',
|
||||||
|
|
||||||
// Export progress stages
|
// Export progress stages
|
||||||
'progress.subdividing': 'Subdividing mesh\u2026',
|
'progress.subdividing': 'Subdividing mesh\u2026',
|
||||||
|
'progress.refining': 'Refining: {cur} triangles, longest edge {edge}',
|
||||||
'progress.applyingDisplacement': 'Applying displacement to {n} triangles\u2026',
|
'progress.applyingDisplacement': 'Applying displacement to {n} triangles\u2026',
|
||||||
'progress.displacingVertices': 'Displacing vertices\u2026',
|
'progress.displacingVertices': 'Displacing vertices\u2026',
|
||||||
'progress.decimatingTo': 'Simplifying {from} \u2192 {to} triangles\u2026',
|
'progress.decimatingTo': 'Simplifying {from} \u2192 {to} triangles\u2026',
|
||||||
@@ -278,11 +279,12 @@ export const TRANSLATIONS = {
|
|||||||
'tooltips.resolution': 'Kanten l\u00e4nger als dieser Wert werden beim Export unterteilt',
|
'tooltips.resolution': 'Kanten l\u00e4nger als dieser Wert werden beim Export unterteilt',
|
||||||
'labels.outputTriangles': 'Max Dreiecke',
|
'labels.outputTriangles': 'Max Dreiecke',
|
||||||
'tooltips.outputTriangles': 'Das Netz wird zuerst vollst\u00e4ndig unterteilt, dann auf diese Anzahl dezimiert',
|
'tooltips.outputTriangles': 'Das Netz wird zuerst vollst\u00e4ndig unterteilt, dann auf diese Anzahl dezimiert',
|
||||||
'warnings.safetyCapHit': '\u26a0 10-Mio.-Dreiecke-Sicherheitsgrenze bei der Unterteilung erreicht \u2014 Ergebnis kann gr\u00f6ber als gew\u00fcnschte Kantenl\u00e4nge sein.',
|
'warnings.safetyCapHit': '\u26a0 20-Mio.-Dreiecke-Sicherheitsgrenze bei der Unterteilung erreicht \u2014 Ergebnis kann gr\u00f6ber als gew\u00fcnschte Kantenl\u00e4nge sein.',
|
||||||
'ui.exportStl': 'STL exportieren',
|
'ui.exportStl': 'STL exportieren',
|
||||||
|
|
||||||
// Export progress stages
|
// Export progress stages
|
||||||
'progress.subdividing': 'Netz wird verfeinert\u2026',
|
'progress.subdividing': 'Netz wird verfeinert\u2026',
|
||||||
|
'progress.refining': 'Verfeinern: {cur} Dreiecke, l\u00e4ngste Kante {edge}',
|
||||||
'progress.applyingDisplacement': 'Textur auf {n} Dreiecke anwenden\u2026',
|
'progress.applyingDisplacement': 'Textur auf {n} Dreiecke anwenden\u2026',
|
||||||
'progress.displacingVertices': 'Punkte werden verschoben\u2026',
|
'progress.displacingVertices': 'Punkte werden verschoben\u2026',
|
||||||
'progress.decimatingTo': '{from} \u2192 {to} Dreiecke vereinfachen\u2026',
|
'progress.decimatingTo': '{from} \u2192 {to} Dreiecke vereinfachen\u2026',
|
||||||
|
|||||||
+6
-1
@@ -1701,7 +1701,12 @@ async function handleExport() {
|
|||||||
|
|
||||||
const { geometry: subdivided, safetyCapHit } = await subdivide(
|
const { geometry: subdivided, safetyCapHit } = await subdivide(
|
||||||
currentGeometry, settings.refineLength,
|
currentGeometry, settings.refineLength,
|
||||||
(p) => setProgress(0.02 + p * 0.35, t('progress.subdividing')),
|
(p, triCount, longestEdge) => {
|
||||||
|
const label = triCount != null
|
||||||
|
? t('progress.refining', { cur: triCount.toLocaleString(), edge: longestEdge.toFixed(2) })
|
||||||
|
: t('progress.subdividing');
|
||||||
|
setProgress(0.02 + p * 0.35, label);
|
||||||
|
},
|
||||||
faceWeights
|
faceWeights
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
+16
-2
@@ -15,7 +15,7 @@
|
|||||||
import * as THREE from 'three';
|
import * as THREE from 'three';
|
||||||
|
|
||||||
const QUANTISE = 1e4;
|
const QUANTISE = 1e4;
|
||||||
const SAFETY_CAP = 10_000_000; // absolute OOM guard
|
const SAFETY_CAP = 20_000_000; // absolute OOM guard
|
||||||
|
|
||||||
// ── Public entry point ───────────────────────────────────────────────────────
|
// ── Public entry point ───────────────────────────────────────────────────────
|
||||||
|
|
||||||
@@ -59,6 +59,19 @@ export async function subdivide(geometry, maxEdgeLength, onProgress, faceWeights
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Find longest edge for progress reporting
|
||||||
|
let maxEdgeLenSq = 0;
|
||||||
|
for (let t = 0; t < currentIndices.length; t += 3) {
|
||||||
|
const a = currentIndices[t], b = currentIndices[t + 1], c = currentIndices[t + 2];
|
||||||
|
const ab = edgeLenSq(positions, a, b);
|
||||||
|
const bc = edgeLenSq(positions, b, c);
|
||||||
|
const ca = edgeLenSq(positions, c, a);
|
||||||
|
if (ab > maxEdgeLenSq) maxEdgeLenSq = ab;
|
||||||
|
if (bc > maxEdgeLenSq) maxEdgeLenSq = bc;
|
||||||
|
if (ca > maxEdgeLenSq) maxEdgeLenSq = ca;
|
||||||
|
}
|
||||||
|
const longestEdge = Math.sqrt(maxEdgeLenSq);
|
||||||
|
|
||||||
const { newIndices, newFaceExcluded, newFaceParentId, changed } = subdividePass(
|
const { newIndices, newFaceExcluded, newFaceParentId, changed } = subdividePass(
|
||||||
positions, normals, weights, currentIndices, maxEdgeLength, SAFETY_CAP, currentFaceExcluded,
|
positions, normals, weights, currentIndices, maxEdgeLength, SAFETY_CAP, currentFaceExcluded,
|
||||||
canonIdx, posCanonMap, currentFaceParentId
|
canonIdx, posCanonMap, currentFaceParentId
|
||||||
@@ -69,7 +82,8 @@ export async function subdivide(geometry, maxEdgeLength, onProgress, faceWeights
|
|||||||
|
|
||||||
if (newIndices.length / 3 >= SAFETY_CAP) safetyCapHit = true;
|
if (newIndices.length / 3 >= SAFETY_CAP) safetyCapHit = true;
|
||||||
|
|
||||||
if (onProgress) onProgress(Math.min(0.95, (iter + 1) / maxIterations));
|
const newTriCount = newIndices.length / 3;
|
||||||
|
if (onProgress) onProgress(Math.min(0.95, (iter + 1) / maxIterations), newTriCount, longestEdge);
|
||||||
await new Promise(r => setTimeout(r, 0));
|
await new Promise(r => setTimeout(r, 0));
|
||||||
if (!changed || safetyCapHit) break;
|
if (!changed || safetyCapHit) break;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user