Restore XYZAC joint readouts

This commit is contained in:
2026-09-10 06:04:42 +08:00
parent 17887c199a
commit 0a202e5841
5 changed files with 15 additions and 7 deletions

View File

@@ -825,9 +825,10 @@ machine/operation values remain on the main element as data attributes for
browser diagnostics; no control command or gate changes with this layout. browser diagnostics; no control command or gate changes with this layout.
Home Joint, the numeric joint selector and Home All are rendered in the Manual Home Joint, the numeric joint selector and Home All are rendered in the Manual
tab's action area; the standalone Machine sequence heading is not rendered. tab's action area; the standalone Machine sequence heading is not rendered.
The XYZAC position summary and preview HUD display only X/Y/Z/A/C; J0-J4 The XYZAC position summary and both preview HUDs display X/Y/Z/A/C together
position readouts are omitted. Numeric homing target selection and canonical with the five authoritative J0-J4 position readouts. Numeric homing target
joint data remain available to the existing control logic. selection and canonical joint data remain available to the existing control
logic.
```text ```text
HOME(all/joint) HOME(all/joint)

View File

@@ -189,7 +189,7 @@ export function XyzacMachineView({ visual, toolpath, view = "p", zoom = 1, rotat
{controllerButton("rotateUp", "Rotate upward", undefined, "\u2b06")}{controllerButton("rotateDown", "Rotate downward", undefined, "\u2b07")} {controllerButton("rotateUp", "Rotate upward", undefined, "\u2b06")}{controllerButton("rotateDown", "Rotate downward", undefined, "\u2b07")}
{controllerButton("reset", "Reset machine view", undefined, "\u21ba")}{controllerButton("tool", "Tool close-up", "tool_axis_z.gif")} {controllerButton("reset", "Reset machine view", undefined, "\u21ba")}{controllerButton("tool", "Tool close-up", "tool_axis_z.gif")}
</div> </div>
<pre className="axis-preview-hud xyzac-machine-hud" aria-label="XYZAC authoritative visual state">{visual.authoritative ? `XYZAC TRT\n${visual.joints.map((value, index) => `${["X", "Y", "Z", "A", "C"][index]} ${value.toFixed(3)}`).join("\n")}${showVelocity ? `\nV ${Number(visual.velocityMmMin ?? 0).toFixed(1)}` : ""}` : "XYZAC TRT\nWASM state pending"}</pre> <pre className="axis-preview-hud xyzac-machine-hud" aria-label="XYZAC authoritative visual state">{visual.authoritative ? `XYZAC TRT\n${visual.joints.map((value, index) => `${["X", "Y", "Z", "A", "C"][index]} ${value.toFixed(3)}`).join("\n")}\n${visual.joints.map((value, index) => `J${index} ${value.toFixed(3)}`).join(" ")}${showVelocity ? `\nV ${Number(visual.velocityMmMin ?? 0).toFixed(1)}` : ""}` : "XYZAC TRT\nWASM state pending"}</pre>
</div>; </div>;
} }

View File

