新增仿真执行过程回放
结论:真实浏览器仿真页面新增 G-code 执行过程和刀具运动回放,支持 reset、step、play、finish,逐帧高亮 G-code 与 motion row,并渲染已执行刀路和移动 toolhead。
This commit is contained in:
@@ -92,14 +92,56 @@
|
||||
if (!api?.getPrograms || !api?.runProgramById) {
|
||||
throw new Error("simulation API missing program controls");
|
||||
}
|
||||
if (!api?.resetPlayback || !api?.stepPlayback || !api?.finishPlayback) {
|
||||
throw new Error("simulation API missing playback controls");
|
||||
}
|
||||
const programs = api.getPrograms();
|
||||
if (programs.length < 5) {
|
||||
throw new Error("simulation test program inventory too small");
|
||||
}
|
||||
|
||||
api.resetPlayback();
|
||||
if (doc.body.dataset.playbackIndex !== "0") {
|
||||
throw new Error("simulation playback did not reset to first frame");
|
||||
}
|
||||
const firstHead = doc.querySelector("[data-toolpath-head]");
|
||||
const firstCx = firstHead?.getAttribute("cx");
|
||||
const firstCy = firstHead?.getAttribute("cy");
|
||||
const firstExecutedPoints = doc.querySelector("[data-toolpath-executed-polyline]")?.getAttribute("points") ?? "";
|
||||
if (!doc.querySelector('[data-program-line="1"]') || doc.querySelector('[data-program-line="2"]')?.dataset.active !== "false") {
|
||||
throw new Error("simulation reset playback did not render first active program line");
|
||||
}
|
||||
|
||||
const secondFrame = api.stepPlayback(1);
|
||||
if (secondFrame.index !== 1 || secondFrame.activeLine !== 2) {
|
||||
throw new Error(`simulation step playback drift: ${JSON.stringify(secondFrame)}`);
|
||||
}
|
||||
const secondExecutedPoints = doc.querySelector("[data-toolpath-executed-polyline]")?.getAttribute("points") ?? "";
|
||||
if (secondExecutedPoints === firstExecutedPoints || !secondExecutedPoints.includes("1,0")) {
|
||||
throw new Error("simulation executed toolpath did not advance on step");
|
||||
}
|
||||
if (firstHead?.getAttribute("cx") === firstCx && firstHead?.getAttribute("cy") === firstCy) {
|
||||
throw new Error("simulation toolhead did not move on playback step");
|
||||
}
|
||||
if (doc.querySelector('[data-program-line="2"]')?.dataset.active !== "true") {
|
||||
throw new Error("simulation step playback did not highlight active G-code line");
|
||||
}
|
||||
if (doc.querySelector('[data-motion-row="1"]')?.dataset.active !== "true") {
|
||||
throw new Error("simulation step playback did not highlight active motion row");
|
||||
}
|
||||
|
||||
const finishedFrame = api.finishPlayback();
|
||||
if (finishedFrame.index !== state.motion.length - 1 || doc.body.dataset.playbackComplete !== "true") {
|
||||
throw new Error("simulation finish playback did not reach final frame");
|
||||
}
|
||||
|
||||
for (const program of programs) {
|
||||
const nextState = await api.runProgramById(program.id);
|
||||
assertRenderedState(doc, nextState);
|
||||
const resetFrame = api.resetPlayback();
|
||||
if (resetFrame.index !== 0 || doc.body.dataset.playbackIndex !== "0") {
|
||||
throw new Error(`simulation playback reset failed for ${program.id}`);
|
||||
}
|
||||
if (nextState.program.id !== program.id) {
|
||||
throw new Error(`simulation API returned wrong program id for ${program.id}`);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ import assert from "node:assert/strict";
|
||||
import {
|
||||
DEFAULT_SIMULATION_PROGRAM,
|
||||
DEFAULT_SIMULATION_PROGRAM_ID,
|
||||
createPlaybackFrame,
|
||||
createSimulationSummary,
|
||||
createToolpathPolylinePoints,
|
||||
getSimulationTestProgram,
|
||||
@@ -80,4 +81,27 @@ assert.ok(summary.motionTypes.includes("ARC_FEED"));
|
||||
assert.equal(summary.finalAxes.x, 0);
|
||||
assert.equal(summary.finalAxes.y, 0);
|
||||
|
||||
const playbackState = {
|
||||
motion: arcMotion,
|
||||
};
|
||||
const firstFrame = createPlaybackFrame(playbackState, 0);
|
||||
assert.equal(firstFrame.apiName, "real-browser-simulation-playback-frame");
|
||||
assert.equal(firstFrame.index, 0);
|
||||
assert.equal(firstFrame.step, 1);
|
||||
assert.equal(firstFrame.total, 3);
|
||||
assert.equal(firstFrame.activeLine, 1);
|
||||
assert.equal(firstFrame.visibleMotion.length, 1);
|
||||
|
||||
const arcFrame = createPlaybackFrame(playbackState, 1);
|
||||
assert.equal(arcFrame.index, 1);
|
||||
assert.equal(arcFrame.activeLine, 3);
|
||||
assert.equal(arcFrame.activeStatement, "G2 X1 Y1 I1 J0 F80");
|
||||
assert.equal(arcFrame.axes.x, 1);
|
||||
assert.equal(arcFrame.axes.y, 1);
|
||||
assert.equal(arcFrame.visibleMotion.length, 2);
|
||||
|
||||
const clampedFrame = createPlaybackFrame(playbackState, 99);
|
||||
assert.equal(clampedFrame.index, 2);
|
||||
assert.equal(clampedFrame.progress, 100);
|
||||
|
||||
console.log("real_simulation_programs_node_smoke=ok");
|
||||
|
||||
Reference in New Issue
Block a user