Fix repeated motion-id preview highlight
This commit is contained in:
@@ -4,7 +4,7 @@ import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
|
||||
import { projectXyzacVisual, type XyzacVisualSource, type XyzacVisualState } from "./xyzac-visual-adapter";
|
||||
|
||||
type Point = Record<string, number>;
|
||||
type Segment = { id?: number; active?: boolean; kind?: string; motion_type?: number; kinematics_mode?: number; turn?: number; center?: Point; normal?: Point; samples?: Point[]; start?: Point; end?: Point };
|
||||
type Segment = { id?: number; source_line?: number | null; active?: boolean; kind?: string; motion_type?: number; kinematics_mode?: number; turn?: number; center?: Point; normal?: Point; samples?: Point[]; start?: Point; end?: Point };
|
||||
type Props = { visual: XyzacVisualState; view?: "z" | "z2" | "x" | "y" | "y2" | "p"; zoom?: number; rotateMode?: boolean; showPath?: boolean; showLive?: boolean; showLimits?: boolean; showVelocity?: boolean; showOffsets?: boolean; showExtents?: boolean };
|
||||
|
||||
const DEG = Math.PI / 180;
|
||||
@@ -82,13 +82,18 @@ export function XyzacToolPreview({ visual, view = "p", zoom = 1, rotateMode = fa
|
||||
};
|
||||
const completed = new THREE.LineBasicMaterial({ color: 0xd8dfe3, depthTest: false });
|
||||
const rapid = new THREE.LineDashedMaterial({ color: 0xa85d5d, dashSize: .025, gapSize: .018, depthTest: false });
|
||||
const live = new THREE.LineBasicMaterial({ color: 0xffd166, depthTest: false });
|
||||
// LinuxCNC uses yellow for jog backplot. Coordinated program execution is
|
||||
// red (live plot), while an unambiguous current program block is cyan.
|
||||
const live = new THREE.LineBasicMaterial({ color: 0x00ffff, depthTest: false });
|
||||
const liveHistory = new THREE.LineBasicMaterial({ color: 0xff6b4a, depthTest: false });
|
||||
let frame = 0;
|
||||
let liveTick = -1;
|
||||
let liveTrace: THREE.Vector3[] = [];
|
||||
let pathSegments: Segment[] | null = null;
|
||||
let segmentById = new Map<number, Segment>();
|
||||
// Native TP active_id is the source line/motion id and may repeat (for
|
||||
// example, each call of the same helix subroutine). Preserve every
|
||||
// occurrence instead of letting a Map overwrite all but one geometry.
|
||||
let segmentCandidatesBySourceLine = new Map<number, Segment[]>();
|
||||
let bounds = { center: new THREE.Vector3(), radius: .12 };
|
||||
let playbackQueue: Array<{ tick: number; pose: Point; joints: number[]; activeSegmentId: number; activeProgress: number }> = [];
|
||||
let playbackStart = 0;
|
||||
@@ -203,7 +208,14 @@ export function XyzacToolPreview({ visual, view = "p", zoom = 1, rotateMode = fa
|
||||
// segments on every animation frame causes visible execution stalls.
|
||||
if (segments !== pathSegments) {
|
||||
pathSegments = segments;
|
||||
segmentById = new Map(segments.flatMap((segment) => Number.isSafeInteger(segment.id) ? [[Number(segment.id), segment] as [number, Segment]] : []));
|
||||
segmentCandidatesBySourceLine = new Map();
|
||||
for (const segment of segments) {
|
||||
const sourceLine = Number(segment.source_line);
|
||||
if (!Number.isSafeInteger(sourceLine) || sourceLine <= 0) continue;
|
||||
const candidates = segmentCandidatesBySourceLine.get(sourceLine) ?? [];
|
||||
candidates.push(segment);
|
||||
segmentCandidatesBySourceLine.set(sourceLine, candidates);
|
||||
}
|
||||
clearLines(pathGroup);
|
||||
clearLines(liveGroup);
|
||||
bounds = fit(segments);
|
||||
@@ -268,7 +280,11 @@ export function XyzacToolPreview({ visual, view = "p", zoom = 1, rotateMode = fa
|
||||
const nextActiveKey = `${renderedTick}:${renderedActiveSegment}:${renderedProgress}`;
|
||||
if (nextActiveKey !== lastActiveKey) {
|
||||
if (activeLiveLine) { activeLiveLine.geometry.dispose(); liveGroup.remove(activeLiveLine); activeLiveLine = null; }
|
||||
const activeSegment = segmentById.get(renderedActiveSegment) ?? segments.find((segment) => Boolean(segment.active));
|
||||
const candidates = segmentCandidatesBySourceLine.get(renderedActiveSegment) ?? [];
|
||||
// A repeated source line has no unique preview geometry. LinuxCNC's
|
||||
// current-line indicator remains authoritative in the program view;
|
||||
// do not invent a yellow/cyan path by selecting an arbitrary repeat.
|
||||
const activeSegment = candidates.length === 1 ? candidates[0] : null;
|
||||
if (activeSegment) {
|
||||
const start = activeSegment.start ?? {}; const end = activeSegment.end ?? {};
|
||||
const points = Array.isArray(activeSegment.samples) && activeSegment.samples.length > 1 ? activeSegment.samples.map(sourcePoint) : [sourcePoint(start), sourcePoint(end)];
|
||||
|
||||
@@ -16,7 +16,7 @@ assert.deepEqual(visual.pose, { x: 11, y: -4, z: 19, a: 31, b: 0, c: 44, u: 0, v
|
||||
assert.deepEqual(visual.livePose, visual.pose);
|
||||
assert.equal(visual.activeProgress, 0.375);
|
||||
assert.equal(visual.activeSegmentId, 3);
|
||||
for (const token of ["xyzac-tool-preview", "xyzac-preview-toolpath", "xyzac-preview-live-toolpath", "xyzac-preview-tool", "xyzac-preview-tool-shaft", "xyzac-preview-tool-tip", "xyzac-origin-coordinate-system", "xyzac-origin-axis-${axis.label.toLowerCase()}", "xyzac-origin-label-${axis.label.toLowerCase()}", "OrbitControls", "enablePan", "enableRotate", "zoomIn", "panRight", "data-xyzac-controller=\"orbit\"", "data-xyzac-origin=\"0,0,0\"", "sourcePoint", "toolGroup.position.copy(pose)", "toolGroup.rotation.set(-Number(renderedPose.a ?? 0) * DEG, -Number(renderedPose.c ?? 0) * DEG, 0)", "const segments = state.toolpath as Segment[]", "segment.samples.map(sourcePoint)", "state.activeProgress", "state.livePose", "motionTrace", "playbackQueue", "data-xyzac-preview=\"toolpath\"", "data-xyzac-helix-count", "data-xyzac-sample-count", "data-xyzac-samples-source", "data-xyzac-live-source", "data-xyzac-live-pose", "preserveDrawingBuffer: true", "authoritative tool preview"]) assert.ok(source.includes(token), token);
|
||||
for (const token of ["xyzac-tool-preview", "xyzac-preview-toolpath", "xyzac-preview-live-toolpath", "xyzac-preview-tool", "xyzac-preview-tool-shaft", "xyzac-preview-tool-tip", "xyzac-origin-coordinate-system", "xyzac-origin-axis-${axis.label.toLowerCase()}", "xyzac-origin-label-${axis.label.toLowerCase()}", "OrbitControls", "enablePan", "enableRotate", "zoomIn", "panRight", "data-xyzac-controller=\"orbit\"", "data-xyzac-origin=\"0,0,0\"", "sourcePoint", "toolGroup.position.copy(pose)", "toolGroup.rotation.set(-Number(renderedPose.a ?? 0) * DEG, -Number(renderedPose.c ?? 0) * DEG, 0)", "const segments = state.toolpath as Segment[]", "activeSegment.samples.map(sourcePoint)", "segmentCandidatesBySourceLine", "candidates.length === 1", "state.activeProgress", "state.livePose", "motionTrace", "playbackQueue", "data-xyzac-preview=\"toolpath\"", "data-xyzac-helix-count", "data-xyzac-sample-count", "data-xyzac-samples-source", "data-xyzac-live-source", "data-xyzac-live-pose", "preserveDrawingBuffer: true", "authoritative tool preview"]) assert.ok(source.includes(token), token);
|
||||
for (const forbidden of [/arcPoints/, /Math\.atan2/, /Quaternion/, /cross\(/]) assert.equal(forbidden.test(source), false, String(forbidden));
|
||||
for (const forbidden of [/xyzac-machine/, /table-x/, /saddle-y/, /spindle-z/, /accept\s*\(/, /postMessage\s*\(/, /_sim_/, /_malloc/, /navigator\.storage/]) assert.equal(forbidden.test(source), false, String(forbidden));
|
||||
console.log(JSON.stringify({ schema: "xyzac-tool-preview-rtcp-10b.v1", status: "verified", tick: visual.tick, state_hash: visual.stateHash, active_segment: visual.activeSegmentId, tool_pose: visual.pose, joints: visual.joints, machine_scene_nodes: 0, canonical_toolpath_segments: visual.toolpath.length, source: visual.source }));
|
||||
|
||||
Reference in New Issue
Block a user