@@ -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;
|
||||
|
||||
@@ -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 => {
|
||||
|
||||
Reference in New Issue
Block a user