Skip to content

Commit

Permalink
Merge pull request #594 from Kitware/unify-ids
Browse files Browse the repository at this point in the history
feat: unify data IDs
  • Loading branch information
floryst committed May 21, 2024
2 parents a7b6290 + e4da486 commit 9e650be
Show file tree
Hide file tree
Showing 27 changed files with 179 additions and 360 deletions.
5 changes: 2 additions & 3 deletions src/components/DataBrowser.vue
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
<script lang="ts">
import { computed, defineComponent, ref, watch } from 'vue';
import { isRegularImage } from '@/src/utils/dataSelection';
import SampleDataBrowser from './SampleDataBrowser.vue';
import { useDicomWebStore } from '../store/dicom-web/dicom-web-store';
import ImageDataBrowser from './ImageDataBrowser.vue';
Expand Down Expand Up @@ -42,9 +43,7 @@ export default defineComponent({
);
const hasAnonymousImages = computed(
() =>
imageStore.idList.filter((id) => !(id in dicomStore.imageIDToVolumeKey))
.length > 0
() => imageStore.idList.filter((id) => isRegularImage(id)).length > 0
);
const panels = ref<string[]>([SAMPLE_DATA_KEY, DICOM_WEB_KEY]);
Expand Down
5 changes: 3 additions & 2 deletions src/components/DicomQuickInfoButton.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
<script setup lang="ts">
import { useDICOMStore } from '@/src/store/datasets-dicom';
import { Maybe } from '@/src/types';
import { isDicomImage } from '@/src/utils/dataSelection';
import { computed, toRef } from 'vue';
interface Props {
Expand All @@ -12,8 +13,8 @@ const imageId = toRef(props, 'imageId');
const dicomStore = useDICOMStore();
const dicomInfo = computed(() => {
if (imageId.value != null && imageId.value in dicomStore.imageIDToVolumeKey) {
const volumeKey = dicomStore.imageIDToVolumeKey[imageId.value];
const volumeKey = imageId.value;
if (volumeKey && isDicomImage(volumeKey)) {
const volumeInfo = dicomStore.volumeInfo[volumeKey];
const studyKey = dicomStore.volumeStudy[volumeKey];
const studyInfo = dicomStore.studyInfo[studyKey];
Expand Down
35 changes: 12 additions & 23 deletions src/components/ImageDataBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,11 @@ import ImageListCard from '@/src/components/ImageListCard.vue';
import { createVTKImageThumbnailer } from '@/src/core/thumbnailers/vtk-image';
import { useSegmentGroupStore } from '@/src/store/segmentGroups';
import {
DataSelection,
ImageSelection,
isRegularImage,
type DataSelection,
selectionEquals,
} from '@/src/utils/dataSelection';
import { useImageStore } from '../store/datasets-images';
import { useDICOMStore } from '../store/datasets-dicom';
import { useDatasetStore } from '../store/datasets';
import { useMultiSelection } from '../composables/useMultiSelection';
Expand All @@ -29,39 +28,32 @@ export default defineComponent({
},
setup() {
const imageStore = useImageStore();
const dicomStore = useDICOMStore();
const dataStore = useDatasetStore();
const layersStore = useLayersStore();
const segmentGroupStore = useSegmentGroupStore();
const primarySelection = computed(() => dataStore.primarySelection);
const nonDICOMImages = computed(() =>
imageStore.idList.filter((id) => !(id in dicomStore.imageIDToVolumeKey))
imageStore.idList.filter((id) => isRegularImage(id))
);
const images = computed(() => {
const { metadata } = imageStore;
const layerImages = layersStore
.getLayers(primarySelection.value)
.filter(({ selection }) => selection.type === 'image');
const layerImageIDs = layerImages.map(
({ selection }) => (selection as ImageSelection).dataID
);
.filter(({ selection }) => isRegularImage(selection));
const layerImageIDs = layerImages.map(({ selection }) => selection);
const loadedLayerImageIDs = layerImages
.filter(({ id }) => id in layersStore.layerImages)
.map(({ selection }) => (selection as ImageSelection).dataID);
.map(({ selection }) => selection);
const selectedImageID =
primarySelection.value?.type === 'image' &&
primarySelection.value?.dataID;
isRegularImage(primarySelection.value) && primarySelection.value;
return nonDICOMImages.value.map((id) => {
const selectionKey = {
type: 'image',
dataID: id,
} as DataSelection;
const selectionKey = id as DataSelection;
const isLayer = layerImageIDs.includes(id);
const layerLoaded = loadedLayerImageIDs.includes(id);
const layerLoading = isLayer && !layerLoaded;
Expand Down Expand Up @@ -136,10 +128,7 @@ export default defineComponent({
function convertToLabelMap(key: string) {
if (primarySelection.value) {
segmentGroupStore.convertImageToLabelmap(
{ type: 'image', dataID: key },
primarySelection.value
);
segmentGroupStore.convertImageToLabelmap(key, primarySelection.value);
}
}
Expand Down Expand Up @@ -261,9 +250,9 @@ export default defineComponent({
image.layerable ? convertToLabelMap(image.id) : null
"
>
<v-icon v-if="!image.layerable" class="mr-1"
>mdi-alert</v-icon
>
<v-icon v-if="!image.layerable" class="mr-1">
mdi-alert
</v-icon>
Convert to Segment Group
<v-tooltip
activator="parent"
Expand Down
5 changes: 1 addition & 4 deletions src/components/LayerProperties.vue
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
<script lang="ts">
import { computed, defineComponent, PropType, toRefs } from 'vue';
import { getImageID } from '@/src/utils/dataSelection';
import { InitViewSpecs } from '../config';
import { useImageStore } from '../store/datasets-images';
import { BlendConfig } from '../types/views';
Expand All @@ -25,9 +24,7 @@ export default defineComponent({
const imageName = computed(() => {
const { selection } = props.layer;
const imageID = getImageID(selection);
if (imageID === undefined) throw new Error('imageID is undefined');
return imageStore.metadata[imageID].name;
return imageStore.metadata[selection].name;
});
const layerColoringStore = useLayerColoringStore();
Expand Down
2 changes: 1 addition & 1 deletion src/components/PatientBrowser.vue
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<script lang="ts">
import { computed, defineComponent, ref, toRefs, watch } from 'vue';
import ItemGroup from '@/src/components/ItemGroup.vue';
import { DataSelection, selectionEquals } from '@/src/utils/dataSelection';
import { type DataSelection, selectionEquals } from '@/src/utils/dataSelection';
import { useDICOMStore } from '../store/datasets-dicom';
import { useDatasetStore } from '../store/datasets';
import { useMultiSelection } from '../composables/useMultiSelection';
Expand Down
17 changes: 6 additions & 11 deletions src/components/PatientStudyVolumeBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { computed, defineComponent, reactive, toRefs, watch } from 'vue';
import { Image } from 'itk-wasm';
import type { PropType } from 'vue';
import GroupableItem from '@/src/components/GroupableItem.vue';
import { DataSelection, DICOMSelection } from '@/src/utils/dataSelection';
import { DataSelection, isDicomImage } from '@/src/utils/dataSelection';
import { getDisplayName, useDICOMStore } from '../store/datasets-dicom';
import { useDatasetStore } from '../store/datasets';
import { useMultiSelection } from '../composables/useMultiSelection';
Expand Down Expand Up @@ -78,21 +78,16 @@ export default defineComponent({
const primarySelection = primarySelectionRef.value;
const layerVolumes = layersStore
.getLayers(primarySelection)
.filter(({ selection }) => selection.type === 'dicom');
const layerVolumeKeys = layerVolumes.map(
({ selection }) => (selection as DICOMSelection).volumeKey
);
.filter(({ selection }) => isDicomImage(selection));
const layerVolumeKeys = layerVolumes.map(({ selection }) => selection);
const loadedLayerVolumeKeys = layerVolumes
.filter(({ id }) => id in layersStore.layerImages)
.map(({ selection }) => (selection as DICOMSelection).volumeKey);
.map(({ selection }) => selection);
const selectedVolumeKey =
primarySelection?.type === 'dicom' && primarySelection.volumeKey;
isDicomImage(primarySelection) && primarySelection;
return volumeKeys.value.map((volumeKey) => {
const selectionKey = {
type: 'dicom',
volumeKey,
} as DataSelection;
const selectionKey = volumeKey as DataSelection;
const isLayer = layerVolumeKeys.includes(volumeKey);
const layerLoaded = loadedLayerVolumeKeys.includes(volumeKey);
const layerLoading = isLayer && !layerLoaded;
Expand Down
8 changes: 3 additions & 5 deletions src/components/SampleDataBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,10 @@ export default defineComponent({
const selection = convertSuccessResultToDataSelection(loadResult);
if (selection) {
const id =
selection.type === 'image' ? selection.dataID : selection.volumeKey;
loaded.idToURL[id] = sample.url;
loaded.urlToID[sample.url] = id;
loaded.idToURL[selection] = sample.url;
loaded.urlToID[sample.url] = selection;
useVolumeColoringStore().setDefaults(id, {
useVolumeColoringStore().setDefaults(selection, {
transferFunction: {
preset: sample.defaults?.colorPreset,
},
Expand Down
8 changes: 8 additions & 0 deletions src/components/SliceViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ import VtkMouseInteractionManipulator from '@/src/components/vtk/VtkMouseInterac
import vtkMouseCameraTrackballPanManipulator from '@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballPanManipulator';
import vtkMouseCameraTrackballZoomToMouseManipulator from '@kitware/vtk.js/Interaction/Manipulators/MouseCameraTrackballZoomToMouseManipulator';
import { useResetViewsEvents } from '@/src/components/tools/ResetViews.vue';
import { whenever } from '@vueuse/core';
interface Props extends LayoutViewProps {
viewDirection: LPSAxisDir;
Expand Down Expand Up @@ -216,6 +217,13 @@ const { slice: currentSlice, range: sliceRange } = useSliceConfig(
currentImageID
);
whenever(
computed(() => !isImageLoading.value),
() => {
resetCamera();
}
);
// segmentations
const segmentations = computed(() => {
if (!currentImageID.value) return [];
Expand Down
8 changes: 8 additions & 0 deletions src/components/VolumeViewer.vue
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ import VtkOrientationMarker from '@/src/components/vtk/VtkOrientationMarker.vue'
import ViewOverlayGrid from '@/src/components/ViewOverlayGrid.vue';
import useVolumeColoringStore from '@/src/store/view-configs/volume-coloring';
import { useResetViewsEvents } from '@/src/components/tools/ResetViews.vue';
import { whenever } from '@vueuse/core';
interface Props extends LayoutViewProps {
viewDirection: LPSAxisDir;
Expand All @@ -100,6 +101,13 @@ useViewAnimationListener(vtkView, viewId, viewType);
// base image
const { currentImageID, isImageLoading } = useCurrentImage();
whenever(
computed(() => !isImageLoading.value),
() => {
resetCamera();
}
);
// color preset
const coloringStore = useVolumeColoringStore();
const coloringConfig = computed(() =>
Expand Down
15 changes: 5 additions & 10 deletions src/components/tools/windowing/WindowLevelControls.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import useWindowingStore, {
import { useViewStore } from '@/src/store/views';
import { WLAutoRanges, WLPresetsCT, WL_AUTO_DEFAULT } from '@/src/constants';
import { getWindowLevels, useDICOMStore } from '@/src/store/datasets-dicom';
import { isDicomImage } from '@/src/utils/dataSelection';
export default defineComponent({
setup() {
Expand All @@ -31,11 +32,8 @@ export default defineComponent({
// --- CT Preset Options --- //
const modality = computed(() => {
if (
currentImageID.value &&
currentImageID.value in dicomStore.imageIDToVolumeKey
) {
const volKey = dicomStore.imageIDToVolumeKey[currentImageID.value];
if (currentImageID.value && isDicomImage(currentImageID.value)) {
const volKey = currentImageID.value;
const { Modality } = dicomStore.volumeInfo[volKey];
return Modality;
}
Expand Down Expand Up @@ -98,11 +96,8 @@ export default defineComponent({
// --- Tag WL Options --- //
const tags = computed(() => {
if (
currentImageID.value &&
currentImageID.value in dicomStore.imageIDToVolumeKey
) {
const volKey = dicomStore.imageIDToVolumeKey[currentImageID.value];
if (currentImageID.value && isDicomImage(currentImageID.value)) {
const volKey = currentImageID.value;
return getWindowLevels(dicomStore.volumeInfo[volKey]);
}
return [];
Expand Down
14 changes: 4 additions & 10 deletions src/composables/useCurrentImage.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
import { useLayersStore } from '@/src/store/datasets-layers';
import { createLPSBounds, getAxisBounds } from '@/src/utils/lps';
import { useDatasetStore } from '@/src/store/datasets';
import { getDataSelection, getImageID } from '@/src/utils/dataSelection';
import { storeToRefs } from 'pinia';

export interface CurrentImageContext {
Expand Down Expand Up @@ -57,21 +56,16 @@ export function getImageData(imageID: Maybe<string>) {
}

export function getIsImageLoading(imageID: Maybe<string>) {
const dataStore = useDatasetStore();
if (!dataStore.primarySelection) return false;

const selectedImageID = getImageID(dataStore.primarySelection);
if (selectedImageID !== unref(imageID)) return false;

return !!dataStore.primarySelection && !dataStore.primaryDataset;
if (!imageID) return false;
const imageStore = useImageStore();
return !imageStore.dataIndex[imageID];
}

export function getImageLayers(imageID: Maybe<string>) {
if (!imageID) return [];
const selection = getDataSelection(imageID);
const layersStore = useLayersStore();
return layersStore
.getLayers(selection)
.getLayers(imageID)
.filter(({ id }) => id in layersStore.layerImages);
}

Expand Down
19 changes: 12 additions & 7 deletions src/composables/useSliceConfigInitializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ export function useSliceConfigInitializer(
) {
const store = useViewSliceStore();
const { config: sliceConfig } = useSliceConfig(viewID, imageID);
const { metadata } = useImage(imageID);
const { metadata, isLoading } = useImage(imageID);

const viewAxis = computed(() => getLPSAxisFromDir(unref(viewDirection)));
const sliceDomain = computed(() => {
Expand All @@ -33,17 +33,22 @@ export function useSliceConfigInitializer(
});

watchImmediate(
[toRef(sliceDomain), toRef(viewDirection)] as const,
([domain, axisDirection]) => {
[
toRef(sliceDomain),
toRef(viewDirection),
toRef(imageID),
isLoading,
] as const,
([domain, axisDirection, id, loading]) => {
if (loading || !id) return;

const configExisted = !!sliceConfig.value;
const imageIdVal = unref(imageID);
if (!imageIdVal) return;
store.updateConfig(unref(viewID), imageIdVal, {
store.updateConfig(unref(viewID), id, {
...domain,
axisDirection,
});
if (!configExisted) {
store.resetSlice(unref(viewID), imageIdVal);
store.resetSlice(unref(viewID), id);
}
}
);
Expand Down
6 changes: 3 additions & 3 deletions src/composables/useVolumeColoringInitializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ export function useVolumeColoringInitializer(
store.getConfig(unref(viewId), unref(imageId))
);

const { imageData } = useImage(imageId);
const { imageData, isLoading } = useImage(imageId);

watchImmediate(coloringConfig, (config) => {
if (config) return;
watchImmediate([coloringConfig, viewId, imageId, isLoading], () => {
if (coloringConfig.value || isLoading.value) return;

const viewIdVal = unref(viewId);
const imageIdVal = unref(imageId);
Expand Down
5 changes: 3 additions & 2 deletions src/composables/useWindowingConfigInitializer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import { getWindowLevels, useDICOMStore } from '@/src/store/datasets-dicom';
import useWindowingStore from '@/src/store/view-configs/windowing';
import { Maybe } from '@/src/types';
import { useResetViewsEvents } from '@/src/components/tools/ResetViews.vue';
import { isDicomImage } from '@/src/utils/dataSelection';

function useAutoRangeValues(imageID: MaybeRef<Maybe<string>>) {
const { imageData } = useImage(imageID);
Expand Down Expand Up @@ -80,8 +81,8 @@ export function useWindowingConfigInitializer(

const firstTag = computed(() => {
const id = unref(imageID);
if (id && id in dicomStore.imageIDToVolumeKey) {
const volKey = dicomStore.imageIDToVolumeKey[id];
if (id && isDicomImage(id)) {
const volKey = id;
const windowLevels = getWindowLevels(dicomStore.volumeInfo[volKey]);
if (windowLevels.length) {
return windowLevels[0];
Expand Down
Loading

0 comments on commit 9e650be

Please sign in to comment.