提交 xyzbc-trt 界面与验证更新
This commit is contained in:
@@ -40,7 +40,10 @@ export function renderFiveAxisScene(canvas, state) {
|
||||
return;
|
||||
}
|
||||
|
||||
const pointCount = geometryPointCount(preview.previewPath.geometry);
|
||||
const axisReferenceMode = isAxisReferencePreview(state);
|
||||
const pointCount = axisReferenceMode
|
||||
? Number(state.programAxisPreviewPath?.sampleCount || 0)
|
||||
: geometryPointCount(preview.previewPath.geometry);
|
||||
const executedPointCount = geometryPointCount(preview.executedPath.geometry);
|
||||
exposePreviewDataset(canvas, state, {
|
||||
pointCount,
|
||||
@@ -52,17 +55,19 @@ export function renderFiveAxisScene(canvas, state) {
|
||||
sceneObjectCount: countSceneObjects(preview.scene),
|
||||
toolhead: preview.currentToolhead,
|
||||
renderer: "webgl",
|
||||
sceneMode: "program-preview-and-tool-execution",
|
||||
machineReferenceModel: "webgl-five-axis-reference",
|
||||
sceneMode: axisReferenceMode ? "linuxcnc-axis-source-preview" : "program-preview-and-tool-execution",
|
||||
machineReferenceModel: axisReferenceMode ? "linuxcnc-axis-preview-reference" : "webgl-five-axis-reference",
|
||||
cameraControls: preview.controls.enabled,
|
||||
toolExecutionMarker: preview.toolMarker.visible,
|
||||
toolAxisMarker: preview.toolAxis.visible,
|
||||
pathFitBounds: preview.pathFitBoundsReady,
|
||||
pathBounds: computePointBoundsFromGeometryGroups([
|
||||
preview.previewPath.geometry,
|
||||
preview.executedPath.geometry,
|
||||
preview.currentSegmentPath.geometry,
|
||||
]),
|
||||
pathBounds: axisReferenceMode
|
||||
? summarizeBounds(computePointBounds(buildProgramPreviewPoints(state)))
|
||||
: computePointBoundsFromGeometryGroups([
|
||||
preview.previewPath.geometry,
|
||||
preview.executedPath.geometry,
|
||||
preview.currentSegmentPath.geometry,
|
||||
]),
|
||||
vismachModel: preview.currentVismachModelState,
|
||||
});
|
||||
}
|
||||
@@ -86,15 +91,18 @@ function createScene(canvas) {
|
||||
|
||||
const scene = new THREE.Scene();
|
||||
const camera = new THREE.PerspectiveCamera(42, 1, 0.001, 10);
|
||||
camera.up.set(0, 0, 1);
|
||||
|
||||
const machineModel = createMachineReferenceModel();
|
||||
const axisReference = createAxisReferencePreviewModel();
|
||||
scene.add(machineModel.root);
|
||||
scene.add(axisReference.root);
|
||||
|
||||
const previewPath = createLine(0x808892, 0.56);
|
||||
const feedPath = createLine(0x4fb3ff, 0.92);
|
||||
const previewPath = createLine(0xffffff, 0.9);
|
||||
const feedPath = createSegmentLine(0x00a8a8, 0.92);
|
||||
const executedPath = createLine(0x1ffff4, 1);
|
||||
const rapidPath = createLine(0xffb13b, 0.82);
|
||||
const arcPath = createLine(0xd7ff62, 0.95);
|
||||
const rapidPath = createSegmentLine(0x00a8a8, 0.92);
|
||||
const arcPath = createSegmentLine(0xffffff, 0.95);
|
||||
const currentSegmentPath = createLine(0xff4fd8, 1);
|
||||
const toolMarker = new THREE.Mesh(
|
||||
new THREE.SphereGeometry(0.0065, 18, 12),
|
||||
@@ -122,6 +130,7 @@ function createScene(canvas) {
|
||||
arcPath,
|
||||
currentSegmentPath,
|
||||
machineModel,
|
||||
axisReference,
|
||||
toolMarker,
|
||||
toolAxis,
|
||||
currentToolhead: new THREE.Vector3(),
|
||||
@@ -288,6 +297,17 @@ function createLine(color, opacity) {
|
||||
);
|
||||
}
|
||||
|
||||
function createSegmentLine(color, opacity) {
|
||||
return new THREE.LineSegments(
|
||||
EMPTY_GEOMETRY.clone(),
|
||||
new THREE.LineBasicMaterial({
|
||||
color,
|
||||
transparent: opacity < 1,
|
||||
opacity,
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function createMachineReferenceModel() {
|
||||
const root = new THREE.Group();
|
||||
root.name = "five-axis-machine-reference";
|
||||
@@ -370,6 +390,104 @@ function createMachineReferenceModel() {
|
||||
};
|
||||
}
|
||||
|
||||
function createAxisReferencePreviewModel() {
|
||||
const root = new THREE.Group();
|
||||
root.name = "axis-native-preview-reference";
|
||||
root.visible = false;
|
||||
|
||||
const zLift = 0.0004;
|
||||
const xAxis = createStaticLine([
|
||||
new THREE.Vector3(-0.024, 0, zLift),
|
||||
new THREE.Vector3(0.036, 0, zLift),
|
||||
], 0x00ff00);
|
||||
const yAxis = createStaticLine([
|
||||
new THREE.Vector3(0, -0.024, zLift),
|
||||
new THREE.Vector3(0, 0.036, zLift),
|
||||
], 0xff2020);
|
||||
const zAxis = createStaticLine([
|
||||
new THREE.Vector3(0, 0, 0),
|
||||
new THREE.Vector3(0, 0, 0.032),
|
||||
], 0x3030ff);
|
||||
|
||||
const dimensions = createDimensionLines();
|
||||
const labels = [
|
||||
createTextSprite("X", 0x00ff00, new THREE.Vector3(0.039, 0, zLift), 0.0034),
|
||||
createTextSprite("Y", 0xff2020, new THREE.Vector3(0, 0.039, zLift), 0.0034),
|
||||
createTextSprite("Z", 0x3030ff, new THREE.Vector3(0, 0, 0.032), 0.0034),
|
||||
createTextSprite("60.0", 0xff7070, new THREE.Vector3(0, -0.0355, zLift), 0.0026),
|
||||
createTextSprite("60.0", 0xff7070, new THREE.Vector3(-0.0355, 0, zLift), 0.0026),
|
||||
createTextSprite("30.0", 0xff7070, new THREE.Vector3(-0.028, 0.014, zLift), 0.0026),
|
||||
createTextSprite("30.0", 0xff7070, new THREE.Vector3(-0.014, -0.028, zLift), 0.0026),
|
||||
];
|
||||
|
||||
const tool = new THREE.Group();
|
||||
tool.name = "axis-native-tool-glyph";
|
||||
const cone = new THREE.Mesh(
|
||||
new THREE.ConeGeometry(0.0017, 0.0048, 4),
|
||||
new THREE.MeshBasicMaterial({ color: 0xe7eef7 }),
|
||||
);
|
||||
cone.rotation.x = Math.PI;
|
||||
cone.position.z = 0.0047;
|
||||
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;
|
||||
tool.add(cone, holder);
|
||||
|
||||
root.add(xAxis, yAxis, zAxis, dimensions, tool, ...labels);
|
||||
return {
|
||||
root,
|
||||
tool,
|
||||
};
|
||||
}
|
||||
|
||||
function createDimensionLines() {
|
||||
const group = new THREE.Group();
|
||||
group.name = "axis-native-preview-dimensions";
|
||||
const z = 0.0002;
|
||||
const lines = [
|
||||
[new THREE.Vector3(-0.030, -0.033, z), new THREE.Vector3(0.030, -0.033, z)],
|
||||
[new THREE.Vector3(-0.030, -0.0355, z), new THREE.Vector3(-0.030, -0.0305, z)],
|
||||
[new THREE.Vector3(0.030, -0.0355, z), new THREE.Vector3(0.030, -0.0305, z)],
|
||||
[new THREE.Vector3(-0.033, -0.030, z), new THREE.Vector3(-0.033, 0.030, z)],
|
||||
[new THREE.Vector3(-0.0355, -0.030, z), new THREE.Vector3(-0.0305, -0.030, z)],
|
||||
[new THREE.Vector3(-0.0355, 0.030, z), new THREE.Vector3(-0.0305, 0.030, z)],
|
||||
[new THREE.Vector3(-0.030, 0.030, z), new THREE.Vector3(0, 0.030, z)],
|
||||
[new THREE.Vector3(-0.030, -0.030, z), new THREE.Vector3(-0.030, 0, z)],
|
||||
];
|
||||
for (const [start, end] of lines) {
|
||||
group.add(createStaticLine([start, end], 0xff3030));
|
||||
}
|
||||
return group;
|
||||
}
|
||||
|
||||
function createTextSprite(text, color, position, height) {
|
||||
const canvas = document.createElement("canvas");
|
||||
canvas.width = 192;
|
||||
canvas.height = 64;
|
||||
const ctx = canvas.getContext("2d");
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
ctx.font = "32px Courier New, monospace";
|
||||
ctx.textAlign = "center";
|
||||
ctx.textBaseline = "middle";
|
||||
ctx.fillStyle = `#${color.toString(16).padStart(6, "0")}`;
|
||||
ctx.fillText(text, canvas.width / 2, canvas.height / 2);
|
||||
const texture = new THREE.CanvasTexture(canvas);
|
||||
texture.needsUpdate = true;
|
||||
const material = new THREE.SpriteMaterial({
|
||||
map: texture,
|
||||
transparent: true,
|
||||
depthTest: false,
|
||||
depthWrite: false,
|
||||
});
|
||||
const sprite = new THREE.Sprite(material);
|
||||
sprite.position.copy(position);
|
||||
sprite.scale.set(height * 3, height, 1);
|
||||
return sprite;
|
||||
}
|
||||
|
||||
function createStaticLine(points, color) {
|
||||
return new THREE.Line(
|
||||
new THREE.BufferGeometry().setFromPoints(points),
|
||||
@@ -378,6 +496,7 @@ function createStaticLine(points, color) {
|
||||
}
|
||||
|
||||
function updateToolpathPreview(preview, state) {
|
||||
const axisReferenceMode = isAxisReferencePreview(state);
|
||||
const previewPoints = buildProgramPreviewPoints(state);
|
||||
const executedPoints = buildExecutedProgramPoints(state, previewPoints);
|
||||
const rapidPoints = buildRapidPreviewPoints(state);
|
||||
@@ -395,14 +514,24 @@ function updateToolpathPreview(preview, state) {
|
||||
state.programExecutionSampleIndex || 0,
|
||||
].join(":");
|
||||
|
||||
updateLineGeometry(preview.previewPath, previewPoints);
|
||||
updateLineGeometry(preview.feedPath, feedPoints);
|
||||
updateLineGeometry(preview.executedPath, executedPoints);
|
||||
updateLineGeometry(preview.rapidPath, rapidPoints);
|
||||
updateLineGeometry(preview.arcPath, arcPoints);
|
||||
updateLineGeometry(preview.currentSegmentPath, currentSegmentPoints);
|
||||
updateToolExecutionMarker(preview, state, toolPosition);
|
||||
updateMachineReferenceModel(preview, state, toolPosition);
|
||||
if (axisReferenceMode) {
|
||||
updateLineGeometry(preview.previewPath, []);
|
||||
updateLineGeometry(preview.feedPath, []);
|
||||
updateLineGeometry(preview.executedPath, []);
|
||||
updateLineSegmentsGeometry(preview.rapidPath, rapidPoints);
|
||||
updateLineSegmentsGeometry(preview.arcPath, arcPoints);
|
||||
updateLineGeometry(preview.currentSegmentPath, []);
|
||||
updateToolExecutionMarker(preview, state, null);
|
||||
} else {
|
||||
updateLineGeometry(preview.previewPath, previewPoints);
|
||||
updateLineGeometry(preview.feedPath, feedPoints);
|
||||
updateLineGeometry(preview.executedPath, executedPoints);
|
||||
updateLineSegmentsGeometry(preview.rapidPath, rapidPoints);
|
||||
updateLineSegmentsGeometry(preview.arcPath, arcPoints);
|
||||
updateLineGeometry(preview.currentSegmentPath, currentSegmentPoints);
|
||||
updateToolExecutionMarker(preview, state, toolPosition);
|
||||
}
|
||||
updateMachineReferenceModel(preview, state, toolPosition, axisReferenceMode);
|
||||
|
||||
const cameraRevision = state.preview.cameraRevision ?? 0;
|
||||
if (
|
||||
@@ -410,7 +539,7 @@ function updateToolpathPreview(preview, state) {
|
||||
preview.lastCameraRevision !== cameraRevision ||
|
||||
preview.lastFitKey !== fitKey
|
||||
) {
|
||||
resetCamera(preview, state.preview.selectedView, fitPoints);
|
||||
resetCamera(preview, state.preview.selectedView, fitPoints, axisReferenceMode);
|
||||
preview.lastSelectedView = state.preview.selectedView;
|
||||
preview.lastCameraRevision = cameraRevision;
|
||||
preview.lastFitKey = fitKey;
|
||||
@@ -439,9 +568,21 @@ function updateToolExecutionMarker(preview, state, toolPosition) {
|
||||
]);
|
||||
}
|
||||
|
||||
function updateMachineReferenceModel(preview, state, toolPosition) {
|
||||
function updateMachineReferenceModel(preview, state, toolPosition, axisReferenceMode = false) {
|
||||
const model = preview.machineModel;
|
||||
if (!model) return;
|
||||
model.root.visible = !axisReferenceMode;
|
||||
if (preview.axisReference) {
|
||||
preview.axisReference.root.visible = axisReferenceMode;
|
||||
if (axisReferenceMode) {
|
||||
const referenceToolPosition = new THREE.Vector3(0, 0, 0.006);
|
||||
preview.axisReference.tool.position.copy(referenceToolPosition);
|
||||
}
|
||||
}
|
||||
if (axisReferenceMode) {
|
||||
preview.currentVismachModelState = null;
|
||||
return;
|
||||
}
|
||||
const vismach = buildVismachModelState(state);
|
||||
preview.currentVismachModelState = summarizeVismachModelStateForDataset(vismach);
|
||||
const toMeters = (value) => linearValueToMeters(value, vismach.linearUnits);
|
||||
@@ -471,11 +612,24 @@ function updateLineGeometry(line, points) {
|
||||
: EMPTY_GEOMETRY.clone();
|
||||
}
|
||||
|
||||
function updateLineSegmentsGeometry(line, segmentPoints) {
|
||||
line.visible = segmentPoints.length > 0;
|
||||
line.geometry.dispose();
|
||||
line.geometry = segmentPoints.length > 0
|
||||
? new THREE.BufferGeometry().setFromPoints(segmentPoints)
|
||||
: EMPTY_GEOMETRY.clone();
|
||||
}
|
||||
|
||||
function geometryPointCount(geometry) {
|
||||
return geometry?.getAttribute("position")?.count || 0;
|
||||
}
|
||||
|
||||
function buildProgramPreviewPoints(state) {
|
||||
const previewSamples = state.programAxisPreviewPath?.samples;
|
||||
if (Array.isArray(previewSamples) && previewSamples.length > 0 && state.preview.pathPoints !== 0) {
|
||||
return limitPoints(previewSamples.map((sample) => vectorFromAxes(sample.tcp || sample.joint, state, "mm")));
|
||||
}
|
||||
|
||||
const motion = state.programExecution?.motion;
|
||||
if (Array.isArray(motion) && motion.length > 0 && state.preview.pathPoints !== 0) {
|
||||
return limitPoints(motion.map((event) => vectorFromAxes(event.axes, state, event.linearUnits)));
|
||||
@@ -488,6 +642,12 @@ function buildProgramPreviewPoints(state) {
|
||||
|
||||
function buildExecutedProgramPoints(state, previewPoints) {
|
||||
if (state.preview.pathPoints === 0 || previewPoints.length === 0) return [];
|
||||
const previewSamples = state.programAxisPreviewPath?.samples;
|
||||
if (Array.isArray(previewSamples) && previewSamples.length > 0) {
|
||||
const end = clamp(Math.round(Number(state.programExecutionSampleIndex || 0)), 0, previewSamples.length - 1);
|
||||
return previewPoints.slice(0, end + 1);
|
||||
}
|
||||
|
||||
const samples = state.programExecutionTiming?.samples;
|
||||
const sampleIndex = Number(state.programExecutionSampleIndex || 0);
|
||||
if (Array.isArray(samples) && samples.length > 0) {
|
||||
@@ -504,17 +664,58 @@ function buildRapidPreviewPoints(state) {
|
||||
}
|
||||
|
||||
function buildTypedPreviewPoints(state, type) {
|
||||
const previewSamples = state.programAxisPreviewPath?.samples;
|
||||
if (Array.isArray(previewSamples) && previewSamples.length > 0 && state.preview.pathPoints !== 0) {
|
||||
const expectedMotionType = type === "STRAIGHT_TRAVERSE"
|
||||
? "rapid"
|
||||
: type === "ARC_FEED"
|
||||
? "arc"
|
||||
: "feed";
|
||||
return limitPoints(buildAxisSampleLineSegments(previewSamples, state, expectedMotionType));
|
||||
}
|
||||
|
||||
const motion = state.programExecution?.motion;
|
||||
if (!Array.isArray(motion) || state.preview.pathPoints === 0) return [];
|
||||
return limitPoints(
|
||||
motion
|
||||
.filter((event) => event.type === type)
|
||||
.map((event) => vectorFromAxes(event.axes, state, event.linearUnits)),
|
||||
.flatMap((event, index, events) => {
|
||||
const previous = events[Math.max(index - 1, 0)];
|
||||
return [
|
||||
vectorFromAxes(previous.axes || event.axes, state, previous.linearUnits || event.linearUnits),
|
||||
vectorFromAxes(event.axes, state, event.linearUnits),
|
||||
];
|
||||
}),
|
||||
);
|
||||
}
|
||||
|
||||
function buildAxisSampleLineSegments(samples, state, motionType) {
|
||||
const points = [];
|
||||
for (let index = 1; index < samples.length; index += 1) {
|
||||
const previous = samples[index - 1];
|
||||
const current = samples[index];
|
||||
if (previous.motionType !== motionType || current.motionType !== motionType) continue;
|
||||
if (current.line !== previous.line && motionType === "arc") continue;
|
||||
points.push(
|
||||
vectorFromAxes(previous.tcp || previous.joint, state, "mm"),
|
||||
vectorFromAxes(current.tcp || current.joint, state, "mm"),
|
||||
);
|
||||
}
|
||||
return points;
|
||||
}
|
||||
|
||||
function buildCurrentSegmentPoints(state) {
|
||||
if (state.preview.pathPoints === 0) return [];
|
||||
const previewSamples = state.programAxisPreviewPath?.samples;
|
||||
if (Array.isArray(previewSamples) && previewSamples.length > 0) {
|
||||
const sampleIndex = clamp(Math.round(Number(state.programExecutionSampleIndex || 0)), 0, previewSamples.length - 1);
|
||||
const current = previewSamples[sampleIndex];
|
||||
const previous = previewSamples[Math.max(sampleIndex - 1, 0)];
|
||||
return [previous, current]
|
||||
.filter(Boolean)
|
||||
.map((sample) => vectorFromAxes(sample.tcp || sample.joint, state, "mm"));
|
||||
}
|
||||
|
||||
const motion = state.programExecution?.motion;
|
||||
if (!Array.isArray(motion) || motion.length === 0) return [];
|
||||
const motionIndex = clampMotionIndex(state, currentMotionIndex(state));
|
||||
@@ -610,6 +811,9 @@ function previewSourceMode(state) {
|
||||
}
|
||||
|
||||
function toolpathPreviewSource(state) {
|
||||
if (state.programAxisPreviewPath?.source === "web-axis-preview-expanded-ngcgui-subroutines") {
|
||||
return "axis_preview_expanded_ngcgui_subroutines";
|
||||
}
|
||||
if (state.programExecution?.sourceMode === "linuxcnc-interpreter-wasm") {
|
||||
return "linuxcnc_interpreter_canonical_motion";
|
||||
}
|
||||
@@ -619,6 +823,10 @@ function toolpathPreviewSource(state) {
|
||||
return "fixture_line_playback_not_promoted";
|
||||
}
|
||||
|
||||
function isAxisReferencePreview(state) {
|
||||
return state.programAxisPreviewPath?.source === "web-axis-preview-expanded-ngcgui-subroutines";
|
||||
}
|
||||
|
||||
function toolExecutionTraceSource(state) {
|
||||
if (Array.isArray(state.programExecutionTiming?.samples) && state.programExecutionTiming.samples.length > 0) {
|
||||
return "linuxcnc_tp_samples_or_task_motion_hal_feedback";
|
||||
@@ -908,16 +1116,26 @@ function panCamera(controls, dx, dy, canvas) {
|
||||
controls.target.addScaledVector(up, dy * speed);
|
||||
}
|
||||
|
||||
function resetCamera(preview, selectedView, fitPoints = []) {
|
||||
function resetCamera(preview, selectedView, fitPoints = [], axisReferenceMode = false) {
|
||||
const preset = CAMERA_PRESETS[selectedView] || CAMERA_PRESETS.iso;
|
||||
preview.controls.theta = preset.theta;
|
||||
preview.controls.phi = preset.phi;
|
||||
preview.controls.radius = preset.radius;
|
||||
preview.controls.target.copy(preset.target);
|
||||
preview.pathFitBoundsReady = applyFitBounds(preview.controls, selectedView, fitPoints);
|
||||
preview.pathFitBoundsReady = axisReferenceMode
|
||||
? applyAxisReferenceCamera(preview.controls)
|
||||
: applyFitBounds(preview.controls, selectedView, fitPoints);
|
||||
applyCameraControls(preview.controls);
|
||||
}
|
||||
|
||||
function applyAxisReferenceCamera(controls) {
|
||||
controls.theta = -0.48;
|
||||
controls.phi = 0.82;
|
||||
controls.radius = 0.125;
|
||||
controls.target.set(0.001, -0.002, 0.006);
|
||||
return true;
|
||||
}
|
||||
|
||||
function applyFitBounds(controls, selectedView, fitPoints) {
|
||||
const bounds = computePointBounds(fitPoints);
|
||||
if (!bounds) return false;
|
||||
|
||||
Reference in New Issue
Block a user