能用prusa切片和预览了,添加了缺失的翻译

Co-authored-by: Copilot <copilot@github.com>
This commit is contained in:
2026-04-24 01:51:08 +08:00
parent 22a6493e24
commit 366372da6e
15 changed files with 394 additions and 38 deletions

View File

@@ -66,8 +66,25 @@ document.addEventListener('DOMContentLoaded', async function() {
'SKIRT': new THREE.Color(0x00ffff),
'SUPPORT-INTERFACE': new THREE.Color(0x2b6b2b),
'TRAVEL': new THREE.Color(0x405060),
'DEFAULT': new THREE.Color(0xaaaaaa),
'DEFAULT': new THREE.Color(0xaaaaaa)
};
// Additional aliases mapped to basic COLORS
const COLOR_ALIASES = {
'External perimeter': COLORS['WALL-OUTER'],
'Overhang perimeter': COLORS['WALL-OUTER'],
'Perimeter': COLORS['WALL-INNER'],
'Internal infill': COLORS['FILL'],
'Solid infill': COLORS['FILL'],
'Top solid infill': COLORS['FILL'],
'Bridge infill': COLORS['FILL'],
'Support material': COLORS['SUPPORT'],
'Skirt/Brim': COLORS['SKIRT'],
'Support material interface': COLORS['SUPPORT-INTERFACE']
};
// Merge aliases into COLORS
Object.assign(COLORS, COLOR_ALIASES);
// Inject printer machine dimensions via Jinja
const bedWidth = {{ machine_width | default(220) }};
@@ -83,6 +100,23 @@ document.addEventListener('DOMContentLoaded', async function() {
'SKIRT': 7, 'SUPPORT-INTERFACE': 8
};
// Aliases for TYPE_INDEX
const TYPE_INDEX_ALIASES = {
'External perimeter': 1,
'Overhang perimeter': 1,
'Perimeter': 2,
'Internal infill': 3,
'Solid infill': 3,
'Top solid infill': 3,
'Bridge infill': 3,
'Support material': 5,
'Skirt/Brim': 7,
'Support material interface': 8
};
// Merge aliases into TYPE_INDEX
Object.assign(TYPE_INDEX, TYPE_INDEX_ALIASES);
let layers = [];
let scene, camera, renderer, controls;
let group = new THREE.Group();
@@ -159,6 +193,21 @@ document.addEventListener('DOMContentLoaded', async function() {
'SUPPORT-INTERFACE': 'uShowSupportInterface',
'TRAVEL': 'uShowTravel'
};
const uniformMapAliases = {
'External perimeter': 'uShowOuter',
'Overhang perimeter': 'uShowOuter',
'Perimeter': 'uShowInner',
'Internal infill': 'uShowInfill',
'Solid infill': 'uShowInfill',
'Top solid infill': 'uShowInfill',
'Bridge infill': 'uShowInfill',
'Support material': 'uShowSupport',
'Skirt/Brim': 'uShowSkirt',
'Support material interface': 'uShowSupportInterface'
};
Object.assign(uniformMap, uniformMapAliases);
document.querySelectorAll('.legend-item').forEach(el => {
el.addEventListener('click', function() {
@@ -292,16 +341,29 @@ document.addEventListener('DOMContentLoaded', async function() {
}
for (let i = 0; i < lines.length; i++) {
let chunk = lines[i].trim().toUpperCase();
let chunk = lines[i].trim();
if (!chunk) continue;
let upperChunk = chunk.toUpperCase();
if (chunk.startsWith(';LAYER:')) {
if (upperChunk.startsWith(';LAYER:')) {
flushLayer();
} else if (chunk.startsWith(';TYPE:')) {
} else if (upperChunk.startsWith(';TYPE:')) {
currentTypeStr = chunk.substring(6).trim();
} else if (chunk.startsWith('G0') || chunk.startsWith('G1')) {
} else if (upperChunk.startsWith(';') && chunk.includes(' perimeter')) {
// Heuristics for Prusa/Slic3r specific comments like `; External perimeter`
currentTypeStr = chunk.substring(1).trim();
} else if (upperChunk.startsWith(';') && chunk.includes(' infill')) {
// Heuristics for Prusa/Slic3r specific comments like `; Internal infill`
currentTypeStr = chunk.substring(1).trim();
} else if (upperChunk.startsWith(';') && chunk.includes(' material')) {
// Support material
currentTypeStr = chunk.substring(1).trim();
} else if (upperChunk.startsWith(';') && chunk.includes('Skirt/Brim')) {
// Skirt/Brim
currentTypeStr = 'Skirt/Brim';
} else if (upperChunk.startsWith('G0') || upperChunk.startsWith('G1')) {
let next = { x: current.x, y: current.y, z: current.z, e: current.e };
let parts = chunk.split(/\s+/);
let parts = upperChunk.split(/\s+/);
let hasMove = false;
for (let p of parts) {
@@ -314,11 +376,17 @@ document.addEventListener('DOMContentLoaded', async function() {
if (hasMove && !isNaN(next.x) && !isNaN(next.y) && !isNaN(next.z)) {
let isExtrude = (next.e > current.e);
// Cura uses G0 for travel generally
if (chunk.startsWith('G0') && !chunk.includes('E')) isExtrude = false;
if (upperChunk.startsWith('G0') && !upperChunk.includes('E')) isExtrude = false;
let activeType = isExtrude ? currentTypeStr : 'TRAVEL';
let col = COLORS[activeType] || COLORS['DEFAULT'];
let tIdx = TYPE_INDEX[activeType] !== undefined ? TYPE_INDEX[activeType] : TYPE_INDEX['DEFAULT'];
// Special case for default aliases like "; External perimeter" which we stored in currentTypeStr
let resolvedType = activeType;
if (isExtrude && Object.keys(COLOR_ALIASES).includes(activeType)) {
resolvedType = activeType;
}
let col = COLORS[resolvedType] || COLORS['DEFAULT'];
let tIdx = TYPE_INDEX[resolvedType] !== undefined ? TYPE_INDEX[resolvedType] : TYPE_INDEX['DEFAULT'];
if (isExtrude) {
let dx = next.x - current.x;

View File

@@ -101,6 +101,20 @@
</div>
</div>
<div class="card shadow-sm flex-shrink-0 mb-3">
<div class="card-header bg-light fw-bold text-secondary d-flex justify-content-between align-items-center collapsed" style="cursor: pointer;" data-bs-toggle="collapse" data-bs-target="#collapseMaterial" aria-expanded="false">
<span><i class="bi bi-box me-2"></i>{{ _('Material Profile') }}</span>
<i class="bi bi-chevron-bar-contract"></i>
</div>
<div id="collapseMaterial" class="collapse" data-bs-parent="#platerSidebarAccordion">
<div class="card-body">
<div class="mb-3">
<select class="form-select bg-light" id="material" data-selected="{{ last_material }}"></select>
</div>
</div>
</div>
</div>
<div class="card shadow-sm flex-shrink-0 mb-3">
<div class="card-header bg-light fw-bold text-secondary d-flex justify-content-between align-items-center collapsed" style="cursor: pointer;" data-bs-toggle="collapse" data-bs-target="#collapseQuality" aria-expanded="false">
<span><i class="bi bi-gear-wide-connected me-2"></i>{{ _('Quality Profile') }}</span>
@@ -679,6 +693,11 @@ function addModelToPlate(btnElement, fileId, url, name, status) {
qSelect.setAttribute('data-selected', data.settings.quality);
qSelect.value = data.settings.quality;
}
if (data.settings.material) {
const mSelect = document.getElementById('material');
mSelect.setAttribute('data-selected', data.settings.material);
mSelect.value = data.settings.material;
}
}
} catch (e) {}
}
@@ -882,6 +901,7 @@ function mergeAndSlice() {
});
const quality = document.getElementById('quality').value;
const material = document.getElementById('material').value;
const infill = document.getElementById('infill-density').value;
const support = document.getElementById('support-type').value;
const supportPattern = document.getElementById('support-pattern').value;
@@ -900,7 +920,7 @@ function mergeAndSlice() {
headers: {
'Content-Type': 'application/json'
},
body: JSON.stringify({ pieces: pieces, quality: quality, infill: infill, support: support, support_pattern: supportPattern, is_edit: isEdit, target_file_id: targetFileId })
body: JSON.stringify({ pieces: pieces, quality: quality, material: material, infill: infill, support: support, support_pattern: supportPattern, is_edit: isEdit, target_file_id: targetFileId })
})
.then(response => response.json())
.then(data => {
@@ -959,6 +979,7 @@ document.addEventListener('DOMContentLoaded', () => {
const engine = "{{ configs.get('slicer_engine', 'cura') }}";
const qualitySelect = document.getElementById('quality');
const patternSelect = document.getElementById('support-pattern');
const materialSelect = document.getElementById('material');
fetch(`/api/engine_options/${engine}`)
.then(res => res.json())
@@ -972,6 +993,20 @@ document.addEventListener('DOMContentLoaded', () => {
});
if(selQ) qualitySelect.value = selQ;
const selM = materialSelect.getAttribute('data-selected');
materialSelect.innerHTML = '';
const emptyOpt = document.createElement('option');
emptyOpt.value = ''; emptyOpt.textContent = "{{ _('Auto / Default') }}";
materialSelect.appendChild(emptyOpt);
if(data.materials) {
data.materials.forEach(p => {
const opt = document.createElement('option');
opt.value = p.id; opt.textContent = p.name;
materialSelect.appendChild(opt);
});
}
if(selM) materialSelect.value = selM;
const selP = patternSelect.getAttribute('data-selected');
patternSelect.innerHTML = '';
data.support_patterns.forEach(p => {