Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions src/components/SampleDataBrowser.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
importDataSources,
} from '@/src/io/import/importDataSources';
import { remoteFileToDataSource } from '@/src/io/import/dataSource';
import useVolumeColoringStore from '@/src/store/view-configs/volume-coloring';
import { SAMPLE_DATA } from '../config';
import { useMessageStore } from '../store/messages';
import { SampleDataset } from '../types';
Expand Down Expand Up @@ -105,6 +106,12 @@ export default defineComponent({
selection.type === 'image' ? selection.dataID : selection.volumeKey;
loaded.idToURL[id] = sample.url;
loaded.urlToID[sample.url] = id;

useVolumeColoringStore().setDefaults(id, {
transferFunction: {
preset: sample.defaults?.colorPreset,
},
});
}
datasetStore.setPrimarySelection(selection);
} catch (error) {
Expand Down
3 changes: 3 additions & 0 deletions src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,9 @@ export const SAMPLE_DATA: SampleDataset[] = [
'3D ultrasound of a baby. Downloaded from tomovision.com.(8 MB)',
url: 'https://data.kitware.com/api/v1/item/635679c311dab8142820a4f4/download',
image: USFetusThumbnail,
defaults: {
colorPreset: 'US-Fetal',
},
},
];

Expand Down
72 changes: 56 additions & 16 deletions src/store/view-configs/volume-coloring.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import {
getDoubleKeyRecord,
patchDoubleKeyRecord,
} from '@/src/utils/doubleKeyRecord';
import { Maybe } from '@/src/types';
import { DeepPartial, Maybe } from '@/src/types';
import { identity } from '@/src/utils';
import { createViewConfigSerializer } from './common';
import { DEFAULT_PRESET } from '../../vtk/ColorMaps';
Expand All @@ -39,6 +39,26 @@ function getPresetFromImageModality(imageID: string) {
return DEFAULT_PRESET;
}

/**
* Gets partial color and opacity function configs from a preset.
* @param preset
* @returns
*/
function getColorAndOpacityFuncsFromPreset(preset: string) {
const ctFunc: Partial<ColorTransferFunction> = {
preset,
};

const ctRange = getColorFunctionRangeFromPreset(preset);
if (ctRange) {
ctFunc.mappingRange = ctRange;
}

const opFunc = getOpacityFunctionFromPreset(preset);

return { colorFunc: ctFunc, opacityFunc: opFunc };
}

export const defaultVolumeColorConfig = (): VolumeColorConfig => ({
colorBy: {
arrayName: '',
Expand Down Expand Up @@ -69,7 +89,12 @@ export const defaultVolumeColorConfig = (): VolumeColorConfig => ({
});

export const useVolumeColoringStore = defineStore('volumeColoring', () => {
const configs = reactive<DoubleKeyRecord<VolumeColorConfig>>({});
const configs = reactive<DoubleKeyRecord<VolumeColorConfig>>(
Object.create(null)
);
const defaultConfigs = reactive<
Record<string, DeepPartial<VolumeColorConfig>>
>(Object.create(null));

const getConfig = (viewID: Maybe<string>, dataID: Maybe<string>) =>
getDoubleKeyRecord(configs, viewID, dataID);
Expand Down Expand Up @@ -114,33 +139,47 @@ export const useVolumeColoringStore = defineStore('volumeColoring', () => {
const setColorPreset = (viewID: string, imageID: string, preset: string) => {
const imageStore = useImageStore();
const image = imageStore.dataIndex[imageID];
if (!image) return;
const imageDataRange = image.getPointData().getScalars().getRange();
if (!image) throw new Error('Invalid imageID');

const ctRange = getColorFunctionRangeFromPreset(preset);
const ctFunc: Partial<ColorTransferFunction> = {
preset,
mappingRange: ctRange || imageDataRange,
};
updateColorTransferFunction(viewID, imageID, ctFunc);
const imageDataRange = image.getPointData().getScalars().getRange();
const { colorFunc, opacityFunc } =
getColorAndOpacityFuncsFromPreset(preset);
colorFunc.mappingRange ||= imageDataRange;
opacityFunc.mappingRange = imageDataRange;

const opFunc = getOpacityFunctionFromPreset(preset);
opFunc.mappingRange = imageDataRange;
updateOpacityFunction(viewID, imageID, opFunc);
updateColorTransferFunction(viewID, imageID, colorFunc);
updateOpacityFunction(viewID, imageID, opacityFunc);
};

const resetToDefaultColoring = (
viewID: string,
dataID: string,
image: vtkImageData
) => {
const defaults = defaultConfigs[dataID];
const scalars = image.getPointData().getScalars();

updateColorBy(viewID, dataID, {
arrayName: scalars.getName(),
location: 'pointData',
arrayName: defaults?.colorBy?.arrayName ?? scalars.getName(),
location: defaults?.colorBy?.location ?? 'pointData',
});
setColorPreset(viewID, dataID, getPresetFromImageModality(dataID));
setColorPreset(
viewID,
dataID,
defaults?.transferFunction?.preset ?? getPresetFromImageModality(dataID)
);
};

/**
* Sets the view config defaults for a dataset.
* @param dataID
* @param defaults
*/
const setDefaults = (
dataID: string,
defaults: DeepPartial<VolumeColorConfig>
) => {
defaultConfigs[dataID] = defaults;
};

const removeView = (viewID: string) => {
Expand Down Expand Up @@ -174,6 +213,7 @@ export const useVolumeColoringStore = defineStore('volumeColoring', () => {
updateOpacityFunction,
updateCVRParameters,
resetToDefaultColoring,
setDefaults,
setColorPreset,
removeView,
removeData,
Expand Down
9 changes: 9 additions & 0 deletions src/types/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,9 @@ export type SampleDataset = {
description: string;
url: string;
image: string;
defaults?: {
colorPreset?: string;
};
};

export type RequiredWithPartial<T, K extends keyof T> = Required<Omit<T, K>> &
Expand Down Expand Up @@ -48,3 +51,9 @@ export type TypedArrayConstructorName =
| 'Int32Array'
| 'Float32Array'
| 'Float64Array';

export type DeepPartial<T> = T extends object
? {
[P in keyof T]?: DeepPartial<T[P]>;
}
: T;