correct export volume orientation
This commit is contained in:
+148
-86
@@ -1334,6 +1334,19 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
|
||||
}
|
||||
}
|
||||
// Attach to window with a unique name
|
||||
|
||||
window[`getViewport_${apiKey}`] = (idx: number) => {
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
if (!renderingEngine) return undefined;
|
||||
return renderingEngine.getViewport(`CT_${idx}`);
|
||||
};
|
||||
window[`getAllViewports_${apiKey}`] = () => {
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
if (!renderingEngine) return [];
|
||||
// Return all currently active viewports as an array
|
||||
return Array.from({ length: MAX_VIEWPORTS }, (_, i) => renderingEngine.getViewport(`CT_${i}`)).filter(Boolean);
|
||||
};
|
||||
|
||||
window[`jumpToSliceByImageId_${apiKey}`] = jumpToSliceByImageId;
|
||||
window[`resetViewer_${apiKey}`] = resetViewer;
|
||||
window[`truncateStack_${apiKey}`] = truncateStack;
|
||||
@@ -1376,15 +1389,21 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
|
||||
i: s.imageIds, // imageIds
|
||||
u: s.studyInstanceUID // studyInstanceUID
|
||||
}));
|
||||
console.log("Exporting viewer state with", numActive, "active viewports");
|
||||
console.log("modes", modes);
|
||||
|
||||
// Only keep minimal properties
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
const props: any[] = [];
|
||||
const stackPos: number[] = [];
|
||||
const cam: any[] = [];
|
||||
const orientations: (string | null)[] = [];
|
||||
const volumeSliceIndices: (number | null)[] = [];
|
||||
for (let i = 0; i < numActive; i++) {
|
||||
let p = null, s = null, c = null;
|
||||
let p = null, s = null, c = null, o = null, vIdx = null;
|
||||
console.log("Exporting state for viewport", i);
|
||||
if (renderingEngine) {
|
||||
console.log("Rendering engine found, exporting state for viewport", i);
|
||||
const viewportId = `CT_${i}`;
|
||||
const viewport = renderingEngine.getViewport(viewportId);
|
||||
if (viewport) {
|
||||
@@ -1398,11 +1417,23 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
|
||||
if (typeof viewport.getCamera === "function") {
|
||||
c = viewport.getCamera();
|
||||
}
|
||||
console.log("viewport", viewportId, "properties", p);
|
||||
// --- Volume orientation and slice index ---
|
||||
if (modes[i] === "volume") {
|
||||
console.log("Getting orientation for viewport", i);
|
||||
console.log("viewport.viewportProperties", viewport.viewportProperties);
|
||||
o = viewport.viewportProperties?.orientation || null;
|
||||
if (typeof viewport.getSliceIndex === "function") {
|
||||
vIdx = viewport.getSliceIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
props.push(p);
|
||||
stackPos.push(s);
|
||||
cam.push(c);
|
||||
orientations.push(o);
|
||||
volumeSliceIndices.push(vIdx);
|
||||
}
|
||||
|
||||
// Use short keys for compactness
|
||||
@@ -1414,6 +1445,8 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
|
||||
stackPos,
|
||||
props,
|
||||
cam,
|
||||
orientations, // <-- add this
|
||||
volumeSliceIndices, // <-- add this
|
||||
};
|
||||
return JSON.stringify(state);
|
||||
};
|
||||
@@ -1440,6 +1473,7 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
|
||||
const maxAttempts = 30;
|
||||
let attempts = 0;
|
||||
|
||||
// eslint-disable-next-line no-inner-declarations
|
||||
async function tryRestore() {
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
if (!renderingEngine) {
|
||||
@@ -1448,29 +1482,33 @@ function App({ container_id, imageStacks, autoCacheStack, annotationJson, viewer
|
||||
}
|
||||
const numActive = state.grid?.rows * state.grid?.cols || 1;
|
||||
let allReady = true;
|
||||
for (let i = 0; i < numActive; i++) {
|
||||
const viewport = renderingEngine.getViewport(`CT_${i}`);
|
||||
if (!viewport) { allReady = false; break; }
|
||||
const stackIdx = state.stackIdx?.[i];
|
||||
const stackObj = state.stacks?.[stackIdx];
|
||||
const importedImageIds = stackObj?.i || [];
|
||||
if (!importedImageIds.length) continue;
|
||||
const viewportImageIds = viewport.getImageIds?.() || [];
|
||||
if (
|
||||
viewportImageIds.length !== importedImageIds.length ||
|
||||
!viewportImageIds.every((id, idx) => id === importedImageIds[idx])
|
||||
) {
|
||||
console.warn(
|
||||
`Viewport ${i}: importedImageIds do not match viewportImageIds`,
|
||||
{ importedImageIds, viewportImageIds }
|
||||
);
|
||||
allReady = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (let i = 0; i < numActive; i++) {
|
||||
console.log("Checking viewport", i);
|
||||
const viewport = renderingEngine.getViewport(`CT_${i}`);
|
||||
if (!viewport) { allReady = false; break; }
|
||||
const stackIdx = state.stackIdx?.[i];
|
||||
const stackObj = state.stacks?.[stackIdx];
|
||||
const importedImageIds = stackObj?.i || [];
|
||||
console.log("Checking viewport", i, "with importedImageIds", importedImageIds);
|
||||
console.log("viewport", viewport);
|
||||
console.log("viewport.getImageIds", viewport.getImageIds?.());
|
||||
if (!importedImageIds.length) continue;
|
||||
const viewportImageIds = viewport.getImageIds?.() || [];
|
||||
if (
|
||||
viewportImageIds.length !== importedImageIds.length ||
|
||||
!viewportImageIds.every((id, idx) => id === importedImageIds[idx])
|
||||
) {
|
||||
console.warn(
|
||||
`Viewport ${i}: importedImageIds do not match viewportImageIds`,
|
||||
{ importedImageIds, viewportImageIds }
|
||||
);
|
||||
allReady = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!allReady && attempts < maxAttempts) {
|
||||
attempts++;
|
||||
setTimeout(() => { tryRestore(); }, 100);
|
||||
setTimeout(() => { tryRestore(); }, 500);
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1490,11 +1528,33 @@ for (let i = 0; i < numActive; i++) {
|
||||
if (state.modes?.[i] === "volume") {
|
||||
// --- Restore volume ---
|
||||
console.log("Restoring volume for viewport", i, importedImageIds);
|
||||
const volumeId = `myVolumeId_${i}`;
|
||||
const volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds: importedImageIds });
|
||||
volume.load();
|
||||
viewport.setVolumes([{ volumeId }]);
|
||||
viewport.render();
|
||||
const volumeId = `myVolumeId_${i}`;
|
||||
const volume = await volumeLoader.createAndCacheVolume(volumeId, { imageIds: importedImageIds });
|
||||
volume.load();
|
||||
viewport.setVolumes([{ volumeId }]);
|
||||
// --- Restore orientation if present ---
|
||||
if (state.orientations && state.orientations[i] && typeof viewport.setOrientation === "function") {
|
||||
try {
|
||||
viewport.setOrientation(state.orientations[i]);
|
||||
viewport.render();
|
||||
} catch (e) {
|
||||
console.warn("Failed to restore orientation for viewport", i, e);
|
||||
}
|
||||
}
|
||||
// --- Restore slice index if present ---
|
||||
if (
|
||||
state.volumeSliceIndices &&
|
||||
typeof state.volumeSliceIndices[i] === "number" &&
|
||||
typeof viewport.setSliceIndex === "function"
|
||||
) {
|
||||
try {
|
||||
viewport.setSliceIndex(state.volumeSliceIndices[i]);
|
||||
viewport.render();
|
||||
} catch (e) {
|
||||
console.warn("Failed to restore slice index for viewport", i, e);
|
||||
}
|
||||
}
|
||||
viewport.render();
|
||||
} else {
|
||||
// --- Restore stack ---
|
||||
if (viewport.setStack) {
|
||||
@@ -1548,7 +1608,7 @@ for (let i = 0; i < numActive; i++) {
|
||||
}
|
||||
|
||||
// Delay start until after next paint
|
||||
setTimeout(() => { tryRestore(); }, 0);
|
||||
setTimeout(() => { tryRestore(); }, 0);
|
||||
|
||||
} catch (e) {
|
||||
restoringStateRef.current = false;
|
||||
@@ -1781,6 +1841,8 @@ for (let i = 0; i < numActive; i++) {
|
||||
window[`truncateStack_${apiKey}`] = undefined;
|
||||
window[`getCurrentStackPosition_${apiKey}`] = undefined;
|
||||
window[`loadAdditionalStack_${apiKey}`] = undefined;
|
||||
window[`getViewport_${apiKey}`] = undefined;
|
||||
window[`getAllViewports_${apiKey}`] = undefined;
|
||||
};
|
||||
}, [
|
||||
viewportGrid,
|
||||
@@ -1799,69 +1861,69 @@ for (let i = 0; i < numActive; i++) {
|
||||
]);
|
||||
|
||||
|
||||
useEffect(() => {
|
||||
function handleArrowKeyNavigation(e: KeyboardEvent) {
|
||||
if (activeViewport === null) return;
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
if (!renderingEngine) return;
|
||||
const viewport = renderingEngine.getViewport(`CT_${activeViewport}`);
|
||||
if (!viewport) return;
|
||||
useEffect(() => {
|
||||
function handleArrowKeyNavigation(e: KeyboardEvent) {
|
||||
if (activeViewport === null) return;
|
||||
const renderingEngine = renderingEngineRef.current;
|
||||
if (!renderingEngine) return;
|
||||
const viewport = renderingEngine.getViewport(`CT_${activeViewport}`);
|
||||
if (!viewport) return;
|
||||
|
||||
// --- Stack mode navigation ---
|
||||
if (viewportModes[activeViewport] === "stack") {
|
||||
if (
|
||||
typeof viewport.getCurrentImageIdIndex !== "function" ||
|
||||
typeof viewport.setImageIdIndex !== "function"
|
||||
) return;
|
||||
const imageIds = viewportImageIds[activeViewport];
|
||||
if (!imageIds || imageIds.length === 0) return;
|
||||
let idx = viewport.getCurrentImageIdIndex();
|
||||
// --- Stack mode navigation ---
|
||||
if (viewportModes[activeViewport] === "stack") {
|
||||
if (
|
||||
typeof viewport.getCurrentImageIdIndex !== "function" ||
|
||||
typeof viewport.setImageIdIndex !== "function"
|
||||
) return;
|
||||
const imageIds = viewportImageIds[activeViewport];
|
||||
if (!imageIds || imageIds.length === 0) return;
|
||||
let idx = viewport.getCurrentImageIdIndex();
|
||||
|
||||
if (e.key === "ArrowUp" || e.key === "ArrowRight") {
|
||||
idx = idx < imageIds.length - 1 ? idx + 1 : 0;
|
||||
csUtilities.jumpToSlice(viewport.element, { imageIndex: idx });
|
||||
updateOverlay(activeViewport, viewport);
|
||||
e.preventDefault();
|
||||
} else if (e.key === "ArrowDown" || e.key === "ArrowLeft") {
|
||||
idx = idx > 0 ? idx - 1 : imageIds.length - 1;
|
||||
csUtilities.jumpToSlice(viewport.element, { imageIndex: idx });
|
||||
updateOverlay(activeViewport, viewport);
|
||||
e.preventDefault();
|
||||
if (e.key === "ArrowUp" || e.key === "ArrowRight") {
|
||||
idx = idx < imageIds.length - 1 ? idx + 1 : 0;
|
||||
csUtilities.jumpToSlice(viewport.element, { imageIndex: idx });
|
||||
updateOverlay(activeViewport, viewport);
|
||||
e.preventDefault();
|
||||
} else if (e.key === "ArrowDown" || e.key === "ArrowLeft") {
|
||||
idx = idx > 0 ? idx - 1 : imageIds.length - 1;
|
||||
csUtilities.jumpToSlice(viewport.element, { imageIndex: idx });
|
||||
updateOverlay(activeViewport, viewport);
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
// --- Volume mode navigation ---
|
||||
if (viewportModes[activeViewport] === "volume") {
|
||||
// Try to scroll through slices in the current orientation
|
||||
if (
|
||||
typeof viewport.getSliceIndex === "function" &&
|
||||
typeof viewport.setSliceIndex === "function" &&
|
||||
typeof viewport.getNumberOfSlices === "function"
|
||||
) {
|
||||
const numSlices = viewport.getNumberOfSlices();
|
||||
let idx = viewport.getSliceIndex();
|
||||
if (numSlices > 1) {
|
||||
if (e.key === "ArrowUp" || e.key === "ArrowRight") {
|
||||
idx = idx < numSlices - 1 ? idx + 1 : 0;
|
||||
viewport.setSliceIndex(idx);
|
||||
viewport.render();
|
||||
updateOverlay(activeViewport, viewport);
|
||||
e.preventDefault();
|
||||
} else if (e.key === "ArrowDown" || e.key === "ArrowLeft") {
|
||||
idx = idx > 0 ? idx - 1 : numSlices - 1;
|
||||
viewport.setSliceIndex(idx);
|
||||
viewport.render();
|
||||
updateOverlay(activeViewport, viewport);
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- Volume mode navigation ---
|
||||
if (viewportModes[activeViewport] === "volume") {
|
||||
// Try to scroll through slices in the current orientation
|
||||
if (
|
||||
typeof viewport.getSliceIndex === "function" &&
|
||||
typeof viewport.setSliceIndex === "function" &&
|
||||
typeof viewport.getNumberOfSlices === "function"
|
||||
) {
|
||||
const numSlices = viewport.getNumberOfSlices();
|
||||
let idx = viewport.getSliceIndex();
|
||||
if (numSlices > 1) {
|
||||
if (e.key === "ArrowUp" || e.key === "ArrowRight") {
|
||||
idx = idx < numSlices - 1 ? idx + 1 : 0;
|
||||
viewport.setSliceIndex(idx);
|
||||
viewport.render();
|
||||
updateOverlay(activeViewport, viewport);
|
||||
e.preventDefault();
|
||||
} else if (e.key === "ArrowDown" || e.key === "ArrowLeft") {
|
||||
idx = idx > 0 ? idx - 1 : numSlices - 1;
|
||||
viewport.setSliceIndex(idx);
|
||||
viewport.render();
|
||||
updateOverlay(activeViewport, viewport);
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener("keydown", handleArrowKeyNavigation);
|
||||
return () => window.removeEventListener("keydown", handleArrowKeyNavigation);
|
||||
}, [activeViewport, viewportModes, viewportImageIds, updateOverlay]);
|
||||
window.addEventListener("keydown", handleArrowKeyNavigation);
|
||||
return () => window.removeEventListener("keydown", handleArrowKeyNavigation);
|
||||
}, [activeViewport, viewportModes, viewportImageIds, updateOverlay]);
|
||||
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user