Files
linuxcncWebWASM/web/worker/test_xyzac_exact_preview.mjs

66 lines
5.5 KiB
JavaScript

import assert from "node:assert/strict";
import { readFile } from "node:fs/promises";
import createModule from "../../build-wasm/linuxcnc-sim-core.js";
import { loadSimulationCase, toWorkerConfiguration } from "../workspace/sim-case-loader.mjs";
import { XyzacSession, CONTEXT_ID } from "./xyzac-session.mjs";
import { fnv1a64 } from "./replay.mjs";
const CASE = "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/xyzac-trt.ini";
const PROGRAM_PATH = "linuxcnc/configs/sim/axis/vismach/5axis/table-rotary-tilting/demos/xyzac_switchkins.ngc";
const fetchImpl = async (url) => {
try { const body = await readFile(new URL(`../../${String(url).replace(/^\//, "")}`, import.meta.url)); return { ok: true, text: async () => body.toString("utf8") }; }
catch { return { ok: false, text: async () => "" }; }
};
const bundle = await loadSimulationCase({ path: CASE, fetchImpl });
assert.equal(bundle.status, "ready");
const source = bundle.files?.[PROGRAM_PATH];
assert.equal(typeof source, "string");
assert.equal(source, await readFile(new URL(`../../${PROGRAM_PATH}`, import.meta.url), "utf8"));
const core = await createModule({ wasmBinary: await readFile(new URL("../../build-wasm/linuxcnc-sim-core.wasm", import.meta.url)) });
const session = new XyzacSession(core, { sessionId: "xyzac-exact-preview" });
const base = { schema_version: 1, context_id: CONTEXT_ID, session_id: session.sessionId };
let seq = 0;
const send = (kind, operationId, payload = {}) => session.accept({ ...base, kind, seq: ++seq, operation_id: operationId, payload });
send("HELLO", "hello");
send("SESSION_ATTACH", "attach");
assert.equal(send("LOAD_WORKSPACE", "workspace", { root_path: "/workspace", configuration: toWorkerConfiguration(bundle) }).payload.status, "verified");
const loaded = send("PROGRAM_LOAD", "program-load", { source, path: PROGRAM_PATH });
assert.equal(loaded.kind, "COMMAND_RESULT");
assert.equal(loaded.payload.status, "verified");
assert.equal(loaded.payload.program.path, PROGRAM_PATH);
assert.equal(loaded.payload.program.source_hash, fnv1a64(source));
assert.equal(loaded.payload.preview.source, "linuxcnc-wasm-sim_program");
assert.equal(loaded.payload.preview.segments.length, 29);
assert.equal(loaded.payload.panel_snapshot.visual.source, "wasm_canonical_motion");
assert.equal(loaded.payload.panel_snapshot.visual.toolpath.length, 29);
const arcs = loaded.payload.preview.segments.filter((segment) => segment.motion_type === 2);
const rapids = loaded.payload.preview.segments.filter((segment) => segment.kind === "rapid");
assert.equal(arcs.length, 4);
assert.equal(rapids.length, 25);
assert.ok(rapids.every((segment) => segment.canonical_motion_mode === 0));
assert.ok(arcs.every((segment) => segment.canonical_motion_mode === 2));
assert.ok(rapids.every((segment) => Math.abs(segment.velocity - 35) < 1e-12));
assert.ok(arcs.every((segment) => Math.abs(segment.velocity - (1000 / 60)) < 1e-12));
assert.ok(arcs.every((segment) => segment.turn === -3));
assert.ok(arcs.every((segment) => Array.isArray(segment.samples) && segment.samples.length === 97));
assert.ok(arcs.every((segment) => segment.samples.some((sample) => sample.z < segment.start.z && sample.z > segment.end.z)));
assert.ok(arcs.every((segment) => segment.samples_source === "linuxcnc-wasm-sim_posemath_segment_point"));
assert.ok(arcs.every((segment) => segment.kind === "helix" && segment.helix === true && segment.radius === 10 && segment.turns === 3 && segment.axial_delta === -5));
assert.ok(arcs.every((segment) => segment.start.a === 20 && segment.end.a === 20 && segment.start.c === 45 && segment.end.c === 45));
assert.deepEqual(arcs.map((segment) => segment.source_line), [67, 67, 67, 67]);
for (const segment of arcs) {
const radius = segment.samples.map((sample) => Math.hypot(sample.x - segment.center.x, sample.y - segment.center.y));
assert.ok(Math.max(...radius) - Math.min(...radius) < 1e-9);
assert.ok(Math.abs(radius[0] - 10) < 1e-9);
assert.ok(Math.abs(segment.samples[0].z - 10) < 1e-9);
assert.ok(Math.abs(segment.samples.at(-1).z - 5) < 1e-9);
}
assert.deepEqual(arcs.map((segment) => [segment.end.x, segment.end.y, segment.end.z]), [[10, 20, 5], [-30, 20, 5], [-30, -20, 5], [10, -20, 5]]);
const clear = send("VISUAL_CLEAR", "visual-clear");
assert.equal(clear.payload.visual_only, true);
assert.deepEqual(clear.payload.before, clear.payload.after);
const restarted = send("PROGRAM_RESTART", "program-restart");
assert.equal(restarted.payload.program.path, PROGRAM_PATH);
assert.equal(restarted.payload.panel_snapshot.visual.toolpath.length, 29);
console.log(JSON.stringify({ schema: "xyzac-exact-tool-preview.v1", status: "verified", case: CASE, program_path: PROGRAM_PATH, source_hash: loaded.payload.program.source_hash, segment_count: loaded.payload.preview.segments.length, rapid_count: rapids.length, arc_count: arcs.length, arc_turn: -3, motion_mode_source: "linuxcnc-wasm-sim_program_canonical", helix_validation: { sample_points_per_helix: arcs[0].samples.length, samples_source: arcs[0].samples_source, radius_mm: 10, z_start: 10, z_end: 5, turns_per_helix: 3 }, helix_details: arcs.map((segment) => ({ source_line: segment.source_line, kind: segment.kind, start: segment.start, end: segment.end, center: segment.center, radius: segment.radius, turns: segment.turns, axial_delta: segment.axial_delta, samples: segment.samples.length, samples_source: segment.samples_source })), visual_segments: loaded.payload.panel_snapshot.visual.toolpath.length, restart_visual_segments: restarted.payload.panel_snapshot.visual.toolpath.length, clear_visual_only: clear.payload.visual_only, state_hash: loaded.payload.panel_snapshot.state_hash }));