Update XYZBC web simulation evidence
This commit is contained in:
@@ -322,8 +322,11 @@ function renderMainTabs(element, state, dispatch) {
|
||||
<button type="button">centering</button>
|
||||
</div>
|
||||
<div class="axis-preview-wrap">
|
||||
<div class="axis-preview-readout" data-preview-readout></div>
|
||||
<canvas class="axis-preview-canvas" data-five-axis-canvas="true" aria-label="AXIS XYZBC TRT preview"></canvas>
|
||||
<div class="axis-preview-stage">
|
||||
<div class="axis-preview-readout" data-preview-readout></div>
|
||||
<canvas class="axis-preview-canvas" data-five-axis-canvas="true" aria-label="AXIS XYZBC TRT preview"></canvas>
|
||||
</div>
|
||||
<aside class="axis-process-monitor" data-linuxcnc-process-monitor></aside>
|
||||
</div>
|
||||
`;
|
||||
element.dataset.mounted = "true";
|
||||
@@ -334,6 +337,7 @@ function renderMainTabs(element, state, dispatch) {
|
||||
readout.dataset.kinsType = state.kinsType;
|
||||
|
||||
renderFiveAxisScene(element.querySelector("[data-five-axis-canvas]"), state);
|
||||
renderLinuxCncProcessMonitor(element.querySelector("[data-linuxcnc-process-monitor]"), state);
|
||||
}
|
||||
|
||||
function renderPyvcp(element, state, dispatch) {
|
||||
@@ -360,10 +364,37 @@ function renderPyvcp(element, state, dispatch) {
|
||||
|
||||
function renderProgram(element, state) {
|
||||
const currentLine = currentGcodeExecutionLine(state);
|
||||
const live = state.programUiExecution || {};
|
||||
const process = state.programAxisPreviewPath?.gcodeExecutionProcess || {};
|
||||
const gcodeStep = live.gcodeStepIndex === null || live.gcodeStepIndex === undefined
|
||||
? null
|
||||
: process.executionSteps?.[Number(live.gcodeStepIndex)] || null;
|
||||
element.dataset.liveSourceFile = live.sourceFile || "";
|
||||
element.dataset.liveSourceLine = String(live.line || currentLine || 0);
|
||||
element.dataset.liveSampleIndex = String(live.sampleIndex || 0);
|
||||
element.dataset.liveExecutedSamples = String(live.executedSampleCount || 0);
|
||||
element.dataset.gcodeExecutionStatus = process.status || "";
|
||||
element.dataset.gcodeExecutionStepCount = String(process.executionStepCount || 0);
|
||||
element.dataset.gcodeMotionStepCount = String(process.summary?.motionStepCount || 0);
|
||||
element.dataset.gcodeParameterStepCount = String(process.summary?.parameterAssignmentStepCount || 0);
|
||||
element.dataset.gcodeCallDepth = String(gcodeStep?.callDepth || 0);
|
||||
const lines = state.programLines?.length
|
||||
? state.programLines.slice(0, 80)
|
||||
: [";"];
|
||||
element.innerHTML = `
|
||||
<section class="axis-gcode-live" data-gcode-live>
|
||||
<header>
|
||||
<span>${escapeHtml(live.sourceFile || state.activeProgram || "-")}:${formatNumber(live.line || currentLine, 0)}</span>
|
||||
<b>${escapeHtml(live.operation || live.motionType || state.runState || "-")}</b>
|
||||
</header>
|
||||
<div class="axis-gcode-live-meta">
|
||||
<span>sample ${formatNumber((live.sampleIndex || 0) + 1, 0)} / ${formatNumber(live.sampleCount || 0, 0)}</span>
|
||||
<span>step ${live.gcodeStepIndex === null || live.gcodeStepIndex === undefined ? "-" : formatNumber(live.gcodeStepIndex, 0)}</span>
|
||||
<span>${escapeHtml(live.activeKinematics || state.kinsType || "-")}</span>
|
||||
</div>
|
||||
<code>${escapeHtml(live.statement || "-")}</code>
|
||||
${renderGcodeExecutionProcess(live, gcodeStep, process)}
|
||||
</section>
|
||||
<ol class="axis-program-list">
|
||||
${lines.map((line, index) => {
|
||||
const lineNo = state.programStartLine + index;
|
||||
@@ -376,16 +407,147 @@ function renderProgram(element, state) {
|
||||
if (activeRow) activeRow.scrollIntoView({ block: "center" });
|
||||
}
|
||||
|
||||
function renderGcodeExecutionProcess(live, gcodeStep, process) {
|
||||
const summary = process?.summary || {};
|
||||
const motion = gcodeStep?.result?.motion || null;
|
||||
const machine = live.machineState || gcodeStep?.result?.machineStateAfter || null;
|
||||
const callStack = Array.isArray(gcodeStep?.callStack) ? gcodeStep.callStack : [];
|
||||
const recentSteps = recentExecutedGcodeSteps(process, live.gcodeStepIndex);
|
||||
return `
|
||||
<section class="axis-gcode-process" data-gcode-process>
|
||||
<header>
|
||||
<span>expanded ${formatNumber(process?.executionStepCount || 0, 0)} steps</span>
|
||||
<span>${formatNumber(summary.motionStepCount || 0, 0)} motion / ${formatNumber(summary.parameterAssignmentStepCount || 0, 0)} params</span>
|
||||
</header>
|
||||
<div class="axis-gcode-flow" data-gcode-call-stack>
|
||||
${callStack.length > 0
|
||||
? callStack.map((entry) => `
|
||||
<span>${escapeHtml(entry.sourceFile)}:${formatNumber(entry.line, 0)} ${escapeHtml(entry.call)}</span>
|
||||
`).join("<b>></b>")
|
||||
: "<span>xyzbc_switchkins.ngc:2 o<xyzbc_switchkins_sub></span>"}
|
||||
</div>
|
||||
<div class="axis-gcode-result-grid">
|
||||
<span>Joint</span><b>${formatJointPose(live.joint || motion?.endJoint)}</b>
|
||||
<span>TCP</span><b>${formatTcpPose(live.tcp || motion?.endTcp)}</b>
|
||||
<span>Tool</span><b>${formatToolAxis(live.toolAxis || motion?.endToolAxis)}</b>
|
||||
<span>Feed</span><b>${formatNumber(machine?.feed?.actualMmPerMin || motion?.feed || 0, 1)} mm/min ${machine?.cutting?.active ? "cutting" : "rapid"}</b>
|
||||
</div>
|
||||
<ol class="axis-gcode-step-list" data-gcode-step-list>
|
||||
${recentSteps.map((step) => `
|
||||
<li class="${Number(step.stepIndex) === Number(live.gcodeStepIndex) ? "active" : ""}" data-gcode-step="${formatNumber(step.stepIndex, 0)}">
|
||||
<span>${formatNumber(step.stepIndex, 0)}</span>
|
||||
<code>${escapeHtml(step.sourceFile)}:${formatNumber(step.line, 0)} ${escapeHtml(step.statement || step.result?.operation || "")}</code>
|
||||
<b>${escapeHtml(step.result?.operation || step.sourceLineKind || "")}</b>
|
||||
</li>
|
||||
`).join("")}
|
||||
</ol>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
function recentExecutedGcodeSteps(process = {}, currentStepIndex = null) {
|
||||
const steps = Array.isArray(process.executionSteps) ? process.executionSteps : [];
|
||||
if (steps.length === 0) return [];
|
||||
const current = Number.isFinite(Number(currentStepIndex))
|
||||
? Number(currentStepIndex)
|
||||
: Math.max(0, steps.findIndex((step) => step.executed !== false));
|
||||
const start = Math.max(0, current - 2);
|
||||
return steps.slice(start, start + 5);
|
||||
}
|
||||
|
||||
function formatJointPose(pose = {}) {
|
||||
if (!pose) return "-";
|
||||
return `X${formatNumber(pose.x, 3)} Y${formatNumber(pose.y, 3)} Z${formatNumber(pose.z, 3)} B${formatNumber(pose.b, 3)} C${formatNumber(pose.c, 3)}`;
|
||||
}
|
||||
|
||||
function formatTcpPose(pose = {}) {
|
||||
if (!pose) return "-";
|
||||
return `X${formatNumber(pose.x, 3)} Y${formatNumber(pose.y, 3)} Z${formatNumber(pose.z, 3)}`;
|
||||
}
|
||||
|
||||
function formatToolAxis(axis = {}) {
|
||||
if (!axis) return "-";
|
||||
return `I${formatNumber(axis.i ?? axis.x, 3)} J${formatNumber(axis.j ?? axis.y, 3)} K${formatNumber(axis.k ?? axis.z, 3)}`;
|
||||
}
|
||||
|
||||
function renderStatusbar(element, state) {
|
||||
const toolLabel = formatToolStatus(state);
|
||||
const monitor = state.linuxCncProcessMonitor || {};
|
||||
element.innerHTML = `
|
||||
<div>${state.machine.powerOn ? "ON" : state.machine.estopActive ? "ESTOP" : "OFF"}</div>
|
||||
<div>${escapeHtml(toolLabel)}</div>
|
||||
<div>Position: Joint</div>
|
||||
<div>F ${formatNumber(monitor.feed?.currentVelocityMmPerMin || 0, 1)} S ${formatNumber(monitor.spindle?.actualRpm || 0, 0)} ${monitor.coolant?.flood ? "FLOOD" : monitor.coolant?.mist ? "MIST" : "M9"}</div>
|
||||
`;
|
||||
element.dataset.toolStatus = toolLabel;
|
||||
}
|
||||
|
||||
function renderLinuxCncProcessMonitor(element, state) {
|
||||
if (!element) return;
|
||||
const monitor = state.linuxCncProcessMonitor || {};
|
||||
const axes = monitor.axes || {};
|
||||
const path = monitor.path || {};
|
||||
const feed = monitor.feed || {};
|
||||
const spindle = monitor.spindle || {};
|
||||
const coolant = monitor.coolant || {};
|
||||
const tool = monitor.toolChange || {};
|
||||
const runtime = monitor.runtime || {};
|
||||
element.dataset.sourceMode = path.executionSource || state.programExecutionSourceMode || "";
|
||||
element.dataset.taskHalReady = String(runtime.taskHalReady === true);
|
||||
element.dataset.activeLine = String(path.activeLine || state.activeLine || 0);
|
||||
element.dataset.liveSourceFile = path.uiExecution?.sourceFile || "";
|
||||
element.dataset.liveSourceLine = String(path.uiExecution?.line || path.activeLine || 0);
|
||||
element.dataset.liveSampleIndex = String(path.uiExecution?.sampleIndex || 0);
|
||||
element.innerHTML = `
|
||||
<header>
|
||||
<strong>LinuxCNC Task / Motion / HAL</strong>
|
||||
<span>${escapeHtml(monitor.control?.runState || state.runState)}</span>
|
||||
</header>
|
||||
<section class="axis-monitor-group" data-monitor-group="position">
|
||||
<h3>Position</h3>
|
||||
${monitorAxisRows(axes.joint || state.axisPose || {})}
|
||||
<div class="axis-monitor-row"><span>TCP</span><b>${formatNumber(axes.tcp?.x, 3)} ${formatNumber(axes.tcp?.y, 3)} ${formatNumber(axes.tcp?.z, 3)}</b></div>
|
||||
<div class="axis-monitor-row"><span>DTG</span><b>${formatNumber(axes.distanceToGo?.x, 3)} ${formatNumber(axes.distanceToGo?.y, 3)} ${formatNumber(axes.distanceToGo?.z, 3)}</b></div>
|
||||
</section>
|
||||
<section class="axis-monitor-group" data-monitor-group="path">
|
||||
<h3>Tool Path</h3>
|
||||
<div class="axis-monitor-row"><span>Line</span><b>${formatNumber(path.activeLine, 0)} / ${formatNumber(state.lineCount || state.programLines?.length || 0, 0)}</b></div>
|
||||
<div class="axis-monitor-row"><span>Source</span><b>${escapeHtml(path.uiExecution?.sourceFile || "-")}:${formatNumber(path.uiExecution?.line || 0, 0)}</b></div>
|
||||
<div class="axis-monitor-row"><span>Motion</span><b>${formatNumber(path.motionIndex + 1, 0)} / ${formatNumber(path.motionCount, 0)}</b></div>
|
||||
<div class="axis-monitor-row"><span>Sample</span><b>${formatNumber(path.sampleIndex + 1, 0)} / ${formatNumber(path.sampleCount, 0)}</b></div>
|
||||
<div class="axis-monitor-code">${escapeHtml(path.activeGcode || "-")}</div>
|
||||
</section>
|
||||
<section class="axis-monitor-group" data-monitor-group="cutting">
|
||||
<h3>Cutting</h3>
|
||||
<div class="axis-monitor-row"><span>Feed</span><b>${formatNumber(feed.currentVelocityMmPerMin, 1)} mm/min</b></div>
|
||||
<div class="axis-monitor-row"><span>Cut</span><b>${formatNumber(feed.cuttingVelocityMmPerMin, 1)} mm/min</b></div>
|
||||
<div class="axis-monitor-row"><span>F cmd</span><b>${formatNumber(feed.feedRate, 1)} ${formatNumber(feed.feedOverridePercent, 0)}%</b></div>
|
||||
<div class="axis-monitor-row"><span>Spindle</span><b>${spindle.enabled ? escapeHtml(spindle.direction) : "stop"} ${formatNumber(spindle.actualRpm, 0)} rpm</b></div>
|
||||
<div class="axis-monitor-row"><span>Coolant</span><b>${coolant.flood ? "flood" : coolant.mist ? "mist" : "off"}</b></div>
|
||||
</section>
|
||||
<section class="axis-monitor-group" data-monitor-group="tool">
|
||||
<h3>Tool Change</h3>
|
||||
<div class="axis-monitor-row"><span>Tool</span><b>T${formatNumber(tool.activeToolNumber || tool.toolInSpindle, 0)} P${formatNumber(tool.activePocket || tool.toolFromPocket, 0)}</b></div>
|
||||
<div class="axis-monitor-row"><span>Offset</span><b>Z ${formatNumber(tool.lengthOffsetZ, 3)} D ${formatNumber(tool.diameter, 3)}</b></div>
|
||||
<div class="axis-monitor-row"><span>IO</span><b>${escapeHtml(tool.emcioStatus || "UNKNOWN")}</b></div>
|
||||
</section>
|
||||
<section class="axis-monitor-group" data-monitor-group="runtime">
|
||||
<h3>Runtime</h3>
|
||||
<div class="axis-monitor-row"><span>Task/HAL</span><b>${runtime.taskHalReady ? "ready" : "blocked"}</b></div>
|
||||
<div class="axis-monitor-row"><span>Loop</span><b>${runtime.taskHalLoopActive ? "active" : "idle"} #${formatNumber(runtime.taskHalTickCount, 0)}</b></div>
|
||||
<div class="axis-monitor-row"><span>Queue</span><b>${formatNumber(path.queueDepth, 0)} / ${formatNumber(path.activeDepth, 0)}</b></div>
|
||||
</section>
|
||||
`;
|
||||
}
|
||||
|
||||
function monitorAxisRows(axisPose) {
|
||||
return ["x", "y", "z", "a", "b", "c"].map((axis) => `
|
||||
<div class="axis-monitor-row">
|
||||
<span>${axis.toUpperCase()}</span>
|
||||
<b>${formatNumber(axisPose?.[axis], axis === "x" || axis === "y" || axis === "z" ? 3 : 4)}</b>
|
||||
</div>
|
||||
`).join("");
|
||||
}
|
||||
|
||||
function toolButton(buttonId, action, title, active = false) {
|
||||
const icon = getGmoccapyIcon(buttonId, active ? "active" : "inactive");
|
||||
const iconMarkup = icon.path
|
||||
|
||||
Reference in New Issue
Block a user