@@ -21,15 +21,7 @@
|
||||
<div id="canvas-container" class="w-100 h-100 d-block overflow-hidden"></div>
|
||||
|
||||
<!-- Legend Overlay -->
|
||||
<div class="position-absolute top-0 start-0 m-3 p-2 rounded shadow bg-dark bg-opacity-75 border border-secondary" style="color: #eee; font-size: 0.85rem; pointer-events: auto; z-index: 10;">
|
||||
<div class="mb-1 legend-item user-select-none" data-type="WALL-OUTER" style="cursor: pointer; transition: opacity 0.2s;"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: #eb8b38;"></span>{{ _('Outer Wall') }}</div>
|
||||
<div class="mb-1 legend-item user-select-none" data-type="WALL-INNER" style="cursor: pointer; transition: opacity 0.2s;"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: #4080cf;"></span>{{ _('Inner Wall') }}</div>
|
||||
<div class="mb-1 legend-item user-select-none" data-type="FILL" style="cursor: pointer; transition: opacity 0.2s;"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: #ccc04b;"></span>{{ _('Infill') }}</div>
|
||||
<div class="mb-1 legend-item user-select-none" data-type="SKIN" style="cursor: pointer; transition: opacity 0.2s;"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: #9e60b3;"></span>{{ _('Skin/TopBottom') }}</div>
|
||||
<div class="mb-1 legend-item user-select-none" data-type="SUPPORT" style="cursor: pointer; transition: opacity 0.2s;"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: #57b357;"></span>{{ _('Support') }}</div>
|
||||
<div class="mb-1 legend-item user-select-none" data-type="SKIRT" style="cursor: pointer; transition: opacity 0.2s;"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: #00ffff;"></span>{{ _('Skirt') }}</div>
|
||||
<div class="mb-1 legend-item user-select-none" data-type="SUPPORT-INTERFACE" style="cursor: pointer; transition: opacity 0.2s;"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: #2b6b2b;"></span>{{ _('Support Interface') }}</div>
|
||||
<div class="mb-1 legend-item user-select-none" data-type="TRAVEL" style="cursor: pointer; transition: opacity 0.2s; opacity: 0.4;"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: #405060;"></span>{{ _('Travel (Move)') }}</div>
|
||||
<div id="legend-overlay" class="position-absolute top-0 start-0 m-3 p-2 rounded shadow bg-dark bg-opacity-75 border border-secondary" style="color: #eee; font-size: 0.85rem; pointer-events: auto; z-index: 10;">
|
||||
</div>
|
||||
|
||||
<!-- Bottom Slider (Intra-Layer Progress) -->
|
||||
@@ -57,34 +49,6 @@
|
||||
|
||||
<script>
|
||||
document.addEventListener('DOMContentLoaded', async function() {
|
||||
const COLORS = {
|
||||
'WALL-OUTER': new THREE.Color(0xeb8b38),
|
||||
'WALL-INNER': new THREE.Color(0x4080cf),
|
||||
'FILL': new THREE.Color(0xccc04b),
|
||||
'SKIN': new THREE.Color(0x9e60b3),
|
||||
'SUPPORT': new THREE.Color(0x57b357),
|
||||
'SKIRT': new THREE.Color(0x00ffff),
|
||||
'SUPPORT-INTERFACE': new THREE.Color(0x2b6b2b),
|
||||
'TRAVEL': new THREE.Color(0x405060),
|
||||
'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) }};
|
||||
@@ -94,29 +58,39 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
const offsetY = {{ offset_y | default(0.0) }};
|
||||
|
||||
// Type indices for shader visibility filtering
|
||||
const TYPE_INDEX = {
|
||||
'TRAVEL': 0, 'WALL-OUTER': 1, 'WALL-INNER': 2,
|
||||
'FILL': 3, 'SKIN': 4, 'SUPPORT': 5, 'DEFAULT': 6,
|
||||
'SKIRT': 7, 'SUPPORT-INTERFACE': 8
|
||||
};
|
||||
let COLORS = {};
|
||||
let TYPE_INDEX = {};
|
||||
let gcodeMat = null;
|
||||
|
||||
// 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
|
||||
const SLICER_CONFIGS = {
|
||||
'Cura': [
|
||||
{ id: 'TRAVEL', label: '{{ _("Travel (Move)") }}', color: 0x405060, defaultShow: false },
|
||||
{ id: 'WALL-OUTER', label: '{{ _("Outer Wall") }}', color: 0xeb8b38, defaultShow: true },
|
||||
{ id: 'WALL-INNER', label: '{{ _("Inner Wall") }}', color: 0x4080cf, defaultShow: true },
|
||||
{ id: 'FILL', label: '{{ _("Infill") }}', color: 0xccc04b, defaultShow: true },
|
||||
{ id: 'SKIN', label: '{{ _("Skin/TopBottom") }}', color: 0x9e60b3, defaultShow: true },
|
||||
{ id: 'SUPPORT', label: '{{ _("Support") }}', color: 0x57b357, defaultShow: true },
|
||||
{ id: 'SKIRT', label: '{{ _("Skirt") }}', color: 0x00ffff, defaultShow: true },
|
||||
{ id: 'SUPPORT-INTERFACE', label: '{{ _("Support Interface") }}', color: 0x2b6b2b, defaultShow: true },
|
||||
{ id: 'DEFAULT', label: '{{ _("Others") }}', color: 0xaaaaaa, defaultShow: true }
|
||||
],
|
||||
'Prusa': [
|
||||
{ id: 'TRAVEL', label: '{{ _("Travel (Move)") }}', color: 0x405060, defaultShow: false },
|
||||
{ id: 'Custom', label: '{{ _("Custom") }}', color: 0xd0e0ff, defaultShow: true },
|
||||
{ id: 'Skirt/Brim', label: '{{ _("Skirt/Brim") }}', color: 0x00FFFF, defaultShow: true },
|
||||
{ id: 'Support material', label: '{{ _("Support material") }}', color: 0x90EE90, defaultShow: true },
|
||||
{ id: 'Perimeter', label: '{{ _("Perimeter") }}', color: 0xFFFFE0, defaultShow: true },
|
||||
{ id: 'External perimeter', label: '{{ _("External perimeter") }}', color: 0xFFA500, defaultShow: true },
|
||||
{ id: 'Solid infill', label: '{{ _("Solid infill") }}', color: 0x800080, defaultShow: true },
|
||||
{ id: 'Overhang perimeter', label: '{{ _("Overhang perimeter") }}', color: 0x00008B, defaultShow: true },
|
||||
{ id: 'Internal infill', label: '{{ _("Internal infill") }}', color: 0x8B0000, defaultShow: true },
|
||||
{ id: 'Bridge infill', label: '{{ _("Bridge infill") }}', color: 0x0000FF, defaultShow: true },
|
||||
{ id: 'Top solid infill', label: '{{ _("Top solid infill") }}', color: 0xFF0000, defaultShow: true },
|
||||
{ id: 'Support material interface', label: '{{ _("Support Interface") }}', color: 0x2b6b2b, defaultShow: true },
|
||||
{ id: 'DEFAULT', label: '{{ _("Others") }}', color: 0xaaaaaa, defaultShow: true }
|
||||
]
|
||||
};
|
||||
|
||||
// Merge aliases into TYPE_INDEX
|
||||
Object.assign(TYPE_INDEX, TYPE_INDEX_ALIASES);
|
||||
|
||||
let layers = [];
|
||||
let scene, camera, renderer, controls;
|
||||
let group = new THREE.Group();
|
||||
@@ -125,102 +99,90 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
const layerDisplay = document.getElementById('layer-display');
|
||||
const progressSlider = document.getElementById('progress-slider');
|
||||
|
||||
// Shader material for high-speed dynamic feature visibility
|
||||
const gcodeMat = new THREE.ShaderMaterial({
|
||||
uniforms: {
|
||||
uShowOuter: { value: 1.0 },
|
||||
uShowInner: { value: 1.0 },
|
||||
uShowInfill: { value: 1.0 },
|
||||
uShowSkin: { value: 1.0 },
|
||||
uShowSupport: { value: 1.0 },
|
||||
uShowSkirt: { value: 1.0 },
|
||||
uShowSupportInterface: { value: 1.0 },
|
||||
uShowTravel: { value: 0.0 },
|
||||
uShowDefault: { value: 1.0 }
|
||||
},
|
||||
vertexShader: `
|
||||
attribute float pType;
|
||||
varying vec3 vColor;
|
||||
varying float vType;
|
||||
void main() {
|
||||
vColor = color;
|
||||
vType = pType;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec3 vColor;
|
||||
varying float vType;
|
||||
uniform float uShowOuter;
|
||||
uniform float uShowInner;
|
||||
uniform float uShowInfill;
|
||||
uniform float uShowSkin;
|
||||
uniform float uShowSupport;
|
||||
uniform float uShowSkirt;
|
||||
uniform float uShowSupportInterface;
|
||||
uniform float uShowTravel;
|
||||
uniform float uShowDefault;
|
||||
void main() {
|
||||
float show = 1.0;
|
||||
int t = int(vType + 0.5);
|
||||
if (t == 0) show = uShowTravel;
|
||||
else if (t == 1) show = uShowOuter;
|
||||
else if (t == 2) show = uShowInner;
|
||||
else if (t == 3) show = uShowInfill;
|
||||
else if (t == 4) show = uShowSkin;
|
||||
else if (t == 5) show = uShowSupport;
|
||||
else if (t == 7) show = uShowSkirt;
|
||||
else if (t == 8) show = uShowSupportInterface;
|
||||
else show = uShowDefault;
|
||||
|
||||
if (show < 0.5) discard;
|
||||
gl_FragColor = vec4(vColor, 1.0);
|
||||
}
|
||||
`,
|
||||
vertexColors: true,
|
||||
side: THREE.DoubleSide,
|
||||
linewidth: 1
|
||||
});
|
||||
|
||||
// Binding the Legend Buttons
|
||||
const uniformMap = {
|
||||
'WALL-OUTER': 'uShowOuter',
|
||||
'WALL-INNER': 'uShowInner',
|
||||
'FILL': 'uShowInfill',
|
||||
'SKIN': 'uShowSkin',
|
||||
'SUPPORT': 'uShowSupport',
|
||||
'SKIRT': 'uShowSkirt',
|
||||
'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() {
|
||||
const t = this.dataset.type;
|
||||
const uniformName = uniformMap[t];
|
||||
if (uniformName) {
|
||||
const currentVal = gcodeMat.uniforms[uniformName].value;
|
||||
const newVal = currentVal > 0.5 ? 0.0 : 1.0;
|
||||
gcodeMat.uniforms[uniformName].value = newVal;
|
||||
this.style.opacity = newVal > 0.5 ? "1.0" : "0.4";
|
||||
function setupSlicerConfig(text) {
|
||||
let slicerType = 'Cura'; // default
|
||||
if (text.substring(0, 500).includes('generated by PrusaSlicer')) {
|
||||
slicerType = 'Prusa';
|
||||
}
|
||||
|
||||
const config = SLICER_CONFIGS[slicerType];
|
||||
|
||||
// 1. Build uniforms & shader strings dynamically
|
||||
let uniformsObj = {};
|
||||
let fragmentUniformsDecl = '';
|
||||
let fragmentUniformsLogic = '';
|
||||
|
||||
let overlayHTML = '';
|
||||
|
||||
config.forEach((c, idx) => {
|
||||
COLORS[c.id] = new THREE.Color(c.color);
|
||||
TYPE_INDEX[c.id] = idx;
|
||||
|
||||
const uniformName = 'uShow' + idx;
|
||||
uniformsObj[uniformName] = { value: c.defaultShow ? 1.0 : 0.0 };
|
||||
|
||||
fragmentUniformsDecl += `uniform float ${uniformName};\n`;
|
||||
|
||||
if (idx === 0) {
|
||||
fragmentUniformsLogic += `if (t == 0) show = ${uniformName};\n`;
|
||||
} else {
|
||||
fragmentUniformsLogic += ` else if (t == ${idx}) show = ${uniformName};\n`;
|
||||
}
|
||||
|
||||
// Build Legend UI
|
||||
const hexColor = '#' + c.color.toString(16).padStart(6, '0');
|
||||
const opacityStyle = c.defaultShow ? '1.0' : '0.4';
|
||||
overlayHTML += `
|
||||
<div class="mb-1 legend-item user-select-none" data-id="${c.id}" data-uniform="${uniformName}" style="cursor: pointer; transition: opacity 0.2s; opacity: ${opacityStyle};"><span class="d-inline-block rounded-circle me-2 border border-dark" style="width: 12px; height: 12px; background: ${hexColor};"></span>${c.label}</div>`;
|
||||
});
|
||||
});
|
||||
|
||||
// Add fallback condition
|
||||
fragmentUniformsLogic += ` else show = 1.0;\n`;
|
||||
|
||||
document.getElementById('legend-overlay').innerHTML = overlayHTML;
|
||||
|
||||
gcodeMat = new THREE.ShaderMaterial({
|
||||
uniforms: uniformsObj,
|
||||
vertexShader: `
|
||||
attribute float pType;
|
||||
varying vec3 vColor;
|
||||
varying float vType;
|
||||
void main() {
|
||||
vColor = color;
|
||||
vType = pType;
|
||||
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
||||
}
|
||||
`,
|
||||
fragmentShader: `
|
||||
varying vec3 vColor;
|
||||
varying float vType;
|
||||
${fragmentUniformsDecl}
|
||||
void main() {
|
||||
float show = 1.0;
|
||||
int t = int(vType + 0.5);
|
||||
${fragmentUniformsLogic}
|
||||
if (show < 0.5) discard;
|
||||
gl_FragColor = vec4(vColor, 1.0);
|
||||
}
|
||||
`,
|
||||
vertexColors: true,
|
||||
side: THREE.DoubleSide,
|
||||
linewidth: 1
|
||||
});
|
||||
|
||||
// Legend binding
|
||||
document.querySelectorAll('.legend-item').forEach(el => {
|
||||
el.addEventListener('click', function() {
|
||||
const uniformName = this.dataset.uniform;
|
||||
if (uniformName && gcodeMat.uniforms[uniformName]) {
|
||||
const currentVal = gcodeMat.uniforms[uniformName].value;
|
||||
const newVal = currentVal > 0.5 ? 0.0 : 1.0;
|
||||
gcodeMat.uniforms[uniformName].value = newVal;
|
||||
this.style.opacity = newVal > 0.5 ? "1.0" : "0.4";
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function init3D() {
|
||||
const container = document.getElementById('canvas-container');
|
||||
@@ -268,6 +230,7 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
document.getElementById('loading-overlay').classList.add('d-none');
|
||||
document.getElementById('preview-container').classList.remove('d-none');
|
||||
|
||||
setupSlicerConfig(gcodeText);
|
||||
init3D();
|
||||
parseGCode(gcodeText);
|
||||
|
||||
@@ -299,6 +262,13 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
const lines = text.split('\n');
|
||||
|
||||
let current = { x: 0, y: 0, z: 0, e: 0 };
|
||||
let relativeE = false; // Track M83 (relative) vs M82 (absolute)
|
||||
|
||||
// Dynamically compute width and layer height based on gcode info if possible
|
||||
let extWidth = 0.4;
|
||||
let layerHeight = 0.2;
|
||||
let pWidth = extWidth;
|
||||
|
||||
let currentTypeStr = 'DEFAULT';
|
||||
|
||||
let currentExtrudePoints = [];
|
||||
@@ -345,12 +315,25 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
if (!chunk) continue;
|
||||
let upperChunk = chunk.toUpperCase();
|
||||
|
||||
if (upperChunk.startsWith(';LAYER:')) {
|
||||
if (upperChunk.startsWith('M82')) relativeE = false;
|
||||
else if (upperChunk.startsWith('M83')) relativeE = true;
|
||||
|
||||
if (upperChunk.startsWith(';LAYER:') || upperChunk.startsWith(';LAYER_CHANGE')) {
|
||||
flushLayer();
|
||||
} else if (upperChunk.startsWith(';LAYER_HEIGHT:')) {
|
||||
let lh = parseFloat(chunk.substring(14));
|
||||
if (!isNaN(lh) && lh > 0) layerHeight = lh;
|
||||
} else if (upperChunk.startsWith(';HEIGHT:')) {
|
||||
let lh = parseFloat(chunk.substring(8));
|
||||
if (!isNaN(lh) && lh > 0) layerHeight = lh;
|
||||
} else if (upperChunk.startsWith(';WIDTH:')) {
|
||||
let w = parseFloat(chunk.substring(7));
|
||||
if (!isNaN(w) && w > 0) pWidth = w;
|
||||
} else if (upperChunk.startsWith(';TYPE:')) {
|
||||
currentTypeStr = chunk.substring(6).trim();
|
||||
} else if (chunk.startsWith(';') && COLORS[chunk.substring(1).trim()] !== undefined) {
|
||||
currentTypeStr = chunk.substring(1).trim();
|
||||
} 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`
|
||||
@@ -365,24 +348,35 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
let next = { x: current.x, y: current.y, z: current.z, e: current.e };
|
||||
let parts = upperChunk.split(/\s+/);
|
||||
let hasMove = false;
|
||||
let hasE = false;
|
||||
let eVal = 0;
|
||||
|
||||
for (let p of parts) {
|
||||
if (p.startsWith('X')) { let v = parseFloat(p.substring(1)); if(!isNaN(v)) { next.x = v; hasMove = true; } }
|
||||
if (p.startsWith('Y')) { let v = parseFloat(p.substring(1)); if(!isNaN(v)) { next.y = v; hasMove = true; } }
|
||||
if (p.startsWith('Z')) { let v = parseFloat(p.substring(1)); if(!isNaN(v)) { next.z = v; hasMove = true; } }
|
||||
if (p.startsWith('E')) { let v = parseFloat(p.substring(1)); if(!isNaN(v)) { next.e = v; } }
|
||||
if (p.startsWith('E')) { let v = parseFloat(p.substring(1)); if(!isNaN(v)) { eVal = v; hasE = true; } }
|
||||
}
|
||||
|
||||
if (hasMove && !isNaN(next.x) && !isNaN(next.y) && !isNaN(next.z)) {
|
||||
let isExtrude = (next.e > current.e);
|
||||
let isExtrude = false;
|
||||
if (hasE) {
|
||||
if (relativeE) {
|
||||
next.e = current.e + eVal;
|
||||
isExtrude = eVal > 0;
|
||||
} else {
|
||||
next.e = eVal;
|
||||
isExtrude = next.e > current.e;
|
||||
}
|
||||
}
|
||||
// Cura uses G0 for travel generally
|
||||
if (upperChunk.startsWith('G0') && !upperChunk.includes('E')) isExtrude = false;
|
||||
|
||||
let activeType = isExtrude ? currentTypeStr : 'TRAVEL';
|
||||
// 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;
|
||||
|
||||
if (isExtrude && COLORS[activeType] === undefined) {
|
||||
resolvedType = 'DEFAULT';
|
||||
}
|
||||
|
||||
let col = COLORS[resolvedType] || COLORS['DEFAULT'];
|
||||
@@ -393,8 +387,8 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
let dy = next.y - current.y;
|
||||
let dist = Math.sqrt(dx*dx + dy*dy);
|
||||
if (dist > 0.0001) {
|
||||
let hw = 0.4 / 2.0; // 0.4mm wire width
|
||||
let hh = 0.2 / 2.0; // 0.2mm layer height roughly
|
||||
let hw = pWidth / 2.0;
|
||||
let hh = layerHeight / 2.0;
|
||||
|
||||
let nx = -(dy / dist) * hw;
|
||||
let ny = (dx / dist) * hw;
|
||||
@@ -450,15 +444,23 @@ document.addEventListener('DOMContentLoaded', async function() {
|
||||
for(let k=0; k<6; k++) { currentExtrudeColors.push(col.r*0.8, col.g*0.8, col.b*0.8); currentExtrudeTypes.push(tIdx); }
|
||||
}
|
||||
} else {
|
||||
currentTravelPoints.push(current.x, current.y, current.z);
|
||||
currentTravelPoints.push(next.x, next.y, next.z);
|
||||
// Travel lines get slight vertical offset for visibility
|
||||
let zOff = 0.05;
|
||||
currentTravelPoints.push(current.x, current.y, current.z + zOff);
|
||||
currentTravelPoints.push(next.x, next.y, next.z + zOff);
|
||||
currentTravelColors.push(col.r, col.g, col.b, col.r, col.g, col.b);
|
||||
currentTravelTypes.push(tIdx, tIdx);
|
||||
}
|
||||
|
||||
current.x = next.x; current.y = next.y; current.z = next.z; current.e = next.e;
|
||||
// Update E based on parsed G-code execution type
|
||||
if (hasE) {
|
||||
if (relativeE) current.e += eVal;
|
||||
else current.e = eVal;
|
||||
}
|
||||
|
||||
current.x = next.x; current.y = next.y; current.z = next.z;
|
||||
}
|
||||
} else if (chunk.startsWith('G92')) {
|
||||
} else if (upperChunk.startsWith('G92')) {
|
||||
let parts = chunk.split(/\s+/);
|
||||
for (let p of parts) {
|
||||
if (p.startsWith('E')) { let v = parseFloat(p.substring(1)); if(!isNaN(v)) current.e = v; }
|
||||
|
||||
Reference in New Issue
Block a user