Fix XYZBC tool execution TCP path
This commit is contained in:
@@ -47,7 +47,10 @@ import {
|
||||
normalizeLinuxCncTaskMode,
|
||||
} from "./linuxcnc-task-policy.js";
|
||||
import { buildProgramExecutionTiming, timingAtMotionIndex } from "../runtime/execution-timing.js";
|
||||
import { buildAxisPreviewPathFromProgram } from "../runtime/axis-preview-path.js";
|
||||
import {
|
||||
buildAxisExecutionTraceFromProgram,
|
||||
buildAxisPreviewPathFromProgram,
|
||||
} from "../runtime/axis-preview-path.js";
|
||||
|
||||
const defaultProfile = getFiveAxisProfile("xyzbc-trt");
|
||||
|
||||
@@ -109,6 +112,11 @@ function withDefaultWebOpfsRequirement(options = {}) {
|
||||
return isBrowser ? { ...options, requireOpfs: true } : options;
|
||||
}
|
||||
|
||||
function buildProgramAxisPathFromProgram(options = {}) {
|
||||
return buildAxisExecutionTraceFromProgram(options)
|
||||
|| buildAxisPreviewPathFromProgram(options);
|
||||
}
|
||||
|
||||
const initialState = {
|
||||
machineProfile: "xyzbc-trt",
|
||||
availableProfiles: fiveAxisProfiles.map(({ id, title, traj, kinematicsModuleId, kinematics }) => ({
|
||||
@@ -213,6 +221,8 @@ const initialState = {
|
||||
programRuntimeFeedback: null,
|
||||
programRuntimeFeedbackHistory: [],
|
||||
programLineExecution: {},
|
||||
programUiExecution: null,
|
||||
linuxCncProcessMonitor: null,
|
||||
taskHalRuntime: null,
|
||||
taskHalRuntimeReadiness: null,
|
||||
taskHalStatus: null,
|
||||
@@ -349,6 +359,7 @@ initialState.machineProject = createMachineProjectState(initialState);
|
||||
initialState.programValidation = createProgramValidationState(initialState);
|
||||
initialState.rightSidebarEntrances = createRightSidebarEntranceState(initialState, initialState.linuxCncTaskPolicy);
|
||||
initialState.linuxCncParityMatrix = createLinuxCncParityMatrix(initialState);
|
||||
initialState.linuxCncProcessMonitor = createLinuxCncProcessMonitor(initialState);
|
||||
|
||||
const programLines = [
|
||||
"; zmax zmin r frate n a b c dist",
|
||||
@@ -381,7 +392,7 @@ export function createSimulationStore(seed = {}) {
|
||||
programLines: seed.programLines || programLines,
|
||||
};
|
||||
const initialAxisPreviewPath = seed.programAxisPreviewPath === undefined
|
||||
? buildAxisPreviewPathFromProgram({
|
||||
? buildProgramAxisPathFromProgram({
|
||||
filename: state.activeProgram,
|
||||
sourceRel: state.programSourceRel,
|
||||
content: state.programLines.join("\n"),
|
||||
@@ -401,6 +412,7 @@ export function createSimulationStore(seed = {}) {
|
||||
state.programValidation = createProgramValidationState(state);
|
||||
state.rightSidebarEntrances = createRightSidebarEntranceState(state, state.linuxCncTaskPolicy);
|
||||
state.linuxCncParityMatrix = createLinuxCncParityMatrix(state);
|
||||
state.linuxCncProcessMonitor = createLinuxCncProcessMonitor(state);
|
||||
state.fullExecutionBoundary = createFullLinuxCncExecutionBoundary(state);
|
||||
const listeners = new Set();
|
||||
let taskHalStatusLoopTimer = null;
|
||||
@@ -449,6 +461,7 @@ export function createSimulationStore(seed = {}) {
|
||||
state = {
|
||||
...nextState,
|
||||
linuxCncParityMatrix: createLinuxCncParityMatrix(nextState),
|
||||
linuxCncProcessMonitor: createLinuxCncProcessMonitor(nextState),
|
||||
fullExecutionBoundary: createFullLinuxCncExecutionBoundary(nextState),
|
||||
};
|
||||
notify();
|
||||
@@ -714,14 +727,32 @@ export function createSimulationStore(seed = {}) {
|
||||
motion: firstMotion,
|
||||
timingSnapshot: firstTiming,
|
||||
});
|
||||
const initialUiPatch = applyProgramPlaybackUiPatch({
|
||||
...state,
|
||||
programExecution: execution,
|
||||
programExecutionTiming: timing,
|
||||
programExecutionSampleIndex: 0,
|
||||
programExecutionMotionIndex: 0,
|
||||
activeLine: firstMotion?.line || state.programStartLine,
|
||||
axisPose: axisPoseFromCanonicalMotion(firstMotion, state.axisPose),
|
||||
kinsType: firstKinsType,
|
||||
rtcpState: rtcpStateFromKinsType(firstKinsType),
|
||||
programRuntimeFeedback: firstFeedback,
|
||||
}, {
|
||||
activeLine: firstMotion?.line || state.programStartLine,
|
||||
axisPose: axisPoseFromCanonicalMotion(firstMotion, state.axisPose),
|
||||
kinsType: firstKinsType,
|
||||
rtcpState: rtcpStateFromKinsType(firstKinsType),
|
||||
motionIndex: 0,
|
||||
sampleIndex: 0,
|
||||
runtimeFeedback: firstFeedback,
|
||||
});
|
||||
setState({
|
||||
programExecution: execution,
|
||||
programExecutionTiming: timing,
|
||||
programExecutionSourceMode: execution.sourceMode,
|
||||
machineFileExecution: execution.machineFilePlan ? execution : state.machineFileExecution,
|
||||
programExecutionMotionIndex: 0,
|
||||
programExecutionSampleIndex: 0,
|
||||
programRuntimeFeedback: firstFeedback,
|
||||
...initialUiPatch,
|
||||
programLineExecution: createProgramLineExecutionPatch(state.programLineExecution, firstFeedback, {
|
||||
status: "ready",
|
||||
source: execution.sourceMode,
|
||||
@@ -729,10 +760,6 @@ export function createSimulationStore(seed = {}) {
|
||||
programElapsedSeconds: firstTiming.elapsedSeconds,
|
||||
programRemainingSeconds: firstTiming.remainingSeconds,
|
||||
interpreterExecutionPending: false,
|
||||
activeLine: firstMotion?.line || state.programStartLine,
|
||||
axisPose: axisPoseFromCanonicalMotion(firstMotion, state.axisPose),
|
||||
kinsType: firstKinsType,
|
||||
rtcpState: rtcpStateFromKinsType(firstKinsType),
|
||||
preview: {
|
||||
...state.preview,
|
||||
pathPoints: state.programAxisPreviewPath?.sampleCount || Math.max(execution.summary.motionEventCount, 1),
|
||||
@@ -974,7 +1001,7 @@ export function createSimulationStore(seed = {}) {
|
||||
programText: selectedFile.text,
|
||||
sourceRel: selectedFile.sourceRel,
|
||||
});
|
||||
const axisPreviewPath = buildAxisPreviewPathFromProgram({
|
||||
const axisPreviewPath = buildProgramAxisPathFromProgram({
|
||||
filename: selectedFile.sourceRel,
|
||||
sourceRel: selectedFile.sourceRel,
|
||||
content: selectedFile.text,
|
||||
@@ -999,6 +1026,7 @@ export function createSimulationStore(seed = {}) {
|
||||
runState: "idle",
|
||||
programAxisPreviewPath: axisPreviewPath,
|
||||
programRuntimeFeedback: null,
|
||||
programUiExecution: null,
|
||||
programLineExecution: {},
|
||||
preview: {
|
||||
...state.preview,
|
||||
@@ -1508,7 +1536,7 @@ export function createSimulationStore(seed = {}) {
|
||||
const toolRuntimeState = createToolRuntimeState(toolDbSimulation, {
|
||||
fallbackToolLength: state.toolPreview?.length,
|
||||
});
|
||||
const axisPreviewPath = buildAxisPreviewPathFromProgram({
|
||||
const axisPreviewPath = buildProgramAxisPathFromProgram({
|
||||
filename: loadedProgram.activeProgram,
|
||||
sourceRel: loadedProgram.programSourceRel,
|
||||
content: action.content,
|
||||
@@ -1563,6 +1591,15 @@ export function createSimulationStore(seed = {}) {
|
||||
break;
|
||||
}
|
||||
const playback = nextProgramRuntimeSamplePlayback(state, 5);
|
||||
const playbackPatch = applyProgramPlaybackUiPatch(state, {
|
||||
activeLine: playback.activeLine,
|
||||
axisPose: playback.axisPose,
|
||||
kinsType: playback.kinsType,
|
||||
rtcpState: playback.rtcpState,
|
||||
motionIndex: playback.motionIndex,
|
||||
sampleIndex: playback.sampleIndex,
|
||||
runtimeFeedback: playback.runtimeFeedback,
|
||||
});
|
||||
setState({
|
||||
machine: {
|
||||
...state.machine,
|
||||
@@ -1573,13 +1610,7 @@ export function createSimulationStore(seed = {}) {
|
||||
taskPaused: false,
|
||||
},
|
||||
runState: playback.complete ? "complete" : "running",
|
||||
activeLine: playback.activeLine,
|
||||
axisPose: playback.axisPose,
|
||||
kinsType: playback.kinsType,
|
||||
rtcpState: playback.rtcpState,
|
||||
programExecutionMotionIndex: playback.motionIndex,
|
||||
programExecutionSampleIndex: playback.sampleIndex,
|
||||
programRuntimeFeedback: playback.runtimeFeedback,
|
||||
...playbackPatch,
|
||||
programLineExecution: createProgramLineExecutionPatch(state.programLineExecution, playback.runtimeFeedback, {
|
||||
status: playback.complete ? "done" : "running",
|
||||
source: playback.runtimeFeedback?.sourceMode,
|
||||
@@ -1747,6 +1778,15 @@ export function createSimulationStore(seed = {}) {
|
||||
break;
|
||||
}
|
||||
const playback = nextProgramRuntimeSamplePlayback(state, 1);
|
||||
const playbackPatch = applyProgramPlaybackUiPatch(state, {
|
||||
activeLine: playback.activeLine,
|
||||
axisPose: playback.axisPose,
|
||||
kinsType: playback.kinsType,
|
||||
rtcpState: playback.rtcpState,
|
||||
motionIndex: playback.motionIndex,
|
||||
sampleIndex: playback.sampleIndex,
|
||||
runtimeFeedback: playback.runtimeFeedback,
|
||||
});
|
||||
setState({
|
||||
machine: {
|
||||
...state.machine,
|
||||
@@ -1759,13 +1799,7 @@ export function createSimulationStore(seed = {}) {
|
||||
taskPaused: true,
|
||||
},
|
||||
runState: "stepping",
|
||||
activeLine: playback.activeLine,
|
||||
axisPose: playback.axisPose,
|
||||
kinsType: playback.kinsType,
|
||||
rtcpState: playback.rtcpState,
|
||||
programExecutionMotionIndex: playback.motionIndex,
|
||||
programExecutionSampleIndex: playback.sampleIndex,
|
||||
programRuntimeFeedback: playback.runtimeFeedback,
|
||||
...playbackPatch,
|
||||
programElapsedSeconds: playback.timing.elapsedSeconds,
|
||||
programRemainingSeconds: playback.timing.remainingSeconds,
|
||||
feed: {
|
||||
@@ -1784,6 +1818,15 @@ export function createSimulationStore(seed = {}) {
|
||||
break;
|
||||
}
|
||||
const playback = nextProgramRuntimeSamplePlayback(state, 5);
|
||||
const playbackPatch = applyProgramPlaybackUiPatch(state, {
|
||||
activeLine: playback.activeLine,
|
||||
axisPose: playback.axisPose,
|
||||
kinsType: playback.kinsType,
|
||||
rtcpState: playback.rtcpState,
|
||||
motionIndex: playback.motionIndex,
|
||||
sampleIndex: playback.sampleIndex,
|
||||
runtimeFeedback: playback.runtimeFeedback,
|
||||
});
|
||||
setState({
|
||||
machine: {
|
||||
...state.machine,
|
||||
@@ -1792,13 +1835,7 @@ export function createSimulationStore(seed = {}) {
|
||||
taskPaused: false,
|
||||
},
|
||||
runState: "running",
|
||||
activeLine: playback.activeLine,
|
||||
axisPose: playback.axisPose,
|
||||
kinsType: playback.kinsType,
|
||||
rtcpState: playback.rtcpState,
|
||||
programExecutionMotionIndex: playback.motionIndex,
|
||||
programExecutionSampleIndex: playback.sampleIndex,
|
||||
programRuntimeFeedback: playback.runtimeFeedback,
|
||||
...playbackPatch,
|
||||
programElapsedSeconds: playback.timing.elapsedSeconds,
|
||||
programRemainingSeconds: playback.timing.remainingSeconds,
|
||||
feed: {
|
||||
@@ -1815,6 +1852,7 @@ export function createSimulationStore(seed = {}) {
|
||||
setState({ operatorMessage: gate.operatorMessage });
|
||||
break;
|
||||
}
|
||||
const homeAxisPose = homeAxisPoseForState(state);
|
||||
if (state.taskHalRuntime?.loaded) {
|
||||
setState({
|
||||
machine: {
|
||||
@@ -1827,7 +1865,7 @@ export function createSimulationStore(seed = {}) {
|
||||
taskPaused: false,
|
||||
},
|
||||
runState: "idle",
|
||||
axisPose: initialAxisPose,
|
||||
axisPose: homeAxisPose,
|
||||
programRuntimeFeedback: null,
|
||||
operatorMessage: "task/HAL home requested",
|
||||
});
|
||||
@@ -1835,6 +1873,7 @@ export function createSimulationStore(seed = {}) {
|
||||
{ type: "EMC_JOINT_HOME", joint: -1 },
|
||||
], {
|
||||
operatorMessage: "task/HAL machine homed",
|
||||
preserveAxisPose: homeAxisPose,
|
||||
preserveMachine: {
|
||||
...state.machine,
|
||||
manualPanel: "manual",
|
||||
@@ -1854,7 +1893,7 @@ export function createSimulationStore(seed = {}) {
|
||||
taskPaused: false,
|
||||
},
|
||||
runState: "idle",
|
||||
axisPose: initialAxisPose,
|
||||
axisPose: homeAxisPose,
|
||||
programRuntimeFeedback: null,
|
||||
operatorMessage: "machine homed to fixture origin",
|
||||
});
|
||||
@@ -2125,6 +2164,7 @@ export function createSimulationStore(seed = {}) {
|
||||
state = {
|
||||
...derivedState,
|
||||
linuxCncParityMatrix: createLinuxCncParityMatrix(derivedState),
|
||||
linuxCncProcessMonitor: createLinuxCncProcessMonitor(derivedState),
|
||||
fullExecutionBoundary: createFullLinuxCncExecutionBoundary(derivedState),
|
||||
};
|
||||
notify();
|
||||
@@ -2954,6 +2994,183 @@ function createProgramValidationState(state = {}) {
|
||||
};
|
||||
}
|
||||
|
||||
function createLinuxCncProcessMonitor(state = {}) {
|
||||
const feedback = state.programRuntimeFeedback || {};
|
||||
const uiExecution = state.programUiExecution || createProgramUiExecution(state);
|
||||
const status = state.taskHalStatus || {};
|
||||
const ui = status.ui || {};
|
||||
const motion = status.motionStatus?.motion || {};
|
||||
const halPins = status.halSnapshot?.pins || {};
|
||||
const toolRuntime = state.toolRuntimeState || {};
|
||||
const toolDb = state.toolDbSimulation || {};
|
||||
const currentTool = toolRuntime.currentTool || toolRuntime.activeToolOffset || toolRuntime.pathTool || null;
|
||||
const path = state.programAxisPreviewPath || null;
|
||||
const previewTool = path?.samples?.find((sample) => sample?.tool)?.tool || null;
|
||||
const runtimePathTool = toolRuntime.pathTool || null;
|
||||
const pathTool = Number(runtimePathTool?.id || 0) > 0 || Number(runtimePathTool?.diameter || 0) > 0
|
||||
? runtimePathTool
|
||||
: previewTool;
|
||||
const sampleCount = Number(path?.sampleCount || path?.samples?.length || 0);
|
||||
const sampleIndex = clampNumber(
|
||||
Number(state.programExecutionSampleIndex ?? feedback.sampleIndex ?? 0),
|
||||
0,
|
||||
Math.max(sampleCount - 1, 0),
|
||||
);
|
||||
const motionCount = Number(state.programExecution?.summary?.motionEventCount || state.programExecution?.motion?.length || 0);
|
||||
const motionIndex = clampNumber(
|
||||
Number(state.programExecutionMotionIndex ?? feedback.motionIndex ?? 0),
|
||||
0,
|
||||
Math.max(motionCount - 1, 0),
|
||||
);
|
||||
const sourceLine = Number(feedback.line || state.activeLine || 0);
|
||||
const activeGcode = uiExecution?.statement || (sourceLine > 0
|
||||
? state.programLines?.[sourceLine - Number(state.programStartLine || 1)] || ""
|
||||
: "");
|
||||
const currentVelocity = Number(feedback.currentVelocityMmPerMin ?? state.feed?.currentVelocity ?? ui.currentVelocity ?? 0);
|
||||
const requestedVelocity = Number(feedback.requestedVelocityMmPerMin ?? motion.requestedVel * 60 ?? currentVelocity);
|
||||
const feedRate = Number(state.feed?.feedRate || currentVelocity || 0);
|
||||
const spindleCommandRpm = Number(state.spindle?.rpm || 0);
|
||||
const spindleActualRpm = state.spindle?.enabled
|
||||
? spindleCommandRpm * (Number(state.spindle?.override || 100) / 100)
|
||||
: 0;
|
||||
const toolChange = {
|
||||
toolInSpindle: Number(toolRuntime.toolInSpindle || toolDb.toolInSpindle || 0),
|
||||
toolFromPocket: Number(toolRuntime.toolFromPocket || toolDb.toolFromPocket || 0),
|
||||
currentPocket: Number(toolRuntime.currentPocket || toolDb.currentPocket || 0),
|
||||
preparedTool: Number(toolDb.preparedTool || 0),
|
||||
preparedPocket: Number(toolDb.preparedPocket || 0),
|
||||
activeToolNumber: Number(toolRuntime.activeToolNumber || pathTool?.id || currentTool?.toolNumber || 0),
|
||||
activePocket: Number(toolRuntime.activePocket || pathTool?.pocket || currentTool?.pocket || 0),
|
||||
diameter: Number(pathTool?.diameter ?? currentTool?.diameter ?? 0),
|
||||
lengthOffsetZ: Number(toolRuntime.kinematics?.toolOffsetZ ?? currentTool?.offset?.z ?? pathTool?.length ?? 0),
|
||||
activeOffsetApplied: Boolean(toolRuntime.activeOffsetApplied),
|
||||
iocontrol: {
|
||||
toolPrepare: Boolean(toolDb.iocontrol?.toolPrepare),
|
||||
toolPrepared: Boolean(toolDb.iocontrol?.toolPrepared),
|
||||
toolChange: Boolean(toolDb.iocontrol?.toolChange),
|
||||
toolChanged: Boolean(toolDb.iocontrol?.toolChanged),
|
||||
toolPrepNumber: Number(toolDb.iocontrol?.toolPrepNumber || 0),
|
||||
toolPrepPocket: Number(toolDb.iocontrol?.toolPrepPocket || 0),
|
||||
},
|
||||
emcioStatus: toolDb.emcioStatus?.status || "UNKNOWN",
|
||||
};
|
||||
|
||||
return {
|
||||
apiName: "web-rtcp-5axis-linuxcnc-process-monitor",
|
||||
semanticBoundary: "linuxcnc_task_motion_hal_interpreter_tool_status_monitor",
|
||||
sourceReferences: {
|
||||
task: "linuxcnc/src/emc/task/emctaskmain.cc",
|
||||
motion: "linuxcnc/src/emc/motion/control.c",
|
||||
interpreter: "linuxcnc/src/emc/rs274ngc",
|
||||
axisGui: "linuxcnc/src/emc/usr_intf/axis/scripts/axis.py",
|
||||
halPins: "linuxcnc/src/emc/usr_intf/halui.cc + src/emc/iotask/ioControl.cc",
|
||||
toolChange: "linuxcnc/src/emc/task/taskclass.cc + src/emc/tooldata/tooldata_common.cc",
|
||||
},
|
||||
control: {
|
||||
powerOn: Boolean(state.machine?.powerOn),
|
||||
estopActive: Boolean(state.machine?.estopActive),
|
||||
taskState: state.machine?.taskState || "estop-reset",
|
||||
taskMode: state.machine?.mode || "manual",
|
||||
interpState: state.machine?.interpState || "idle",
|
||||
runState: state.runState || "idle",
|
||||
allHomed: Boolean(state.machine?.allHomed),
|
||||
taskPaused: Boolean(state.machine?.taskPaused),
|
||||
buttonParityCount: 57,
|
||||
policy: state.linuxCncTaskPolicy || null,
|
||||
},
|
||||
path: {
|
||||
activeProgram: state.activeProgram || null,
|
||||
programSourceRel: state.programSourceRel || state.machineFileStaging?.selectedGcodeSourceRel || null,
|
||||
previewSource: path?.source || state.programValidation?.previewSource || state.programExecutionSourceMode,
|
||||
executionSource: feedback.sourceMode || state.programExecutionSourceMode,
|
||||
activeLine: sourceLine,
|
||||
sourceFile: uiExecution?.sourceFile || null,
|
||||
sourceLine: Number(uiExecution?.line || sourceLine || 0),
|
||||
activeGcode,
|
||||
uiExecution,
|
||||
motionIndex,
|
||||
motionCount,
|
||||
sampleIndex,
|
||||
sampleCount,
|
||||
elapsedSeconds: Number(state.programElapsedSeconds || feedback.timeSeconds || 0),
|
||||
remainingSeconds: Number(state.programRemainingSeconds || 0),
|
||||
queueDepth: Number(feedback.queueDepth || ui.motionQueueDepth || 0),
|
||||
activeDepth: Number(feedback.activeDepth || 0),
|
||||
lineExecution: state.programLineExecution?.[sourceLine] || null,
|
||||
},
|
||||
axes: {
|
||||
linearUnits: state.profile?.traj?.linearUnits || feedback.linearUnits || "mm",
|
||||
rotaryUnits: "deg",
|
||||
positionSource: feedback.sourceMode || state.frameSourceMode || "ui-state",
|
||||
dro: { ...(state.dro || {}) },
|
||||
joint: { ...pickExecutionAxes(state.axisPose || {}) },
|
||||
tcp: {
|
||||
x: Number(state.tcpPose?.x || 0),
|
||||
y: Number(state.tcpPose?.y || 0),
|
||||
z: Number(state.tcpPose?.z || 0),
|
||||
},
|
||||
distanceToGo: {
|
||||
x: Number(state.dro?.dtgX || 0),
|
||||
y: Number(state.dro?.dtgY || 0),
|
||||
z: Number(state.dro?.dtgZ || 0),
|
||||
scalar: Number(feedback.distanceToGo || 0),
|
||||
},
|
||||
toolAxisVector: { ...(state.toolAxisVector || {}) },
|
||||
kinsType: state.kinsType || "identity",
|
||||
rtcpState: state.rtcpState || "off",
|
||||
},
|
||||
spindle: {
|
||||
enabled: Boolean(state.spindle?.enabled),
|
||||
direction: state.spindle?.direction || "stop",
|
||||
commandRpm: spindleCommandRpm,
|
||||
actualRpm: spindleActualRpm,
|
||||
overridePercent: Number(state.spindle?.override || 0),
|
||||
halPins: {
|
||||
on: Number(halPins["spindle.0.on"]?.value ?? (state.spindle?.enabled ? 1 : 0)),
|
||||
forward: Number(halPins["spindle.0.forward"]?.value ?? (state.spindle?.direction === "forward" ? 1 : 0)),
|
||||
reverse: Number(halPins["spindle.0.reverse"]?.value ?? (state.spindle?.direction === "reverse" ? 1 : 0)),
|
||||
speedOut: Number(halPins["spindle.0.speed-out"]?.value ?? spindleActualRpm),
|
||||
},
|
||||
},
|
||||
feed: {
|
||||
currentVelocityMmPerMin: currentVelocity,
|
||||
requestedVelocityMmPerMin: requestedVelocity,
|
||||
cuttingVelocityMmPerMin: isCuttingMotion(feedback) ? currentVelocity : 0,
|
||||
feedRate,
|
||||
feedOverridePercent: Number(state.feed?.feedOverride || 0),
|
||||
rapidOverridePercent: Number(state.feed?.rapidOverride || 0),
|
||||
feedMode: feedback.feedMode || "units-per-minute",
|
||||
},
|
||||
coolant: {
|
||||
flood: Boolean(state.coolant?.flood),
|
||||
mist: Boolean(state.coolant?.mist),
|
||||
halPins: {
|
||||
flood: Number(halPins["iocontrol.0.coolant-flood"]?.value ?? (state.coolant?.flood ? 1 : 0)),
|
||||
mist: Number(halPins["iocontrol.0.coolant-mist"]?.value ?? (state.coolant?.mist ? 1 : 0)),
|
||||
},
|
||||
},
|
||||
toolChange,
|
||||
runtime: {
|
||||
interpreterReady: state.interpreterRuntimeReadiness?.loaded === true,
|
||||
kinematicsReady: state.kinematicsRuntimeReadiness?.loaded === true,
|
||||
taskHalReady: state.taskHalRuntimeReadiness?.taskRuntimeReady === true
|
||||
&& state.taskHalRuntimeReadiness?.motionRuntimeReady === true
|
||||
&& state.taskHalRuntimeReadiness?.halRuntimeReady === true,
|
||||
taskHalLoopActive: state.taskHalStatusLoop?.active === true,
|
||||
taskHalTickCount: Number(state.taskHalStatusLoop?.tickCount || 0),
|
||||
taskCycle: Number(feedback.taskCycle || ui.taskCycle || 0),
|
||||
servoCycle: Number(feedback.cycle || ui.servoCycle || 0),
|
||||
halChangedPinCount: Number(feedback.halChangedPinCount || ui.halChangedPinCount || 0),
|
||||
fallbackReason: state.taskHalFallbackReason || null,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
function isCuttingMotion(feedback = {}) {
|
||||
const type = String(feedback.type || "").toUpperCase();
|
||||
return type.includes("FEED") || type.includes("ARC") || type === "TASK_MOTION";
|
||||
}
|
||||
|
||||
function createRightSidebarEntranceState(state = {}, taskPolicy = createLinuxCncTaskPolicyStatus(state)) {
|
||||
const manualActive = state.machine?.mode === "manual" && state.machine?.manualPanel !== "jog";
|
||||
const jogActive = state.machine?.mode === "manual" && state.machine?.manualPanel === "jog";
|
||||
@@ -3276,12 +3493,25 @@ function applyTaskHalStatusPatch(state, status, operatorMessage, {
|
||||
? "jogging"
|
||||
: "idle";
|
||||
const runtimeFeedback = createTaskHalRuntimeFeedback(state, status, axisPose, activeLine);
|
||||
const taskHalSampleIndex = resolveRuntimeSampleIndexForLine(state, activeLine, runtimeFeedback.sampleIndex);
|
||||
const taskHalPlaybackPatch = applyProgramPlaybackUiPatch(state, {
|
||||
activeLine,
|
||||
axisPose,
|
||||
kinsType,
|
||||
rtcpState: rtcpStateFromKinsType(kinsType),
|
||||
motionIndex: runtimeFeedback.motionIndex,
|
||||
sampleIndex: taskHalSampleIndex,
|
||||
runtimeFeedback: {
|
||||
...runtimeFeedback,
|
||||
sampleIndex: taskHalSampleIndex,
|
||||
},
|
||||
});
|
||||
const loopActive = state.taskHalStatusLoop?.active === true
|
||||
&& loopSequence !== null
|
||||
&& Number(state.taskHalStatusLoop.sequence) === Number(loopSequence)
|
||||
&& (runState === "running" || runState === "mdi");
|
||||
const nextTickCount = loopActive ? Number(state.taskHalStatusLoop.tickCount || 0) + 1 : Number(state.taskHalStatusLoop?.tickCount || 0);
|
||||
const feedbackHistory = [runtimeFeedback, ...(state.programRuntimeFeedbackHistory || [])].slice(0, 100);
|
||||
const feedbackHistory = [taskHalPlaybackPatch.programRuntimeFeedback, ...(state.programRuntimeFeedbackHistory || [])].slice(0, 100);
|
||||
const lineStatus = runState === "complete"
|
||||
? "done"
|
||||
: runState === "running" || runState === "mdi"
|
||||
@@ -3293,10 +3523,7 @@ function applyTaskHalStatusPatch(state, status, operatorMessage, {
|
||||
taskHalExecutionPending: false,
|
||||
taskHalFallbackReason: null,
|
||||
pendingJogCommand: null,
|
||||
activeLine,
|
||||
axisPose,
|
||||
kinsType,
|
||||
rtcpState: rtcpStateFromKinsType(kinsType),
|
||||
...taskHalPlaybackPatch,
|
||||
programExecutionSourceMode: "linuxcnc-task-motion-hal-wasm",
|
||||
machine: {
|
||||
...state.machine,
|
||||
@@ -3325,9 +3552,8 @@ function applyTaskHalStatusPatch(state, status, operatorMessage, {
|
||||
...state.feed,
|
||||
currentVelocity,
|
||||
},
|
||||
programRuntimeFeedback: runtimeFeedback,
|
||||
programRuntimeFeedbackHistory: feedbackHistory,
|
||||
programLineExecution: createProgramLineExecutionPatch(state.programLineExecution, runtimeFeedback, {
|
||||
programLineExecution: createProgramLineExecutionPatch(state.programLineExecution, taskHalPlaybackPatch.programRuntimeFeedback, {
|
||||
status: lineStatus,
|
||||
source: "linuxcnc-task-motion-hal-wasm",
|
||||
}),
|
||||
@@ -3494,6 +3720,195 @@ function createTaskHalRuntimeFeedback(state, status, axisPose, activeLine) {
|
||||
};
|
||||
}
|
||||
|
||||
function resolveRuntimeSampleIndexForLine(state = {}, activeLine, fallbackSampleIndex = 0) {
|
||||
const samples = state.programAxisPreviewPath?.samples;
|
||||
if (!Array.isArray(samples) || samples.length === 0) {
|
||||
return Number(fallbackSampleIndex) || 0;
|
||||
}
|
||||
const line = Number(activeLine);
|
||||
if (!Number.isFinite(line)) {
|
||||
return clampNumber(fallbackSampleIndex, 0, samples.length - 1);
|
||||
}
|
||||
const current = clampNumber(state.programExecutionSampleIndex || 0, 0, samples.length - 1);
|
||||
for (let index = current; index < samples.length; index += 1) {
|
||||
if (Number(samples[index]?.line) >= line) return index;
|
||||
}
|
||||
return samples.length - 1;
|
||||
}
|
||||
|
||||
function applyProgramPlaybackUiPatch(state = {}, {
|
||||
activeLine,
|
||||
axisPose,
|
||||
kinsType,
|
||||
rtcpState,
|
||||
motionIndex,
|
||||
sampleIndex,
|
||||
runtimeFeedback,
|
||||
} = {}) {
|
||||
const sample = currentProgramPathSample(state, sampleIndex);
|
||||
const sampleAxisPose = axisPoseFromProgramPathSample(sample, axisPose || state.axisPose, state.profile);
|
||||
const sampleKinsType = sample?.activeKinematics
|
||||
? normalizeSampleKinsType(state, sample.activeKinematics)
|
||||
: kinsType;
|
||||
const sampleLine = Number(sample?.line || activeLine || state.activeLine || 0);
|
||||
const sampleMotionIndex = Number.isFinite(Number(sample?.segmentIndex))
|
||||
? Number(sample.segmentIndex)
|
||||
: Number(motionIndex || 0);
|
||||
const sampleSampleIndex = Number.isFinite(Number(sample?.sampleIndex))
|
||||
? Number(sample.sampleIndex)
|
||||
: Number(sampleIndex || 0);
|
||||
const toolAxisVector = toolAxisVectorFromSample(sample, state.toolAxisVector);
|
||||
const enrichedFeedback = enrichRuntimeFeedbackWithSample(runtimeFeedback, sample, {
|
||||
...state,
|
||||
activeLine: sampleLine,
|
||||
axisPose: sampleAxisPose,
|
||||
kinsType: sampleKinsType || state.kinsType,
|
||||
toolAxisVector,
|
||||
});
|
||||
const patchState = {
|
||||
...state,
|
||||
activeLine: sampleLine,
|
||||
axisPose: sampleAxisPose,
|
||||
kinsType: sampleKinsType || state.kinsType,
|
||||
rtcpState: sampleKinsType ? rtcpStateFromKinsType(sampleKinsType) : rtcpState || state.rtcpState,
|
||||
toolAxisVector,
|
||||
programExecutionMotionIndex: sampleMotionIndex,
|
||||
programExecutionSampleIndex: sampleSampleIndex,
|
||||
programRuntimeFeedback: enrichedFeedback,
|
||||
};
|
||||
return {
|
||||
activeLine: patchState.activeLine,
|
||||
axisPose: patchState.axisPose,
|
||||
kinsType: patchState.kinsType,
|
||||
rtcpState: patchState.rtcpState,
|
||||
toolAxisVector,
|
||||
programExecutionMotionIndex: patchState.programExecutionMotionIndex,
|
||||
programExecutionSampleIndex: patchState.programExecutionSampleIndex,
|
||||
programRuntimeFeedback: enrichedFeedback,
|
||||
programUiExecution: createProgramUiExecution(patchState),
|
||||
};
|
||||
}
|
||||
|
||||
function createProgramUiExecution(state = {}) {
|
||||
const sample = currentProgramPathSample(state, state.programExecutionSampleIndex);
|
||||
const feedback = state.programRuntimeFeedback || {};
|
||||
const sampleCount = Number(state.programAxisPreviewPath?.sampleCount || state.programAxisPreviewPath?.samples?.length || 0);
|
||||
const lineExecutionTrace = state.programAxisPreviewPath?.lineExecutionTrace || [];
|
||||
const traceEntry = sample
|
||||
? lineExecutionTrace.find((entry) => (
|
||||
Number(entry.segmentIndex) === Number(sample.segmentIndex)
|
||||
&& entry.sourceFile === sample.sourceFile
|
||||
&& Number(entry.line) === Number(sample.line)
|
||||
)) || null
|
||||
: null;
|
||||
const gcodeSteps = state.programAxisPreviewPath?.gcodeExecutionProcess?.executionSteps || [];
|
||||
const gcodeStep = traceEntry
|
||||
? gcodeSteps.find((step) => Number(step.result?.traceExecutionIndex) === Number(traceEntry.executionIndex)) || null
|
||||
: null;
|
||||
const sourceFile = sample?.sourceFile || traceEntry?.sourceFile || feedback.sourceFile || null;
|
||||
const sourceLine = Number(sample?.line || traceEntry?.line || feedback.line || state.activeLine || 0);
|
||||
const sampleIndex = Number(sample?.sampleIndex ?? state.programExecutionSampleIndex ?? 0);
|
||||
return {
|
||||
apiName: "web-rtcp-5axis-ui-gcode-live-execution",
|
||||
status: state.runState || "idle",
|
||||
source: sample
|
||||
? "programAxisPreviewPath.samples"
|
||||
: feedback.sourceMode || state.programExecutionSourceMode || "ui-state",
|
||||
samplePeriodMs: Number(state.programAxisPreviewPath?.samplePeriodMs || 0),
|
||||
sampleIndex,
|
||||
sampleCount,
|
||||
executedSampleCount: sampleCount > 0 ? Math.min(sampleIndex + 1, sampleCount) : 0,
|
||||
timeMs: Number(sample?.timeMs ?? feedback.timeSeconds * 1000 ?? 0),
|
||||
activeProgram: state.activeProgram || null,
|
||||
sourceFile,
|
||||
line: sourceLine,
|
||||
statement: sample?.statement || traceEntry?.statement || gcodeStep?.statement || "",
|
||||
operation: traceEntry?.operation || gcodeStep?.result?.operation || null,
|
||||
executionIndex: traceEntry?.executionIndex ?? null,
|
||||
gcodeStepIndex: gcodeStep?.stepIndex ?? null,
|
||||
segmentIndex: sample?.segmentIndex ?? traceEntry?.segmentIndex ?? null,
|
||||
motionType: sample?.motionType || traceEntry?.motionType || feedback.motionType || feedback.type || null,
|
||||
activeKinematics: sample?.activeKinematics || traceEntry?.activeKinematicsAfter || state.kinsType,
|
||||
joint: sample?.joint || pickExecutionAxes(state.axisPose || {}),
|
||||
tcp: sample?.tcp || {
|
||||
x: Number(state.tcpPose?.x || state.axisPose?.x || 0),
|
||||
y: Number(state.tcpPose?.y || state.axisPose?.y || 0),
|
||||
z: Number(state.tcpPose?.z || state.axisPose?.z || 0),
|
||||
},
|
||||
toolAxis: sample?.toolAxis || toolAxisSampleFromVector(state.toolAxisVector),
|
||||
tool: sample?.tool || currentPathTool(state),
|
||||
machineState: sample?.machineState || null,
|
||||
semanticBoundary: "ui_updates_from_real_expanded_linuxcnc_gcode_sample_stream",
|
||||
};
|
||||
}
|
||||
|
||||
function currentProgramPathSample(state = {}, sampleIndex = 0) {
|
||||
const samples = state.programAxisPreviewPath?.samples;
|
||||
if (!Array.isArray(samples) || samples.length === 0) return null;
|
||||
const index = clampNumber(sampleIndex, 0, samples.length - 1);
|
||||
return samples[index] || null;
|
||||
}
|
||||
|
||||
function axisPoseFromProgramPathSample(sample, fallbackPose = {}, profile = defaultProfile) {
|
||||
const joint = sample?.joint || {};
|
||||
return clampAxisPoseToProfile({
|
||||
...fallbackPose,
|
||||
x: numberOrFallback(joint.x, fallbackPose.x, 0),
|
||||
y: numberOrFallback(joint.y, fallbackPose.y, 0),
|
||||
z: numberOrFallback(joint.z, fallbackPose.z, 0),
|
||||
b: numberOrFallback(joint.b, fallbackPose.b, 0),
|
||||
c: numberOrFallback(joint.c, fallbackPose.c, 0),
|
||||
}, profile || defaultProfile);
|
||||
}
|
||||
|
||||
function normalizeSampleKinsType(state = {}, value) {
|
||||
if (value === "tcp-xyzbc" || value === "tcp-xyzac" || value === "identity" || value === "userk") {
|
||||
return value;
|
||||
}
|
||||
if (value === "tcp") return tcpKinsTypeForProfile(state.profile) || value;
|
||||
return value || null;
|
||||
}
|
||||
|
||||
function toolAxisVectorFromSample(sample, fallbackVector = {}) {
|
||||
const axis = sample?.toolAxis || {};
|
||||
return {
|
||||
x: numberOrFallback(axis.x, axis.i, fallbackVector.x, 0),
|
||||
y: numberOrFallback(axis.y, axis.j, fallbackVector.y, 0),
|
||||
z: numberOrFallback(axis.z, axis.k, fallbackVector.z, 1),
|
||||
};
|
||||
}
|
||||
|
||||
function toolAxisSampleFromVector(vector = {}) {
|
||||
return {
|
||||
i: Number(vector.x || 0),
|
||||
j: Number(vector.y || 0),
|
||||
k: Number(vector.z ?? 1),
|
||||
};
|
||||
}
|
||||
|
||||
function enrichRuntimeFeedbackWithSample(feedback = {}, sample = null, state = {}) {
|
||||
if (!sample) return feedback;
|
||||
const tcp = sample.tcp || {
|
||||
x: Number(state.tcpPose?.x ?? state.axisPose?.x ?? feedback?.axisPose?.x ?? 0),
|
||||
y: Number(state.tcpPose?.y ?? state.axisPose?.y ?? feedback?.axisPose?.y ?? 0),
|
||||
z: Number(state.tcpPose?.z ?? state.axisPose?.z ?? feedback?.axisPose?.z ?? 0),
|
||||
};
|
||||
return {
|
||||
...(feedback || {}),
|
||||
sampleIndex: Number(sample.sampleIndex || 0),
|
||||
motionIndex: Number(sample.segmentIndex || feedback?.motionIndex || 0),
|
||||
line: Number(sample.line || feedback?.line || 0),
|
||||
sourceFile: sample.sourceFile || feedback?.sourceFile || null,
|
||||
statement: sample.statement || feedback?.statement || "",
|
||||
motionType: sample.motionType || feedback?.motionType || null,
|
||||
activeKinematics: sample.activeKinematics || feedback?.activeKinematics || state.kinsType,
|
||||
axisPose: axisPoseFromProgramPathSample(sample, state.axisPose || feedback?.axisPose || {}, state.profile),
|
||||
tcp,
|
||||
toolAxis: sample.toolAxis || feedback?.toolAxis || null,
|
||||
machineState: sample.machineState || feedback?.machineState || null,
|
||||
};
|
||||
}
|
||||
|
||||
function createProgramLineExecutionPatch(previous = {}, feedback = null, {
|
||||
status = "running",
|
||||
source = null,
|
||||
@@ -3637,6 +4052,24 @@ function clampAxisPoseToProfile(axisPose, profile = defaultProfile) {
|
||||
return next;
|
||||
}
|
||||
|
||||
function homeAxisPoseForState(state = {}) {
|
||||
if (state.profile?.id === "xyzac-trt" || state.profile?.id === "xyzbc-trt") {
|
||||
return clampAxisPoseToProfile({
|
||||
...initialAxisPose,
|
||||
x: 43,
|
||||
y: -32.15,
|
||||
z: -11.306,
|
||||
}, state.profile);
|
||||
}
|
||||
const pose = { ...initialAxisPose };
|
||||
for (const joint of state.profile?.jointConfig || []) {
|
||||
const axis = String(joint.axis || "").toLowerCase();
|
||||
if (!axis) continue;
|
||||
pose[axis] = Number(joint.home || 0);
|
||||
}
|
||||
return clampAxisPoseToProfile(pose, state.profile || defaultProfile);
|
||||
}
|
||||
|
||||
function executeMdiCommand(state, rawCommand) {
|
||||
const command = normalizeMdiCommand(rawCommand);
|
||||
if (!command) {
|
||||
@@ -3937,6 +4370,61 @@ function nextProgramRuntimeSamplePlayback(state, step) {
|
||||
};
|
||||
}
|
||||
|
||||
const pathSamples = state.programAxisPreviewPath?.samples;
|
||||
if (Array.isArray(pathSamples) && pathSamples.length > 0) {
|
||||
const sampleIndex = Math.min(
|
||||
Number(state.programExecutionSampleIndex || 0) + Math.max(Number(step) || 1, 1),
|
||||
pathSamples.length - 1,
|
||||
);
|
||||
const sample = pathSamples[sampleIndex];
|
||||
const motionIndex = Number.isFinite(Number(sample?.segmentIndex)) ? Number(sample.segmentIndex) : 0;
|
||||
const axisPose = axisPoseFromProgramPathSample(sample, state.axisPose, state.profile);
|
||||
const kinsType = sample?.activeKinematics
|
||||
? normalizeSampleKinsType(state, sample.activeKinematics)
|
||||
: state.kinsType;
|
||||
const elapsedSeconds = Number(sample?.timeMs || 0) / 1000;
|
||||
const currentVelocity = Number(sample?.machineState?.feed?.actualMmPerMin || sample?.feed || 0);
|
||||
const runtimeFeedback = {
|
||||
apiName: "web-rtcp-5axis-program-runtime-feedback",
|
||||
sourceMode: "web-axis-source-execution-expanded-ngcgui-subroutines",
|
||||
semanticBoundary: "linuxcnc_xyzbc_switchkins_sample_stream_feedback",
|
||||
sampleIndex,
|
||||
motionIndex,
|
||||
sourceFile: sample?.sourceFile || null,
|
||||
statement: sample?.statement || "",
|
||||
line: sample?.line || state.activeLine,
|
||||
type: sample?.motionType || null,
|
||||
motionType: sample?.motionType || null,
|
||||
linearUnits: state.profile?.traj?.linearUnits || "mm",
|
||||
timeSeconds: elapsedSeconds,
|
||||
axisPose,
|
||||
currentVelocityMmPerMin: currentVelocity,
|
||||
requestedVelocityMmPerMin: currentVelocity,
|
||||
distanceToGo: sampleIndex >= pathSamples.length - 1 ? 0 : 1,
|
||||
dtg: { x: 0, y: 0, z: 0 },
|
||||
queueDepth: 0,
|
||||
activeDepth: sampleIndex >= pathSamples.length - 1 ? 0 : 1,
|
||||
cycle: sampleIndex,
|
||||
};
|
||||
return {
|
||||
motionIndex,
|
||||
sampleIndex,
|
||||
activeLine: sample?.line || state.activeLine,
|
||||
axisPose,
|
||||
kinsType,
|
||||
rtcpState: rtcpStateFromKinsType(kinsType),
|
||||
timing: {
|
||||
elapsedSeconds,
|
||||
remainingSeconds: Math.max(((pathSamples.length - 1) * Number(state.programAxisPreviewPath?.samplePeriodMs || 0)) / 1000 - elapsedSeconds, 0),
|
||||
currentVelocity,
|
||||
segmentDurationSeconds: Number(state.programAxisPreviewPath?.samplePeriodMs || 0) / 1000,
|
||||
segmentDistanceMm: 0,
|
||||
},
|
||||
runtimeFeedback,
|
||||
complete: sampleIndex >= pathSamples.length - 1,
|
||||
};
|
||||
}
|
||||
|
||||
const playback = nextProgramPlayback(state, step);
|
||||
return {
|
||||
...playback,
|
||||
|
||||
@@ -16,6 +16,7 @@ const CAMERA_PRESETS = {
|
||||
};
|
||||
const MAX_TOOLPATH_POINTS = Number.POSITIVE_INFINITY;
|
||||
const EMPTY_GEOMETRY = new THREE.BufferGeometry().setFromPoints([]);
|
||||
const LOCAL_TOOL_AXIS = new THREE.Vector3(0, 0, 1);
|
||||
|
||||
export function renderFiveAxisScene(canvas, state) {
|
||||
let preview = scenes.get(canvas);
|
||||
@@ -134,6 +135,7 @@ function createScene(canvas) {
|
||||
toolMarker,
|
||||
toolAxis,
|
||||
currentToolhead: new THREE.Vector3(),
|
||||
currentToolGlyphAxis: new THREE.Vector3(0, 0, 1),
|
||||
currentVismachModelState: null,
|
||||
lastSelectedView: null,
|
||||
lastCameraRevision: null,
|
||||
@@ -254,6 +256,7 @@ function exposePreviewDataset(canvas, state, preview) {
|
||||
canvas.dataset.threeLinearUnits = linearUnitsLabel(resolveSceneLinearUnits(state));
|
||||
canvas.dataset.threeLinearUnitScaleToMeters = String(linearUnitsToMetersFactor(resolveSceneLinearUnits(state)));
|
||||
canvas.dataset.threeToolAxis = JSON.stringify(toRoundedVector(state.toolAxisVector));
|
||||
canvas.dataset.threeToolGlyphAxis = JSON.stringify(toRoundedVector(preview.toolGlyphAxis || preview.currentToolGlyphAxis || state.toolAxisVector));
|
||||
canvas.dataset.threeTcpPose = JSON.stringify(toRoundedPose(state.tcpPose));
|
||||
canvas.dataset.threeRtcpState = state.rtcpState;
|
||||
canvas.dataset.threeSelectedView = state.preview.selectedView;
|
||||
@@ -360,13 +363,13 @@ function createMachineReferenceModel() {
|
||||
new THREE.MeshBasicMaterial({ color: 0xf1f5f9 }),
|
||||
);
|
||||
holderBody.rotation.x = Math.PI / 2;
|
||||
holderBody.position.z = 0.032;
|
||||
holderBody.position.z = 0.046;
|
||||
const cutter = new THREE.Mesh(
|
||||
new THREE.ConeGeometry(0.006, 0.025, 18),
|
||||
new THREE.MeshBasicMaterial({ color: 0xfff176 }),
|
||||
);
|
||||
cutter.rotation.x = Math.PI;
|
||||
cutter.position.z = 0.008;
|
||||
cutter.rotation.x = -Math.PI / 2;
|
||||
cutter.position.z = 0.0125;
|
||||
toolHolder.add(holderBody, cutter);
|
||||
|
||||
toolOffsetAxis.add(toolHolder);
|
||||
@@ -426,14 +429,14 @@ function createAxisReferencePreviewModel() {
|
||||
new THREE.ConeGeometry(0.0017, 0.0048, 4),
|
||||
new THREE.MeshBasicMaterial({ color: 0xe7eef7 }),
|
||||
);
|
||||
cone.rotation.x = Math.PI;
|
||||
cone.position.z = 0.0047;
|
||||
cone.rotation.x = -Math.PI / 2;
|
||||
cone.position.z = 0.0024;
|
||||
const holder = new THREE.Mesh(
|
||||
new THREE.CylinderGeometry(0.0011, 0.0011, 0.0065, 8),
|
||||
new THREE.MeshBasicMaterial({ color: 0xbfc8d0 }),
|
||||
);
|
||||
holder.rotation.x = Math.PI / 2;
|
||||
holder.position.z = 0.008;
|
||||
holder.position.z = 0.00805;
|
||||
tool.add(cone, holder);
|
||||
|
||||
root.add(xAxis, yAxis, zAxis, dimensions, tool, ...labels);
|
||||
@@ -576,7 +579,10 @@ function updateMachineReferenceModel(preview, state, toolPosition, axisReference
|
||||
preview.axisReference.root.visible = axisReferenceMode;
|
||||
if (axisReferenceMode) {
|
||||
const referenceToolPosition = new THREE.Vector3(0, 0, 0.006);
|
||||
const toolVector = toToolVector(state.toolAxisVector);
|
||||
preview.axisReference.tool.position.copy(referenceToolPosition);
|
||||
alignToolGlyphToAxis(preview.axisReference.tool, toolVector);
|
||||
preview.currentToolGlyphAxis.copy(toolVector);
|
||||
}
|
||||
}
|
||||
if (axisReferenceMode) {
|
||||
@@ -601,7 +607,17 @@ function updateMachineReferenceModel(preview, state, toolPosition, axisReference
|
||||
|
||||
const tcpPosition = toolPosition || toPreviewVector(state.tcpPose || state.axisPose, state);
|
||||
const toolVector = toToolVector(state.toolAxisVector);
|
||||
model.toolHolder.lookAt(tcpPosition.clone().add(toolVector));
|
||||
model.toolHolder.position.copy(tcpPosition);
|
||||
alignToolGlyphToAxis(model.toolHolder, toolVector);
|
||||
preview.currentToolGlyphAxis.copy(toolVector);
|
||||
}
|
||||
|
||||
function alignToolGlyphToAxis(object, toolVector) {
|
||||
const axis = toolVector.clone().normalize();
|
||||
if (!Number.isFinite(axis.x) || !Number.isFinite(axis.y) || !Number.isFinite(axis.z) || axis.lengthSq() === 0) {
|
||||
axis.copy(LOCAL_TOOL_AXIS);
|
||||
}
|
||||
object.quaternion.setFromUnitVectors(LOCAL_TOOL_AXIS, axis);
|
||||
}
|
||||
|
||||
function updateLineGeometry(line, points) {
|
||||
@@ -745,6 +761,14 @@ function buildFixturePreviewPoints(pointCount, tcpPosition) {
|
||||
}
|
||||
|
||||
function executionToolPosition(state, previewPoints) {
|
||||
const uiTcp = state.programUiExecution?.tcp;
|
||||
if (uiTcp && hasLinearAxes(uiTcp)) {
|
||||
return vectorFromAxes(uiTcp, state, state.programRuntimeFeedback?.linearUnits || "mm");
|
||||
}
|
||||
const feedbackTcp = state.programRuntimeFeedback?.tcp;
|
||||
if (feedbackTcp && hasLinearAxes(feedbackTcp)) {
|
||||
return vectorFromAxes(feedbackTcp, state, state.programRuntimeFeedback?.linearUnits || "mm");
|
||||
}
|
||||
const feedbackAxes = state.programRuntimeFeedback?.axisPose || state.programRuntimeFeedback;
|
||||
if (feedbackAxes && hasLinearAxes(feedbackAxes)) {
|
||||
return vectorFromAxes(feedbackAxes, state, state.programRuntimeFeedback?.linearUnits);
|
||||
@@ -811,7 +835,7 @@ function previewSourceMode(state) {
|
||||
}
|
||||
|
||||
function toolpathPreviewSource(state) {
|
||||
if (state.programAxisPreviewPath?.source === "web-axis-preview-expanded-ngcgui-subroutines") {
|
||||
if (isAxisReferencePreview(state)) {
|
||||
return "axis_preview_expanded_ngcgui_subroutines";
|
||||
}
|
||||
if (state.programExecution?.sourceMode === "linuxcnc-interpreter-wasm") {
|
||||
@@ -824,7 +848,9 @@ function toolpathPreviewSource(state) {
|
||||
}
|
||||
|
||||
function isAxisReferencePreview(state) {
|
||||
return state.programAxisPreviewPath?.source === "web-axis-preview-expanded-ngcgui-subroutines";
|
||||
return state.programAxisPreviewPath?.source === "web-axis-preview-expanded-ngcgui-subroutines"
|
||||
|| state.programAxisPreviewPath?.source === "web-axis-source-execution-expanded-ngcgui-subroutines"
|
||||
|| Boolean(state.programAxisPreviewPath?.gcodeExecutionProcess);
|
||||
}
|
||||
|
||||
function toolExecutionTraceSource(state) {
|
||||
|
||||
Reference in New Issue
Block a user