1- import { MaybeRef , computed , unref , watch } from 'vue' ;
2- import * as Comlink from 'comlink' ;
3- import vtkDataArray from '@kitware/vtk.js/Common/Core/DataArray' ;
4- import { computedAsync , watchImmediate } from '@vueuse/core' ;
1+ import { MaybeRef , computed , unref } from 'vue' ;
2+ import { watchImmediate } from '@vueuse/core' ;
53import { useImage } from '@/src/composables/useCurrentImage' ;
6- import { useWindowingConfig } from '@/src/composables/useWindowingConfig' ;
7- import { WLAutoRanges , WL_AUTO_DEFAULT , WL_HIST_BINS } from '@/src/constants' ;
84import { getWindowLevels , useDICOMStore } from '@/src/store/datasets-dicom' ;
9- import { vtkFieldRef } from '@/src/core/vtk/vtkFieldRef' ;
10- import useWindowingStore from '@/src/store/view-configs/windowing' ;
5+ import { useWindowingStore } from '@/src/store/view-configs/windowing' ;
116import { Maybe } from '@/src/types' ;
127import { useResetViewsEvents } from '@/src/components/tools/ResetViews.vue' ;
138import { isDicomImage } from '@/src/utils/dataSelection' ;
14- import { HistogramWorker } from '@/src/utils/histogram.worker' ;
15-
16- function useAutoRangeValues ( imageID : MaybeRef < Maybe < string > > ) {
17- const { imageData, isLoading : isImageLoading } = useImage ( imageID ) ;
18-
19- const worker = Comlink . wrap < HistogramWorker > (
20- new Worker ( new URL ( '@/src/utils/histogram.worker.ts' , import . meta. url ) , {
21- type : 'module' ,
22- } )
23- ) ;
24-
25- const scalars = vtkFieldRef (
26- computed ( ( ) => imageData . value ?. getPointData ( ) ) ,
27- 'scalars'
28- ) ;
29-
30- const autoRangeValues = computedAsync ( async ( ) => {
31- if ( isImageLoading . value || ! scalars . value ) {
32- return { } ;
33- }
34-
35- // Pre-compute the auto-range values
36- const scalarData = scalars . value . getData ( ) ;
37- // Assumes all data is one component
38- const { min, max } = vtkDataArray . fastComputeRange (
39- scalarData as number [ ] ,
40- 0 ,
41- 1
42- ) ;
43- const hist = await worker . histogram ( scalarData , [ min , max ] , WL_HIST_BINS ) ;
44- const cumm = hist . reduce ( ( acc , val , idx ) => {
45- const prev = idx !== 0 ? acc [ idx - 1 ] : 0 ;
46- acc . push ( val + prev ) ;
47- return acc ;
48- } , [ ] ) ;
49-
50- const width = ( max - min + 1 ) / WL_HIST_BINS ;
51- return Object . fromEntries (
52- Object . entries ( WLAutoRanges ) . map ( ( [ key , value ] ) => {
53- const startIdx = cumm . findIndex (
54- ( v : number ) => v >= value * 0.01 * scalarData . length
55- ) ;
56- const endIdx = cumm . findIndex (
57- ( v : number ) => v >= ( 1 - value * 0.01 ) * scalarData . length
58- ) ;
59- const start = Math . max ( min , min + width * startIdx ) ;
60- const end = Math . min ( max , min + width * endIdx + width ) ;
61- return [ key , [ start , end ] ] ;
62- } )
63- ) ;
64- } , { } ) ;
65-
66- return { autoRangeValues } ;
67- }
9+ import { WL_AUTO_DEFAULT } from '../constants' ;
6810
6911export function useWindowingConfigInitializer (
7012 viewID : MaybeRef < string > ,
@@ -73,18 +15,7 @@ export function useWindowingConfigInitializer(
7315 const { imageData } = useImage ( imageID ) ;
7416 const dicomStore = useDICOMStore ( ) ;
7517
76- const scalarRange = vtkFieldRef (
77- computed ( ( ) => imageData . value ?. getPointData ( ) ?. getScalars ( ) ) ,
78- 'range'
79- ) ;
80-
8118 const store = useWindowingStore ( ) ;
82- const { config : windowConfig } = useWindowingConfig ( viewID , imageID ) ;
83- const { autoRangeValues } = useAutoRangeValues ( imageID ) ;
84- const autoRange = computed < keyof typeof WLAutoRanges > (
85- ( ) => windowConfig . value ?. auto || WL_AUTO_DEFAULT
86- ) ;
87-
8819 const firstTag = computed ( ( ) => {
8920 const id = unref ( imageID ) ;
9021 if ( id && isDicomImage ( id ) ) {
@@ -96,94 +27,52 @@ export function useWindowingConfigInitializer(
9627 return undefined ;
9728 } ) ;
9829
99- watchImmediate ( windowConfig , ( config ) => {
100- const image = imageData . value ;
101- const imageIdVal = unref ( imageID ) ;
102- const viewIdVal = unref ( viewID ) ;
103- if ( config || ! image || ! imageIdVal ) return ;
104-
105- const [ min , max ] = image . getPointData ( ) . getScalars ( ) . getRange ( ) ;
106- store . updateConfig ( viewIdVal , imageIdVal , { min, max } ) ;
107- store . resetWindowLevel ( viewIdVal , imageIdVal ) ;
108- } ) ;
109-
110- watchImmediate ( scalarRange , ( range ) => {
111- const imageIdVal = unref ( imageID ) ;
112- const viewIdVal = unref ( viewID ) ;
113- if ( ! range || ! imageIdVal || ! viewIdVal ) return ;
114- store . updateConfig ( viewIdVal , imageIdVal , { min : range [ 0 ] , max : range [ 1 ] } ) ;
115- } ) ;
116-
117- function updateConfigFromAutoRangeValues ( ) {
30+ function resetWidthLevel ( ) {
11831 const imageIdVal = unref ( imageID ) ;
11932 const viewIdVal = unref ( viewID ) ;
12033 if ( imageIdVal == null ) {
12134 return ;
12235 }
12336
124- if ( autoRange . value in autoRangeValues . value ) {
125- const [ min , max ] = autoRangeValues . value [ autoRange . value ] ;
126- store . updateConfig ( viewIdVal , imageIdVal , {
127- min,
128- max,
129- } ) ;
130- }
37+ store . updateConfig ( viewIdVal , imageIdVal , {
38+ auto : WL_AUTO_DEFAULT ,
39+ } ) ;
13140
13241 const firstTagVal = unref ( firstTag ) ;
13342 if ( firstTagVal ?. width ) {
13443 store . updateConfig ( viewIdVal , imageIdVal , {
135- preset : {
136- width : firstTagVal . width ,
137- level : firstTagVal . level ,
138- } ,
44+ width : firstTagVal . width ,
45+ level : firstTagVal . level ,
13946 } ) ;
14047 }
14148
142- const forcedWL = store . runtimeConfigWindowLevel ;
143- if ( forcedWL ) {
49+ const widthLevel = store . runtimeConfigWindowLevel ;
50+ if ( widthLevel ) {
14451 store . updateConfig ( viewIdVal , imageIdVal , {
145- preset : {
146- ...forcedWL ,
147- } ,
52+ ...widthLevel ,
14853 } ) ;
14954 }
150-
151- store . resetWindowLevel ( viewIdVal , imageIdVal ) ;
15255 }
15356
15457 watchImmediate (
155- [ imageData , autoRangeValues ] ,
58+ [ imageData ] ,
15659 ( ) => {
157- if ( ! imageData . value ) {
60+ const imageIdValue = unref ( imageID ) ;
61+ if ( ! imageData . value || ! imageIdValue ) {
15862 return ;
15963 }
16064
161- updateConfigFromAutoRangeValues ( ) ;
65+ const config = store . getConfig ( unref ( viewID ) , imageIdValue ) . value ;
66+ if ( config ?. userTriggered ) {
67+ return ;
68+ }
69+
70+ resetWidthLevel ( ) ;
16271 } ,
16372 { deep : true }
16473 ) ;
16574
166- watch ( autoRange , ( percentile ) => {
167- const image = imageData . value ;
168- const imageIdVal = unref ( imageID ) ;
169- const viewIdVal = unref ( viewID ) ;
170- if ( imageIdVal == null || windowConfig . value == null || ! image ) {
171- return ;
172- }
173- const range = autoRangeValues . value [ percentile ] ;
174- store . updateConfig ( viewIdVal , imageIdVal , {
175- min : range [ 0 ] ,
176- max : range [ 1 ] ,
177- } ) ;
178- store . resetWindowLevel ( viewIdVal , imageIdVal ) ;
179- } ) ;
180-
18175 useResetViewsEvents ( ) . onClick ( ( ) => {
182- const imageIdVal = unref ( imageID ) ;
183- const viewIdVal = unref ( viewID ) ;
184- if ( imageIdVal == null || windowConfig . value == null ) {
185- return ;
186- }
187- store . resetWindowLevel ( viewIdVal , imageIdVal ) ;
76+ resetWidthLevel ( ) ;
18877 } ) ;
18978}
0 commit comments