Skip to content

Commit 810e848

Browse files
committed
fix(segmentation): use segment group's coordinate system for slice rendering
When a segment group has a different direction matrix than its parent image, the slice overlay was showing incorrect slices. Now computes the labelmap's LPS orientation independently and transforms the parent slice position through world space to find the correct labelmap slice.
1 parent 97f32b0 commit 810e848

File tree

1 file changed

+46
-4
lines changed

1 file changed

+46
-4
lines changed

src/components/vtk/VtkSegmentationSliceRepresentation.vue

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import { useSliceRepresentation } from '@/src/core/vtk/useSliceRepresentation';
55
import { LPSAxis } from '@/src/types/lps';
66
import { onVTKEvent } from '@/src/composables/onVTKEvent';
77
import { SlicingMode } from '@kitware/vtk.js/Rendering/Core/ImageMapper/Constants';
8+
import type { Matrix3x3 } from '@kitware/vtk.js/types';
89
import { VtkViewContext } from '@/src/components/vtk/context';
910
import {
1011
useSegmentGroupStore,
@@ -14,7 +15,9 @@ import { InterpolationType } from '@kitware/vtk.js/Rendering/Core/ImageProperty/
1415
import vtkColorTransferFunction from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction';
1516
import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction';
1617
import { vtkFieldRef } from '@/src/core/vtk/vtkFieldRef';
17-
import { syncRef } from '@vueuse/core';
18+
import { watchImmediate } from '@vueuse/core';
19+
import { vec3, mat3 } from 'gl-matrix';
20+
import { getLPSDirections } from '@/src/utils/lps';
1821
import { useSliceConfig } from '@/src/composables/useSliceConfig';
1922
import useLayerColoringStore from '@/src/store/view-configs/layers';
2023
import { useSegmentGroupConfigStore } from '@/src/store/view-configs/segmentGroups';
@@ -86,17 +89,56 @@ watchEffect(() => {
8689
const parentImageId = computed(() => metadata.value?.parentImage);
8790
const { metadata: parentMetadata } = useImage(parentImageId);
8891
92+
// Compute labelmap's LPS orientation from its direction matrix
93+
const labelmapLpsOrientation = computed(() => {
94+
const labelmap = imageData.value;
95+
if (!labelmap) return null;
96+
const direction = labelmap.getDirection() as Matrix3x3;
97+
const mat = mat3.fromValues(...direction);
98+
return getLPSDirections(mat);
99+
});
100+
101+
// Set slicing mode based on labelmap's own orientation
89102
watchEffect(() => {
90-
const { lpsOrientation } = parentMetadata.value;
103+
const lpsOrientation = labelmapLpsOrientation.value;
104+
if (!lpsOrientation) return;
91105
const ijkIndex = lpsOrientation[axis.value];
92106
const mode = [SlicingMode.I, SlicingMode.J, SlicingMode.K][ijkIndex];
93107
sliceRep.mapper.setSlicingMode(mode);
94108
});
95109
96-
// sync slicing
110+
// sync slicing - convert parent slice to labelmap slice via world coordinates
97111
const slice = vtkFieldRef(sliceRep.mapper, 'slice');
98112
const { slice: storedSlice } = useSliceConfig(viewId, parentImageId);
99-
syncRef(storedSlice, slice, { immediate: true });
113+
114+
watchImmediate(
115+
[storedSlice, labelmapLpsOrientation, () => parentMetadata.value],
116+
() => {
117+
const parentImage = parentMetadata.value;
118+
const labelmap = imageData.value;
119+
const labelmapLps = labelmapLpsOrientation.value;
120+
if (!parentImage || !labelmap || !labelmapLps || storedSlice.value == null)
121+
return;
122+
123+
const { lpsOrientation: parentLps, indexToWorld } = parentImage;
124+
const parentIjkIndex = parentLps[axis.value];
125+
const labelmapIjkIndex = labelmapLps[axis.value];
126+
127+
// Get world position of the parent's slice
128+
const parentIndexPoint = vec3.fromValues(0, 0, 0);
129+
parentIndexPoint[parentIjkIndex] = storedSlice.value;
130+
const worldPoint = vec3.create();
131+
vec3.transformMat4(worldPoint, parentIndexPoint, indexToWorld);
132+
133+
// Convert world position to labelmap index space
134+
const labelmapWorldToIndex = labelmap.getWorldToIndex();
135+
const labelmapIndexPoint = vec3.create();
136+
vec3.transformMat4(labelmapIndexPoint, worldPoint, labelmapWorldToIndex);
137+
138+
// Use the labelmap's IJK index for this LPS axis
139+
slice.value = Math.round(labelmapIndexPoint[labelmapIjkIndex]);
140+
}
141+
);
100142
101143
// set coloring properties
102144
const applySegmentColoring = () => {

0 commit comments

Comments
 (0)