@@ -404,7 +404,7 @@ export function XyzacToolPreview({ visual, view = "p", zoom = 1, rotateMode = fa
element.dataset.xyzacLimitsVisible = String(limitGrid.visible); element.dataset.xyzacLimitsVisible = String(limitGrid.visible);
element.dataset.xyzacExtentsVisible = String(extents.visible); element.dataset.xyzacExtentsVisible = String(extents.visible);
element.dataset.xyzacOffset = JSON.stringify(offset); element.dataset.xyzacOffset = JSON.stringify(offset);
if (hudRef.current) hudRef.current.textContent = `TOOL PREVIEW\nX ${Number(renderedPose.x).toFixed(3)} Y ${Number(renderedPose.y).toFixed(3)} Z ${Number(renderedPose.z).toFixed(3)}\nA ${Number(renderedPose.a).toFixed(3)} C ${Number(renderedPose.c).toFixed(3)}`; if (hudRef.current) hudRef.current.textContent = `TOOL PREVIEW\nX ${Number(renderedPose.x).toFixed(3)} Y ${Number(renderedPose.y).toFixed(3)} Z ${Number(renderedPose.z).toFixed(3)}\nA ${Number(renderedPose.a).toFixed(3)} C ${Number(renderedPose.c).toFixed(3)}\nJ0 ${Number(renderedJoints[0] ?? 0).toFixed(3)} J1 ${Number(renderedJoints[1] ?? 0).toFixed(3)} J2 ${Number(renderedJoints[2] ?? 0).toFixed(3)}\nJ3 ${Number(renderedJoints[3] ?? 0).toFixed(3)} J4 ${Number(renderedJoints[4] ?? 0).toFixed(3)}`;
if (layer.showVelocity && hudRef.current) hudRef.current.textContent += `\nV ${Number(state.velocityMmMin ?? 0).toFixed(1)} mm/min`; if (layer.showVelocity && hudRef.current) hudRef.current.textContent += `\nV ${Number(state.velocityMmMin ?? 0).toFixed(1)} mm/min`;
controls.mouseButtons.LEFT = rotateRef.current ? THREE.MOUSE.ROTATE : THREE.MOUSE.PAN; controls.mouseButtons.LEFT = rotateRef.current ? THREE.MOUSE.ROTATE : THREE.MOUSE.PAN;
controls.update(); renderer.render(scene, camera); frame = requestAnimationFrame(render); controls.update(); renderer.render(scene, camera); frame = requestAnimationFrame(render);
@@ -417,7 +417,7 @@ export function XyzacToolPreview({ visual, view = "p", zoom = 1, rotateMode = fa
const helixCount = visual.toolpath.filter((segment) => (segment as { kind?: string }).kind === "helix").length; const helixCount = visual.toolpath.filter((segment) => (segment as { kind?: string }).kind === "helix").length;
const sampleCount = visual.toolpath.reduce((count, segment) => count + (Array.isArray((segment as { samples?: unknown[] }).samples) ? (segment as { samples: unknown[] }).samples.length : 0), 0); const sampleCount = visual.toolpath.reduce((count, segment) => count + (Array.isArray((segment as { samples?: unknown[] }).samples) ? (segment as { samples: unknown[] }).samples.length : 0), 0);
const controllerButton = (action: string, label: string, glyph: string) => ["zoomIn", "zoomOut"].includes(action) ? null : <button type="button" data-axis-control={`preview-${action}`} data-xyzac-controller={action} title={label} aria-label={label} onClick={() => { const controller = (host.current as (HTMLDivElement & { xyzacController?: Record<string, () => void> }) | null)?.xyzacController; controller?.[action]?.(); }}>{glyph}</button>; const controllerButton = (action: string, label: string, glyph: string) => ["zoomIn", "zoomOut"].includes(action) ? null : <button type="button" data-axis-control={`preview-${action}`} data-xyzac-controller={action} title={label} aria-label={label} onClick={() => { const controller = (host.current as (HTMLDivElement & { xyzacController?: Record<string, () => void> }) | null)?.xyzacController; controller?.[action]?.(); }}>{glyph}</button>;
return <div className="three-viewer xyzac-tool-preview" ref={host} data-xyzac-authoritative={String(visual.authoritative)} data-xyzac-preview="toolpath" data-xyzac-controller="orbit" data-xyzac-origin="0,0,0" data-xyzac-origin-axes="X,Y,Z" data-xyzac-toolpath-count={visual.toolpath.length} data-xyzac-helix-count={helixCount} data-xyzac-sample-count={sampleCount} data-xyzac-samples-source="linuxcnc-wasm-sim_posemath_segment_point" data-xyzac-live-source="linuxcnc-source-tp" data-xyzac-live-progress={visual.activeProgress} data-xyzac-live-pose={JSON.stringify(visual.livePose)} data-xyzac-tick={visual.tick} data-xyzac-state-hash={visual.stateHash} data-xyzac-active-segment={visual.activeSegmentId ?? ""} aria-label="XYZAC authoritative tool preview"><div className="xyzac-view-controller" role="toolbar" aria-label="3D preview controller">{controllerButton("zoomIn", "Zoom in", "+")}{controllerButton("zoomOut", "Zoom out", "-")}<span className="xyzac-controller-divider" aria-hidden="true" />{controllerButton("panLeft", "Pan left", "L")}{controllerButton("panRight", "Pan right", "R")}{controllerButton("panUp", "Pan up", "U")}{controllerButton("panDown", "Pan down", "D")}<span className="xyzac-controller-divider" aria-hidden="true" />{controllerButton("reset", "Reset 3D view", "0")}</div><pre ref={hudRef} className="axis-preview-hud" aria-label="XYZAC tool preview state">{visual.authoritative ? `TOOL PREVIEW\nX ${Number(pose.x).toFixed(3)} Y ${Number(pose.y).toFixed(3)} Z ${Number(pose.z).toFixed(3)}\nA ${Number(pose.a).toFixed(3)} C ${Number(pose.c).toFixed(3)}` : "TOOL PREVIEW\nWASM state pending"}</pre></div>; return <div className="three-viewer xyzac-tool-preview" ref={host} data-xyzac-authoritative={String(visual.authoritative)} data-xyzac-preview="toolpath" data-xyzac-controller="orbit" data-xyzac-origin="0,0,0" data-xyzac-origin-axes="X,Y,Z" data-xyzac-toolpath-count={visual.toolpath.length} data-xyzac-helix-count={helixCount} data-xyzac-sample-count={sampleCount} data-xyzac-samples-source="linuxcnc-wasm-sim_posemath_segment_point" data-xyzac-live-source="linuxcnc-source-tp" data-xyzac-live-progress={visual.activeProgress} data-xyzac-live-pose={JSON.stringify(visual.livePose)} data-xyzac-tick={visual.tick} data-xyzac-state-hash={visual.stateHash} data-xyzac-active-segment={visual.activeSegmentId ?? ""} data-xyzac-joints={JSON.stringify(visual.joints)} aria-label="XYZAC authoritative tool preview"><div className="xyzac-view-controller" role="toolbar" aria-label="3D preview controller">{controllerButton("zoomIn", "Zoom in", "+")}{controllerButton("zoomOut", "Zoom out", "-")}<span className="xyzac-controller-divider" aria-hidden="true" />{controllerButton("panLeft", "Pan left", "L")}{controllerButton("panRight", "Pan right", "R")}{controllerButton("panUp", "Pan up", "U")}{controllerButton("panDown", "Pan down", "D")}<span className="xyzac-controller-divider" aria-hidden="true" />{controllerButton("reset", "Reset 3D view", "0")}</div><pre ref={hudRef} className="axis-preview-hud" aria-label="XYZAC tool preview state">{visual.authoritative ? `TOOL PREVIEW\nX ${Number(pose.x).toFixed(3)} Y ${Number(pose.y).toFixed(3)} Z ${Number(pose.z).toFixed(3)}\nA ${Number(pose.a).toFixed(3)} C ${Number(pose.c).toFixed(3)}\nJ0 ${Number(visual.joints[0] ?? 0).toFixed(3)} J1 ${Number(visual.joints[1] ?? 0).toFixed(3)} J2 ${Number(visual.joints[2] ?? 0).toFixed(3)}\nJ3 ${Number(visual.joints[3] ?? 0).toFixed(3)} J4 ${Number(visual.joints[4] ?? 0).toFixed(3)}` : "TOOL PREVIEW\nWASM state pending"}</pre></div>;
} }
export function XyzacToolPreviewFromSnapshot({ snapshot, ...props }: Omit<Props, "visual"> & { snapshot: XyzacVisualSource | null | undefined }) { export function XyzacToolPreviewFromSnapshot({ snapshot, ...props }: Omit<Props, "visual"> & { snapshot: XyzacVisualSource | null | undefined }) {

View File

@@ -24,7 +24,7 @@ export function XyzacManualPanel({ view }: { view: XyzacPanelView }) {
return <section className="xyzac-manual-summary" aria-label="XYZAC authoritative position"> return <section className="xyzac-manual-summary" aria-label="XYZAC authoritative position">
<div className="xyzac-section-title"><strong>XYZAC authority</strong><span>{view.kinematics?.linear_units ?? "mm"} / {view.kinematics?.angular_units ?? "deg"}</span></div> <div className="xyzac-section-title"><strong>XYZAC authority</strong><span>{view.kinematics?.linear_units ?? "mm"} / {view.kinematics?.angular_units ?? "deg"}</span></div>
<div className="xyzac-position-grid"> <div className="xyzac-position-grid">
{axes.map((axis) => <div key={axis}><b>{axis.toUpperCase()}</b><output>{pose ? Number(pose[axis] ?? Number.NaN).toFixed(axis === "a" || axis === "c" ? 3 : 4) : "-"}</output></div>)} {axes.map((axis, index) => <div key={axis}><b>{axis.toUpperCase()}</b><output>{pose ? Number(pose[axis] ?? Number.NaN).toFixed(axis === "a" || axis === "c" ? 3 : 4) : "-"}</output><small>J{index} {view.joints.length === 5 ? Number(view.joints[index]).toFixed(4) : "-"}</small></div>)}
</div> </div>
<div className="xyzac-offset-row"><span>Tool {view.kinematics ? Number(view.kinematics.offsets.tool_offset).toFixed(3) : "-"}</span><span>Y offset {view.kinematics ? Number(view.kinematics.offsets.y_offset).toFixed(3) : "-"}</span><span>Z offset {view.kinematics ? Number(view.kinematics.offsets.z_offset).toFixed(3) : "-"}</span></div> <div className="xyzac-offset-row"><span>Tool {view.kinematics ? Number(view.kinematics.offsets.tool_offset).toFixed(3) : "-"}</span><span>Y offset {view.kinematics ? Number(view.kinematics.offsets.y_offset).toFixed(3) : "-"}</span><span>Z offset {view.kinematics ? Number(view.kinematics.offsets.z_offset).toFixed(3) : "-"}</span></div>
</section>; </section>;

View File

@@ -5,6 +5,8 @@ import * as THREE from "three";
import { buildXyzacMachine } from "./xyzac-machine-model.ts"; import { buildXyzacMachine } from "./xyzac-machine-model.ts";
const source = await readFile(new URL("./XyzacMachineView.tsx", import.meta.url), "utf8") + await readFile(new URL("./xyzac-machine-model.ts", import.meta.url), "utf8"); const source = await readFile(new URL("./XyzacMachineView.tsx", import.meta.url), "utf8") + await readFile(new URL("./xyzac-machine-model.ts", import.meta.url), "utf8");
const panelSource = await readFile(new URL("./XyzacTrtPanel.tsx", import.meta.url), "utf8");
const toolSource = await readFile(new URL("./XyzacToolPreview.tsx", import.meta.url), "utf8");
const adapter = await readFile(new URL("./xyzac-visual-adapter.ts", import.meta.url), "utf8"); const adapter = await readFile(new URL("./xyzac-visual-adapter.ts", import.meta.url), "utf8");
const snapshot = { const snapshot = {
schema: "axis-panel-snapshot.v1", schema: "axis-panel-snapshot.v1",
@@ -45,6 +47,11 @@ assert.deepEqual(XYZAC_MACHINE_GROUPS, ["xyzac-machine", "table-x", "saddle-y",
for (const token of ["table-x", "saddle-y", "spindle-z", "tilt-a", "rotate-c", "tool-offset", "tableX.position.x = -tableXJoint * MM", "saddle.position.z = -saddleYJoint * MM", "zslide.position.y = (200 - spindleZJoint) * MM", "tilt.rotation.x = -tiltAJoint * DEG", "rotate.rotation.y = -rotateCJoint * DEG", "tool.position.y = -state.offsets.tool_offset * MM", "data-xyzac-tick", "data-xyzac-state-hash", "data-xyzac-active-segment", "data-xyzac-joints", "data-xyzac-offsets"]) assert.ok(source.includes(token), token); for (const token of ["table-x", "saddle-y", "spindle-z", "tilt-a", "rotate-c", "tool-offset", "tableX.position.x = -tableXJoint * MM", "saddle.position.z = -saddleYJoint * MM", "zslide.position.y = (200 - spindleZJoint) * MM", "tilt.rotation.x = -tiltAJoint * DEG", "rotate.rotation.y = -rotateCJoint * DEG", "tool.position.y = -state.offsets.tool_offset * MM", "data-xyzac-tick", "data-xyzac-state-hash", "data-xyzac-active-segment", "data-xyzac-joints", "data-xyzac-offsets"]) assert.ok(source.includes(token), token);
for (const forbidden of [/accept\s*\(/, /postMessage\s*\(/, /_sim_/, /_malloc/, /navigator\.storage/, /HAL_SET/, /KINEMATICS_SELECT/]) assert.equal(forbidden.test(source), false, String(forbidden)); for (const forbidden of [/accept\s*\(/, /postMessage\s*\(/, /_sim_/, /_malloc/, /navigator\.storage/, /HAL_SET/, /KINEMATICS_SELECT/]) assert.equal(forbidden.test(source), false, String(forbidden));
assert.ok(adapter.includes("source: \"linuxcnc-wasm-worker\"")); assert.ok(adapter.includes("source: \"linuxcnc-wasm-worker\""));
for (const token of ["J0", "J1", "J2", "J3", "J4"]) {
assert.ok(panelSource.includes("J{index}"), "panel joint label template");
assert.ok(toolSource.includes(token), `tool preview ${token}`);
assert.ok(source.includes("J${index}"), "machine preview joint label template");
}
const model = buildXyzacMachine(); const model = buildXyzacMachine();
const original = structuredClone(visual); const original = structuredClone(visual);
const zero = { joints: [0, 0, 0, 0, 0], offsets: { x_rot_point: 0, y_offset: 20, z_offset: 10, tool_offset: 0 } }; const zero = { joints: [0, 0, 0, 0, 0], offsets: { x_rot_point: 0, y_offset: 20, z_offset: 10, tool_offset: 0 } };