@@ -39,7 +39,6 @@ import { ZoomSlider, Zoom } from 'ol/control'
3939import { getCenter , getHeight , getWidth } from 'ol/extent'
4040import { defaults as defaultInteractions } from 'ol/interaction'
4141import dcmjs from 'dcmjs'
42- import { quantileSeq } from 'mathjs'
4342
4443import {
4544 AnnotationGroup ,
@@ -65,14 +64,17 @@ import { ParameterMapping, _groupFramesPerMapping } from './mapping.js'
6564import { ROI } from './roi.js'
6665import { Segment } from './segment.js'
6766import {
67+ areCodedConceptsEqual ,
6868 applyTransform ,
6969 buildInverseTransform ,
7070 buildTransform ,
7171 computeRotation ,
72+ getContentItemNameCodedConcept ,
7273 _generateUID ,
7374 _getUnitSuffix ,
7475 doContentItemsMatch ,
75- createWindow
76+ createWindow ,
77+ rgb2hex
7678} from './utils.js'
7779import {
7880 _scoord3dCoordinates2geometryCoordinates ,
@@ -630,7 +632,7 @@ function _getColorInterpolationStyleForTileLayer ({
630632 * @private
631633 */
632634function _getColorPaletteStyleForPointLayer ( {
633- name ,
635+ key ,
634636 minValue,
635637 maxValue,
636638 colormap
@@ -649,7 +651,7 @@ function _getColorPaletteStyleForPointLayer ({
649651 '*' ,
650652 [
651653 '-' ,
652- [ 'get' , name ] ,
654+ [ 'get' , key ] ,
653655 minValue
654656 ] ,
655657 [
@@ -674,7 +676,7 @@ function _getColorPaletteStyleForPointLayer ({
674676 const expression = [
675677 'palette' ,
676678 indexExpression ,
677- colormap
679+ colormap . map ( c => rgb2hex ( c ) )
678680 ]
679681
680682 return { color : expression }
@@ -2935,7 +2937,7 @@ class VolumeImageViewer {
29352937
29362938 const defaultAnnotationGroupStyle = {
29372939 opacity : 1.0 ,
2938- color : '#027ea3'
2940+ color : [ 2 , 126 , 163 ]
29392941 }
29402942
29412943 metadata . AnnotationGroupSequence . forEach ( ( item , index ) => {
@@ -3019,6 +3021,7 @@ class VolumeImageViewer {
30193021 const graphicIndex = retrievedBulkdata [ 1 ]
30203022 const measurements = retrievedBulkdata [ 2 ]
30213023
3024+ console . log ( 'process annotations' )
30223025 for ( let i = 0 ; i < numberOfAnnotations ; i ++ ) {
30233026 const point = _getCentroid (
30243027 graphicType ,
@@ -3038,13 +3041,11 @@ class VolumeImageViewer {
30383041 geometry : new PointGeometry ( coordinates )
30393042 } )
30403043 const properties = { }
3041- measurements . forEach ( item => {
3042- const name = item . name
3043- const key = `${ name . CodingSchemeDesignator } ${ name . CodeValue } `
3044- const value = item . values [ i ]
3045- properties [ key ] = value
3044+ measurements . forEach ( ( measurementItem , measurementIndex ) => {
3045+ const value = measurementItem . values [ i ]
3046+ properties [ measurementIndex ] = value
30463047 } )
3047- feature . setProperties ( properties )
3048+ feature . setProperties ( properties , true )
30483049 feature . setId ( i + 1 )
30493050 features . push ( feature )
30503051 }
@@ -3054,17 +3055,27 @@ class VolumeImageViewer {
30543055 `for annotation group "${ annotationGroupUID } "`
30553056 )
30563057 this . addFeatures ( features )
3058+ console . info (
3059+ 'compute statistics for measurement values ' +
3060+ `of annotation group "${ annotationGroupUID } "`
3061+ )
30573062 const properties = { }
3058- measurements . forEach ( item => {
3059- const name = item . name
3060- const key = `${ name . CodingSchemeDesignator } ${ name . CodeValue } `
3061- const value = quantileSeq (
3062- [ ...item . values ] ,
3063- [ 0 , 0.015 , 0.25 , 0.5 , 0.75 , 0.95 , 1 ]
3063+ measurements . forEach ( ( measurementItem , measurementIndex ) => {
3064+ /*
3065+ * Ideally, we would compute quantiles, but that is an expensive
3066+ * operation. For now, just compute mininum and maximum.
3067+ */
3068+ const min = measurementItem . values . reduce (
3069+ ( a , b ) => Math . min ( a , b ) ,
3070+ Infinity
3071+ )
3072+ const max = measurementItem . values . reduce (
3073+ ( a , b ) => Math . max ( a , b ) ,
3074+ - Infinity
30643075 )
3065- properties [ key ] = value
3076+ properties [ measurementIndex ] = { min , max }
30663077 } )
3067- this . setProperties ( properties )
3078+ this . setProperties ( properties , true )
30683079 success ( features )
30693080 } ) . catch ( error => {
30703081 console . error ( error )
@@ -3076,8 +3087,7 @@ class VolumeImageViewer {
30763087 loader,
30773088 wrapX : false ,
30783089 rotateWithView : true ,
3079- overlaps : false ,
3080- features : new Collection ( [ ] , { unique : true } )
3090+ overlaps : false
30813091 } )
30823092 source . on ( 'featuresloadstart' , ( event ) => {
30833093 const container = this [ _map ] . getTargetElement ( )
@@ -3116,8 +3126,7 @@ class VolumeImageViewer {
31163126 }
31173127 annotationGroup . layer = new PointsLayer ( {
31183128 source,
3119- style,
3120- disableHitDetection : true
3129+ style
31213130 } )
31223131 annotationGroup . layer . setVisible ( false )
31233132
@@ -3159,7 +3168,9 @@ class VolumeImageViewer {
31593168 *
31603169 * @param {string } annotationGroupUID - Unique identifier of an annotation group
31613170 * @param {Object } styleOptions
3162- * @param {number } styleOptions.measurement - Selected measurement for colorizing annotations
3171+ * @param {number } [styleOptions.opacity] - Opacity
3172+ * @param {number[] } [styleOptions.color] - RGB color triplet
3173+ * @param {Object } [styleOptions.measurement] - Selected measurement
31633174 */
31643175 showAnnotationGroup ( annotationGroupUID , styleOptions = { } ) {
31653176 if ( ! ( annotationGroupUID in this [ _annotationGroups ] ) ) {
@@ -3212,8 +3223,10 @@ class VolumeImageViewer {
32123223 *
32133224 * @param {string } annotationGroupUID - Unique identifier of an annotation group
32143225 * @param {Object } styleOptions - Style options
3215- * @param {number } styleOptions.opacity - Opacity
3216- * @param {number } styleOptions.measurement - Selected measurement for colorizing annotations
3226+ * @param {number } [styleOptions.opacity] - Opacity
3227+ * @param {number[] } [styleOptions.color] - RGB color triplet
3228+ * @param {Object } [styleOptions.measurement] - Selected measurement for
3229+ * colorizing annotations
32173230 */
32183231 setAnnotationGroupStyle ( annotationGroupUID , styleOptions = { } ) {
32193232 if ( ! ( annotationGroupUID in this [ _annotationGroups ] ) ) {
@@ -3227,13 +3240,40 @@ class VolumeImageViewer {
32273240 annotationGroup . style . opacity = styleOptions . opacity
32283241 annotationGroup . layer . setOpacity ( styleOptions . opacity )
32293242 }
3243+ if ( styleOptions . color != null ) {
3244+ annotationGroup . style . color = styleOptions . color
3245+ }
3246+ console . info (
3247+ `set style for annotation group "${ annotationGroupUID } "` ,
3248+ styleOptions
3249+ )
32303250
3251+ const metadata = annotationGroup . metadata
32313252 const source = annotationGroup . layer . getSource ( )
3253+ const groupItem = metadata . AnnotationGroupSequence . find ( item => {
3254+ return item . AnnotationGroupUID === annotationGroupUID
3255+ } )
3256+ if ( groupItem == null ) {
3257+ throw new Error (
3258+ 'Cannot set style of annotation group. ' +
3259+ `Could not find metadata of annotation group "${ annotationGroupUID } ".`
3260+ )
3261+ }
3262+
32323263 const name = styleOptions . measurement
32333264 if ( name ) {
3234- const key = `${ name . CodingSchemeDesignator } ${ name . CodeValue } `
3265+ const measurementIndex = groupItem . MeasurementsSequence . findIndex ( item => {
3266+ return areCodedConceptsEqual ( name , getContentItemNameCodedConcept ( item ) )
3267+ } )
3268+ if ( measurementIndex == null ) {
3269+ throw new Error (
3270+ 'Cannot set style of annotation group. ' +
3271+ `Could not find measurement "${ name . CodeMeaning } " ` +
3272+ `of annotation group "${ annotationGroupUID } ".`
3273+ )
3274+ }
32353275 const properties = source . getProperties ( )
3236- if ( properties [ key ] ) {
3276+ if ( properties [ measurementIndex ] ) {
32373277 const colormap = createColormap ( {
32383278 name : ColormapNames . VIRIDIS ,
32393279 bins : 50
@@ -3256,16 +3296,17 @@ class VolumeImageViewer {
32563296 Object . assign (
32573297 style ,
32583298 _getColorPaletteStyleForPointLayer ( {
3259- name : key ,
3260- minValue : properties [ key ] [ 0 ] ,
3261- maxValue : properties [ key ] [ properties [ key ] . length - 2 ] ,
3299+ key : measurementIndex ,
3300+ minValue : properties [ measurementIndex ] . min ,
3301+ maxValue : properties [ measurementIndex ] . max ,
32623302 colormap
32633303 } )
32643304 )
32653305 const newLayer = new PointsLayer ( {
32663306 source,
32673307 style,
3268- disableHitDetection : true
3308+ disableHitDetection : true ,
3309+ visible : false
32693310 } )
32703311 this [ _map ] . addLayer ( newLayer )
32713312 this [ _map ] . removeLayer ( annotationGroup . layer )
@@ -3285,20 +3326,22 @@ class VolumeImageViewer {
32853326 this [ _pyramid ] . metadata . length ,
32863327 15
32873328 ] ,
3288- color : annotationGroup . style . color ,
3329+ color : rgb2hex ( annotationGroup . style . color ) ,
32893330 opacity : annotationGroup . style . opacity
32903331 }
32913332 }
32923333 const newLayer = new PointsLayer ( {
32933334 source,
32943335 style,
3295- disableHitDetection : true
3336+ disableHitDetection : true ,
3337+ visible : false
32963338 } )
32973339 this [ _map ] . addLayer ( newLayer )
32983340 this [ _map ] . removeLayer ( annotationGroup . layer )
32993341 annotationGroup . layer . dispose ( )
33003342 annotationGroup . layer = newLayer
33013343 }
3344+ annotationGroup . layer . setVisible ( true )
33023345 }
33033346
33043347 /**
0 commit comments