Skip to content

Commit 07e5bb3

Browse files
committed
feat: first attempt at bringing oblique views back
1 parent c7530d7 commit 07e5bb3

7 files changed

Lines changed: 123 additions & 39 deletions

File tree

src/components/ControlsStripTools.vue

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,7 @@ import PolygonControls from '@/src/components/PolygonControls.vue';
142142
import WindowLevelControls from '@/src/components/tools/windowing/WindowLevelControls.vue';
143143
import { actionToKey } from '@/src/composables/useKeyboardShortcuts';
144144
import { useCurrentImage } from '@/src/composables/useCurrentImage';
145+
import { useViewStore } from '@/src/store/views';
145146
146147
export default defineComponent({
147148
components: {
@@ -158,11 +159,16 @@ export default defineComponent({
158159
},
159160
setup() {
160161
const toolStore = useToolStore();
162+
const viewStore = useViewStore();
161163
162164
const { currentImageID } = useCurrentImage();
163165
const noCurrentImage = computed(() => !currentImageID.value);
164166
const currentTool = computed(() => toolStore.currentTool);
165-
const isObliqueLayout = computed(() => false);
167+
const isObliqueLayout = computed(() => {
168+
if (!viewStore.activeView) return false;
169+
const view = viewStore.viewByID[viewStore.activeView];
170+
return view.type === 'Oblique';
171+
});
166172
167173
const paintMenu = ref(false);
168174
const cropMenu = ref(false);

src/components/MultiObliqueSliceViewer.vue

Lines changed: 6 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class="vtk-view"
88
ref="vtkView"
99
data-testid="vtk-view"
10-
:view-id="id"
10+
:view-id="viewId"
1111
:image-id="currentImageID"
1212
:view-direction="viewDirection"
1313
:view-up="viewUp"
@@ -41,7 +41,6 @@ import { useCurrentImage } from '@/src/composables/useCurrentImage';
4141
import { LPSAxis, LPSAxisDir } from '@/src/types/lps';
4242
import VtkVolumeView from '@/src/components/vtk/VtkVolumeView.vue';
4343
import { VtkViewApi } from '@/src/types/vtk-types';
44-
import { LayoutViewProps } from '@/src/types';
4544
import VtkBaseObliqueSliceRepresentation from '@/src/components/vtk/VtkBaseObliqueSliceRepresentation.vue';
4645
import VtkImageOutlineRepresentation from '@/src/components/vtk/VtkImageOutlineRepresentation.vue';
4746
import { useViewAnimationListener } from '@/src/composables/useViewAnimationListener';
@@ -59,7 +58,8 @@ interface SliceSpec {
5958
axis: LPSAxis;
6059
}
6160
62-
interface Props extends LayoutViewProps {
61+
interface Props {
62+
viewId: string;
6363
viewDirection: LPSAxisDir;
6464
viewUp: LPSAxisDir;
6565
slices: SliceSpec[];
@@ -69,15 +69,9 @@ const vtkView = ref<VtkViewApi>();
6969
7070
const props = defineProps<Props>();
7171
72-
const {
73-
id: viewId,
74-
type: viewType,
75-
viewDirection,
76-
viewUp,
77-
slices,
78-
} = toRefs(props);
72+
const { viewId, viewDirection, viewUp, slices } = toRefs(props);
7973
80-
useViewAnimationListener(vtkView, viewId, viewType);
74+
useViewAnimationListener(vtkView, viewId, 'Oblique');
8175
8276
// base image
8377
const { currentImageID } = useCurrentImage();
@@ -96,7 +90,7 @@ const obliqueSliceProps = computed(() => {
9690
);
9791
const outlineColor = vec3.scale(
9892
[0, 0, 0],
99-
OBLIQUE_OUTLINE_COLORS[sliceSpec.viewID],
93+
OBLIQUE_OUTLINE_COLORS[`Oblique${sliceSpec.axis}`],
10094
1 / 255
10195
) as RGBColor;
10296
return {

src/components/ObliqueSliceViewer.vue

Lines changed: 12 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
class="vtk-view"
88
ref="vtkView"
99
data-testid="vtk-view"
10-
:view-id="id"
10+
:view-id="viewId"
1111
:image-id="currentImageID"
1212
:view-direction="viewDirection"
1313
:view-up="viewUp"
@@ -36,30 +36,30 @@
3636
:manipulator-props="{ button: 3 }"
3737
></vtk-mouse-interaction-manipulator>
3838
<vtk-slice-view-window-manipulator
39-
:view-id="id"
39+
:view-id="viewId"
4040
:image-id="currentImageID"
4141
:manipulator-config="windowingManipulatorProps"
4242
></vtk-slice-view-window-manipulator>
4343
<slice-viewer-overlay
44-
:view-id="id"
44+
:view-id="viewId"
4545
:image-id="currentImageID"
4646
></slice-viewer-overlay>
4747
<vtk-base-oblique-slice-representation
48-
:view-id="id"
48+
:view-id="viewId"
4949
:image-id="currentImageID"
5050
:plane-normal="planeNormal"
5151
:plane-origin="planeOrigin"
5252
></vtk-base-oblique-slice-representation>
5353
<vtk-image-outline-representation
54-
:view-id="id"
54+
:view-id="viewId"
5555
:image-id="currentImageID"
5656
:plane-normal="planeNormal"
5757
:plane-origin="planeOrigin"
5858
:thickness="4"
5959
:color="outlineColor"
6060
></vtk-image-outline-representation>
6161
<reslice-cursor-tool
62-
:view-id="id"
62+
:view-id="viewId"
6363
:view-direction="viewDirection"
6464
></reslice-cursor-tool>
6565
<slot></slot>
@@ -84,7 +84,6 @@ import { vtkFieldRef } from '@/src/core/vtk/vtkFieldRef';
8484
import useResliceCursorStore, {
8585
mapAxisToViewType,
8686
} from '@/src/store/reslice-cursor';
87-
import { LayoutViewProps } from '@/src/types';
8887
import { LPSAxisDir } from '@/src/types/lps';
8988
import { VtkViewApi } from '@/src/types/vtk-types';
9089
import { batchForNextTask } from '@/src/utils/batchForNextTask';
@@ -104,7 +103,9 @@ import { storeToRefs } from 'pinia';
104103
import { useToolStore } from '@/src/store/tools';
105104
import { Tools } from '@/src/store/tools/types';
106105
107-
interface Props extends LayoutViewProps {
106+
interface Props {
107+
viewId: string;
108+
outlineType: string;
108109
viewDirection: LPSAxisDir;
109110
viewUp: LPSAxisDir;
110111
}
@@ -113,11 +114,11 @@ const vtkView = ref<VtkViewApi>();
113114
114115
const props = defineProps<Props>();
115116
116-
const { id: viewId, type: viewType, viewDirection, viewUp } = toRefs(props);
117+
const { viewId, outlineType, viewDirection, viewUp } = toRefs(props);
117118
const viewAxis = computed(() => getLPSAxisFromDir(viewDirection.value));
118119
119120
useWebGLWatchdog(vtkView);
120-
useViewAnimationListener(vtkView, viewId, viewType);
121+
useViewAnimationListener(vtkView, viewId, 'Oblique');
121122
122123
// active tool
123124
const { currentTool } = storeToRefs(useToolStore());
@@ -261,7 +262,7 @@ const outlineColor = computed(
261262
() =>
262263
vec3.scale(
263264
[0, 0, 0],
264-
OBLIQUE_OUTLINE_COLORS[viewId.value],
265+
OBLIQUE_OUTLINE_COLORS[outlineType.value],
265266
1 / 255
266267
) as RGBColor
267268
);

src/components/ObliqueViewer.vue

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
<template>
2+
<div class="d-flex flex-row flex-grow-1">
3+
<div class="d-flex flex-column flex-grow-1">
4+
<div class="d-flex flex-grow-1" style="border-bottom: 1px solid gray">
5+
<ObliqueSliceViewer
6+
:view-id="`${viewId}-coronal`"
7+
outline-type="ObliqueCoronal"
8+
view-direction="Posterior"
9+
view-up="Superior"
10+
/>
11+
</div>
12+
<div class="d-flex flex-grow-1" style="border-right: 1px solid gray">
13+
<ObliqueSliceViewer
14+
:view-id="`${viewId}-sagittal`"
15+
outline-type="ObliqueSagittal"
16+
view-direction="Right"
17+
view-up="Superior"
18+
/>
19+
</div>
20+
</div>
21+
<div class="d-flex flex-column flex-grow-1">
22+
<div class="d-flex flex-grow-1" style="border-left: 1px solid gray">
23+
<MultiObliqueSliceViewer
24+
:view-id="`${viewId}-multi-oblique`"
25+
view-direction="Posterior"
26+
view-up="Superior"
27+
:slices="[
28+
{
29+
viewID: `${viewId}-coronal`,
30+
axis: 'Coronal',
31+
},
32+
{
33+
viewID: `${viewId}-sagittal`,
34+
axis: 'Sagittal',
35+
},
36+
{
37+
viewID: `${viewId}-axial`,
38+
axis: 'Axial',
39+
},
40+
]"
41+
/>
42+
</div>
43+
<div class="d-flex flex-grow-1" style="border-top: 1px solid gray">
44+
<ObliqueSliceViewer
45+
:view-id="`${viewId}-axial`"
46+
outline-type="ObliqueAxial"
47+
view-direction="Superior"
48+
view-up="Anterior"
49+
/>
50+
</div>
51+
</div>
52+
</div>
53+
</template>
54+
55+
<script setup lang="ts">
56+
import MultiObliqueSliceViewer from '@/src/components/MultiObliqueSliceViewer.vue';
57+
import ObliqueSliceViewer from '@/src/components/ObliqueSliceViewer.vue';
58+
import useResliceCursorStore from '@/src/store/reslice-cursor';
59+
60+
interface Props {
61+
viewId: string;
62+
}
63+
64+
defineProps<Props>();
65+
66+
// initialize the reslice cursor store
67+
useResliceCursorStore();
68+
</script>

src/config.ts

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,21 @@ export const InitViewIDs: Record<string, string> = {
2828

2929
export const getAvailableViews = () => {
3030
const list: ViewInfoInit[] = [
31+
{
32+
name: 'Oblique',
33+
type: 'Oblique',
34+
dataID: null,
35+
options: {},
36+
},
37+
{
38+
name: 'Volume',
39+
type: '3D',
40+
dataID: null,
41+
options: {
42+
viewDirection: 'Posterior',
43+
viewUp: 'Superior',
44+
},
45+
},
3146
{
3247
name: 'Coronal',
3348
type: '2D',
@@ -52,15 +67,6 @@ export const getAvailableViews = () => {
5267
orientation: 'Axial',
5368
},
5469
},
55-
{
56-
name: 'Volume',
57-
type: '3D',
58-
dataID: null,
59-
options: {
60-
viewDirection: 'Posterior',
61-
viewUp: 'Superior',
62-
},
63-
},
6470
];
6571

6672
const byName = list.reduce(
@@ -75,7 +81,7 @@ const availableViews = getAvailableViews();
7581

7682
export const DefaultLayoutSlots: ViewInfoInit[] = [
7783
availableViews.byName.Coronal,
78-
availableViews.byName.Volume,
84+
availableViews.byName.Oblique,
7985
availableViews.byName.Sagittal,
8086
availableViews.byName.Axial,
8187
];

src/core/viewTypes.ts

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,16 @@ import SliceViewer from '@/src/components/SliceViewer.vue';
55
import VolumeViewer from '@/src/components/VolumeViewer.vue';
66
import { ViewInfo } from '@/src/types/views';
77
import { Maybe } from '@/src/types';
8+
import ObliqueViewer from '@/src/components/ObliqueViewer.vue';
89

910
export function getComponentFromViewInfo(info: ViewInfo): Maybe<Component> {
1011
switch (info.type) {
1112
case '2D':
1213
return SliceViewer;
1314
case '3D':
1415
return VolumeViewer;
15-
// case 'Oblique':
16-
//
16+
case 'Oblique':
17+
return ObliqueViewer;
1718
default:
1819
return null;
1920
}

src/types/views.ts

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ import {
66
import { Maybe } from '@/src/types';
77
import { LPSAxis, LPSAxisDir } from '@/src/types/lps';
88

9-
export type ViewType = '2D' | '3D' | 'Oblique2D' | 'Oblique3D';
9+
export type ViewType = '2D' | '3D' | 'Oblique';
1010

1111
interface GenericViewInfo {
1212
id: string;
@@ -31,8 +31,16 @@ export interface ViewInfo3D extends GenericViewInfo {
3131
};
3232
}
3333

34-
export type ViewInfo = ViewInfo2D | ViewInfo3D;
35-
export type ViewInfoInit = Omit<ViewInfo2D, 'id'> | Omit<ViewInfo3D, 'id'>;
34+
export interface ViewInfoOblique extends GenericViewInfo {
35+
type: 'Oblique';
36+
options: {};
37+
}
38+
39+
export type ViewInfo = ViewInfo2D | ViewInfo3D | ViewInfoOblique;
40+
export type ViewInfoInit = Omit<
41+
ViewInfo2D | ViewInfo3D | ViewInfoOblique,
42+
'id'
43+
>;
3644

3745
export interface ViewSpec {
3846
viewType: string;

0 commit comments

Comments
 (0)