mirror of
https://github.com/CNCKitchen/stlTexturizer.git
synced 2026-04-07 22:11:32 +00:00
feat: update bucket threshold and enhance mesh info display in UI
This commit is contained in:
+5
-7
@@ -296,8 +296,8 @@
|
||||
<!-- Bucket threshold (shown when Fill is active) -->
|
||||
<div id="excl-threshold-row" class="form-row slider-row hidden">
|
||||
<label for="excl-threshold-slider" data-i18n="labels.maxAngle" data-i18n-title="tooltips.maxAngle" title="Maximum dihedral angle between adjacent triangles for the fill to cross">Max angle</label>
|
||||
<input type="range" id="excl-threshold-slider" min="0" max="180" step="1" value="30" />
|
||||
<input type="number" class="val" id="excl-threshold-val" value="30" min="0" max="180" step="1" />
|
||||
<input type="range" id="excl-threshold-slider" min="0" max="180" step="1" value="20" />
|
||||
<input type="number" class="val" id="excl-threshold-val" value="20" min="0" max="180" step="1" />
|
||||
</div>
|
||||
|
||||
<!-- Footer: count + clear -->
|
||||
@@ -345,11 +345,9 @@
|
||||
<button id="license-close" class="license-close-btn" aria-label="Close">×</button>
|
||||
<h2 id="license-title" data-i18n="license.title">License & Terms</h2>
|
||||
<ul class="license-list">
|
||||
<li data-i18n-html="license.item1">This tool is <strong>open-source</strong> — <a href="https://github.com/CNCKitchen/stlTexturizer" target="_blank" rel="noopener">view & contribute on GitHub</a>.</li>
|
||||
<li data-i18n-html="license.item2">Free to use for any purpose, including <strong>commercial work</strong> (e.g., texturing STLs for clients or products).</li>
|
||||
<li data-i18n-html="license.item3">Attribution is <strong>appreciated</strong> but <strong>not required</strong> when using this tool as-is.</li>
|
||||
<li data-i18n-html="license.item4">You may <strong>not</strong> sell or commercially redistribute this tool itself.</li>
|
||||
<li data-i18n-html="license.item5">Forks or derivative works must credit <strong>CNC Kitchen</strong> by name and link to <a href="https://cnckitchen.store" target="_blank" rel="noopener">cnckitchen.store</a>.</li>
|
||||
<li data-i18n-html="license.item1">Free to use for any purpose, including <strong>commercial work</strong> (e.g., texturing STLs for clients or products).</li>
|
||||
<li data-i18n-html="license.item2">Attribution is <strong>appreciated</strong> but <strong>not required</strong> when using this tool as-is.</li>
|
||||
<li data-i18n-html="license.item3">Want to support this tool and our work? Check out our <a href="https://geni.us/CNCStoreTexture" target="_blank" rel="noopener">online store</a>!</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
+8
-12
@@ -15,7 +15,7 @@ export const TRANSLATIONS = {
|
||||
// Viewport footer
|
||||
'ui.wireframe': 'Wireframe',
|
||||
'ui.controlsHint': 'Left drag: orbit \u00a0·\u00a0 Right drag: pan \u00a0·\u00a0 Scroll: zoom',
|
||||
'ui.meshInfo': '{n} triangles · {mb} MB',
|
||||
'ui.meshInfo': '{n} triangles · {mb} MB · {sx} × {sy} × {sz} mm',
|
||||
|
||||
// Load STL button
|
||||
'ui.loadStl': 'Load STL\u2026',
|
||||
@@ -127,11 +127,9 @@ export const TRANSLATIONS = {
|
||||
// License popup
|
||||
'license.btn': 'License & Terms',
|
||||
'license.title': 'License & Terms',
|
||||
'license.item1': 'This tool is <strong>open-source</strong> \u2014 <a href="https://github.com/CNCKitchen/stlTexturizer" target="_blank" rel="noopener">view & contribute on GitHub</a>.',
|
||||
'license.item2': 'Free to use for any purpose, including <strong>commercial work</strong> (e.g., texturing STLs for clients or products).',
|
||||
'license.item3': 'Attribution is <strong>appreciated</strong> but <strong>not required</strong> when using this tool as-is.',
|
||||
'license.item4': 'You may <strong>not</strong> sell or commercially redistribute this tool itself.',
|
||||
'license.item5': 'Forks or derivative works must credit <strong>CNC Kitchen</strong> by name and link to <a href="https://cnckitchen.store" target="_blank" rel="noopener">cnckitchen.store</a>.',
|
||||
'license.item1': 'Free to use for any purpose, including <strong>commercial work</strong> (e.g., texturing STLs for clients or products).',
|
||||
'license.item2': 'Attribution is <strong>appreciated</strong> but <strong>not required</strong> when using this tool as-is.',
|
||||
'license.item3': 'Want to support this tool and our work? Check out our <a href="https://geni.us/CNCStoreTexture" target="_blank" rel="noopener">online store</a>!',
|
||||
|
||||
// Sponsor modal
|
||||
'sponsor.title': 'Thanks for using CNC Kitchen STL Texturizer!',
|
||||
@@ -162,7 +160,7 @@ export const TRANSLATIONS = {
|
||||
// Viewport footer
|
||||
'ui.wireframe': 'Drahtgitter',
|
||||
'ui.controlsHint': 'Linke Maustaste: Drehen \u00a0·\u00a0 Rechte Maustaste: Verschieben \u00a0·\u00a0 Mausrad: Zoomen',
|
||||
'ui.meshInfo': '{n} Dreiecke · {mb} MB',
|
||||
'ui.meshInfo': '{n} Dreiecke · {mb} MB · {sx} × {sy} × {sz} mm',
|
||||
|
||||
// Load STL button
|
||||
'ui.loadStl': 'STL laden\u2026',
|
||||
@@ -274,11 +272,9 @@ export const TRANSLATIONS = {
|
||||
// License popup
|
||||
'license.btn': 'Lizenz & Nutzung',
|
||||
'license.title': 'Lizenz & Nutzungsbedingungen',
|
||||
'license.item1': 'Dieses Tool ist <strong>Open Source</strong> \u2014 <a href="https://github.com/CNCKitchen/stlTexturizer" target="_blank" rel="noopener">auf GitHub ansehen & beitragen</a>.',
|
||||
'license.item2': 'Kostenlos nutzbar f\u00fcr jeden Zweck, auch f\u00fcr <strong>kommerzielle Arbeit</strong> (z.B. Texturierung von STLs f\u00fcr Kunden oder Produkte).',
|
||||
'license.item3': 'Namensnennung wird <strong>gesch\u00e4tzt</strong>, ist aber bei der Nutzung dieses Tools <strong>nicht erforderlich</strong>.',
|
||||
'license.item4': 'Das Tool selbst darf <strong>nicht</strong> verkauft oder kommerziell weitervertrieben werden.',
|
||||
'license.item5': 'Forks oder abgeleitete Werke m\u00fcssen <strong>CNC Kitchen</strong> namentlich nennen und auf <a href="https://cnckitchen.store" target="_blank" rel="noopener">cnckitchen.store</a> verlinken.',
|
||||
'license.item1': 'Kostenlos nutzbar f\u00fcr jeden Zweck, auch f\u00fcr <strong>kommerzielle Arbeit</strong> (z.B. Texturierung von STLs f\u00fcr Kunden oder Produkte).',
|
||||
'license.item2': 'Namensnennung wird <strong>gesch\u00e4tzt</strong>, ist aber bei der Nutzung dieses Tools <strong>nicht erforderlich</strong>.',
|
||||
'license.item3': 'M\u00f6chtest du dieses Tool und unsere Arbeit unterst\u00fctzen? Schau in unserem <a href="https://geni.us/CNCStoreTexture" target="_blank" rel="noopener">Online-Shop</a> vorbei!',
|
||||
|
||||
// Sponsor modal
|
||||
'sponsor.title': 'Danke f\u00fcr die Nutzung des CNC Kitchen STL Texturizers!',
|
||||
|
||||
+10
-4
@@ -31,7 +31,7 @@ let exclusionTool = null; // 'brush' | 'bucket' | null
|
||||
let eraseMode = false;
|
||||
let brushIsRadius = false;
|
||||
let brushRadius = 5.0;
|
||||
let bucketThreshold = 30;
|
||||
let bucketThreshold = 20;
|
||||
let isPainting = false;
|
||||
let selectionMode = false; // false = exclude painted faces; true = include only painted faces
|
||||
let _lastHoverTriIdx = -1; // last triangle index used for hover preview
|
||||
@@ -415,7 +415,7 @@ function wireEvents() {
|
||||
_lastHoverTriIdx = -1; // invalidate hover so next mousemove re-computes
|
||||
});
|
||||
exclThresholdVal.addEventListener('change', () => {
|
||||
bucketThreshold = Math.max(0, Math.min(180, parseFloat(exclThresholdVal.value) || 30));
|
||||
bucketThreshold = Math.max(0, Math.min(180, parseFloat(exclThresholdVal.value) || 20));
|
||||
exclThresholdSlider.value = bucketThreshold;
|
||||
exclThresholdVal.value = bucketThreshold;
|
||||
_lastHoverTriIdx = -1;
|
||||
@@ -758,7 +758,10 @@ function loadDefaultCube() {
|
||||
|
||||
const triCount = getTriangleCount(geo);
|
||||
const mb = ((geo.attributes.position.array.byteLength) / 1024 / 1024).toFixed(2);
|
||||
meshInfo.textContent = t('ui.meshInfo', { n: triCount.toLocaleString(), mb });
|
||||
const sx = currentBounds.size.x.toFixed(2);
|
||||
const sy = currentBounds.size.y.toFixed(2);
|
||||
const sz = currentBounds.size.z.toFixed(2);
|
||||
meshInfo.textContent = t('ui.meshInfo', { n: triCount.toLocaleString(), mb, sx, sy, sz });
|
||||
|
||||
exportBtn.disabled = (activeMapEntry === null);
|
||||
updatePreview();
|
||||
@@ -838,7 +841,10 @@ async function handleSTL(file) {
|
||||
|
||||
const triCount = getTriangleCount(geometry);
|
||||
const mb = ((geometry.attributes.position.array.byteLength) / 1024 / 1024).toFixed(2);
|
||||
meshInfo.textContent = t('ui.meshInfo', { n: triCount.toLocaleString(), mb });
|
||||
const sx = bounds.size.x.toFixed(2);
|
||||
const sy = bounds.size.y.toFixed(2);
|
||||
const sz = bounds.size.z.toFixed(2);
|
||||
meshInfo.textContent = t('ui.meshInfo', { n: triCount.toLocaleString(), mb, sx, sy, sz });
|
||||
|
||||
exportBtn.disabled = (activeMapEntry === null);
|
||||
updatePreview();
|
||||
|
||||
+5
-10
@@ -24,17 +24,15 @@ function buildAxesIndicator(size) {
|
||||
const pts = [new THREE.Vector3(0, 0, 0), dir.clone().multiplyScalar(r * 0.78)];
|
||||
const line = new THREE.Line(
|
||||
new THREE.BufferGeometry().setFromPoints(pts),
|
||||
new THREE.LineBasicMaterial({ color: hex, depthTest: false, transparent: true, opacity: 0.9 }),
|
||||
new THREE.LineBasicMaterial({ color: hex, transparent: true, opacity: 0.9 }),
|
||||
);
|
||||
line.renderOrder = 999;
|
||||
group.add(line);
|
||||
|
||||
// Cone arrowhead
|
||||
const cone = new THREE.Mesh(
|
||||
new THREE.ConeGeometry(r * 0.07, r * 0.22, 8),
|
||||
new THREE.MeshBasicMaterial({ color: hex, depthTest: false }),
|
||||
new THREE.MeshBasicMaterial({ color: hex }),
|
||||
);
|
||||
cone.renderOrder = 999;
|
||||
cone.position.copy(dir.clone().multiplyScalar(r * 0.89));
|
||||
cone.quaternion.setFromUnitVectors(new THREE.Vector3(0, 1, 0), dir);
|
||||
group.add(cone);
|
||||
@@ -49,9 +47,8 @@ function buildAxesIndicator(size) {
|
||||
ctx.textBaseline = 'middle';
|
||||
ctx.fillText(label, 32, 32);
|
||||
const sprite = new THREE.Sprite(
|
||||
new THREE.SpriteMaterial({ map: new THREE.CanvasTexture(c), depthTest: false }),
|
||||
new THREE.SpriteMaterial({ map: new THREE.CanvasTexture(c) }),
|
||||
);
|
||||
sprite.renderOrder = 999;
|
||||
sprite.position.copy(dir.clone().multiplyScalar(r * 1.18));
|
||||
sprite.scale.set(r * 0.32, r * 0.32, 1);
|
||||
group.add(sprite);
|
||||
@@ -79,9 +76,8 @@ function buildDimensionLabel(text, hex, worldW, worldH) {
|
||||
ctx.fillText(text, 128, 32);
|
||||
const mesh = new THREE.Mesh(
|
||||
new THREE.PlaneGeometry(worldW, worldH),
|
||||
new THREE.MeshBasicMaterial({ map: new THREE.CanvasTexture(c), transparent: true, depthTest: false, side: THREE.DoubleSide }),
|
||||
new THREE.MeshBasicMaterial({ map: new THREE.CanvasTexture(c), transparent: true, side: THREE.DoubleSide }),
|
||||
);
|
||||
mesh.renderOrder = 998;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
@@ -98,9 +94,8 @@ function buildDimensions(box, groundZ, scale) {
|
||||
const addLine = (pts, hex) => {
|
||||
const line = new THREE.Line(
|
||||
new THREE.BufferGeometry().setFromPoints(pts),
|
||||
new THREE.LineBasicMaterial({ color: hex, depthTest: false, transparent: true, opacity: 0.75 }),
|
||||
new THREE.LineBasicMaterial({ color: hex, transparent: true, opacity: 0.75 }),
|
||||
);
|
||||
line.renderOrder = 997;
|
||||
group.add(line);
|
||||
};
|
||||
|
||||
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 60 KiB After Width: | Height: | Size: 182 KiB |
Reference in New Issue
Block a user