diff --git a/src/VTKViewport/View2D.js b/src/VTKViewport/View2D.js index a66dcf5b..4bc5d413 100644 --- a/src/VTKViewport/View2D.js +++ b/src/VTKViewport/View2D.js @@ -11,8 +11,11 @@ import vtkSVGWidgetManager from './vtkSVGWidgetManager'; import ViewportOverlay from '../ViewportOverlay/ViewportOverlay.js'; import { ViewTypes } from 'vtk.js/Sources/Widgets/Core/WidgetManager/Constants'; import { createSub } from '../lib/createSub.js'; +import realsApproximatelyEqual from '../lib/math/realsApproximatelyEqual'; import createLabelPipeline from './createLabelPipeline'; +const minSlabThickness = 0.1; // TODO -> Should this be configurable or not? + export default class View2D extends Component { static propTypes = { volumes: PropTypes.array.isRequired, @@ -27,10 +30,14 @@ export default class View2D extends Component { onCreated: PropTypes.func, onDestroyed: PropTypes.func, orientation: PropTypes.object, + labelmapRenderingOptions: PropTypes.object, }; static defaultProps = { painting: false, + labelmapRenderingOptions: { + visible: true, + }, }; constructor(props) { @@ -258,8 +265,6 @@ export default class View2D extends Component { if (currentIStyle.getSlabThickness) { return currentIStyle.getSlabThickness(); } - - //return this.currentSlabThickness; } setSlabThickness(slabThickness) { @@ -268,6 +273,23 @@ export default class View2D extends Component { if (istyle.setSlabThickness) { istyle.setSlabThickness(slabThickness); + + if (this.props.paintFilterLabelMapImageData) { + const labelmapActor = this.labelmap.actor; + + if (realsApproximatelyEqual(slabThickness, minSlabThickness)) { + if ( + labelmapActor.getVisibility() !== + this.props.labelmapRenderingOptions.visible + ) { + labelmapActor.setVisibility( + this.props.labelmapRenderingOptions.visible + ); + } + } else { + labelmapActor.setVisibility(false); + } + } } renderWindow.render(); @@ -392,7 +414,8 @@ export default class View2D extends Component { const labelmapImageData = this.props.paintFilterLabelMapImageData; const labelmap = createLabelPipeline( this.props.paintFilterBackgroundImageData, - labelmapImageData + labelmapImageData, + this.props.labelmapRenderingOptions ); this.labelmap = labelmap; @@ -410,6 +433,16 @@ export default class View2D extends Component { ); } + if ( + prevProps.labelmapRenderingOptions && + prevProps.labelmapRenderingOptions.visible !== + this.props.labelmapRenderingOptions.visible + ) { + this.labelmap.actor.setVisibility( + prevProps.labelmapRenderingOptions.visible + ); + } + if (prevProps.painting !== this.props.painting) { if (this.props.painting) { this.viewWidget = this.widgetManager.addWidget( diff --git a/src/VTKViewport/View3D.js b/src/VTKViewport/View3D.js index 2379662d..14d7d835 100644 --- a/src/VTKViewport/View3D.js +++ b/src/VTKViewport/View3D.js @@ -24,11 +24,15 @@ export default class View3D extends Component { dataDetails: PropTypes.object, onCreated: PropTypes.func, onDestroyed: PropTypes.func, + labelmapRenderingOptions: PropTypes.object, }; static defaultProps = { painting: false, sliceNormal: [0, 0, 1], + labelmapRenderingOptions: { + visible: true, + }, }; constructor(props) { @@ -189,6 +193,7 @@ export default class View3D extends Component { const labelmap = createLabelPipeline( this.props.paintFilterBackgroundImageData, labelmapImageData, + this.props.labelmapRenderingOptions, true ); diff --git a/src/VTKViewport/createLabelPipeline.js b/src/VTKViewport/createLabelPipeline.js index e2858228..6ea9ccfb 100644 --- a/src/VTKViewport/createLabelPipeline.js +++ b/src/VTKViewport/createLabelPipeline.js @@ -8,10 +8,21 @@ import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunct export default function createLabelPipeline( backgroundImageData, paintFilterLabelMapImageData, + options, useSampleDistance = false ) { let labelMapData; + let { colorLUT, globalOpacity, visible } = options; + + if (visible === undefined) { + visible = false; + } + + if (globalOpacity === undefined) { + globalOpacity = 1.0; + } + if (paintFilterLabelMapImageData) { labelMapData = paintFilterLabelMapImageData; } else { @@ -53,17 +64,41 @@ export default function createLabelPipeline( // labelmap pipeline labelMap.actor.setMapper(labelMap.mapper); + labelMap.actor.setVisibility(visible); + labelMap.ofun.addPoint(0, 0); // set up labelMap color and opacity mapping - labelMap.cfun.addRGBPoint(1, 1, 0, 0); // label '1' will be red - labelMap.cfun.addRGBPoint(2, 0, 1, 0); // label '2' will be green - labelMap.cfun.addRGBPoint(3, 0, 1, 1); // label '3' will be blue - labelMap.ofun.addPoint(0, 0); - labelMap.ofun.addPoint(1, 0.9); + if (colorLUT) { + // TODO -> It seems to crash if you set it higher than 256?? + const numColors = Math.min(256, colorLUT.length); + + for (let i = 0; i < numColors; i++) { + //for (let i = 0; i < colorLUT.length; i++) { + const color = colorLUT[i]; + labelMap.cfun.addRGBPoint( + i, + color[0] / 255, + color[1] / 255, + color[2] / 255 + ); + + const segmentOpacity = (color[3] / 255) * globalOpacity; + labelMap.ofun.addPointLong(i, segmentOpacity, 0.5, 1.0); + } + } else { + // Some default. + labelMap.cfun.addRGBPoint(1, 1, 0, 0); // label '1' will be red + labelMap.cfun.addRGBPoint(2, 0, 1, 0); // label '2' will be green + labelMap.cfun.addRGBPoint(3, 0, 1, 1); // label '3' will be blue + labelMap.ofun.addPoint(1, 0.5); // All labels full opacity + } labelMap.actor.getProperty().setRGBTransferFunction(0, labelMap.cfun); labelMap.actor.getProperty().setScalarOpacity(0, labelMap.ofun); + labelMap.actor.getProperty().setInterpolationTypeToNearest(); + labelMap.actor.getProperty().setScalarOpacityUnitDistance(0, 0.1); + labelMap.actor.getProperty().setUseGradientOpacity(0, false); return labelMap; } diff --git a/src/helpers/formatDA.js b/src/helpers/formatDA.js index 582291d2..d0e7f936 100644 --- a/src/helpers/formatDA.js +++ b/src/helpers/formatDA.js @@ -5,7 +5,12 @@ export default function formatDA(date, strFormat = 'MMM D, YYYY') { return; } - const parsedDateTime = parse(date, 'YYYYMMDD'); + try { + const parsedDateTime = parse(date, 'yyyyMMdd', new Date()); + const formattedDateTime = format(parsedDateTime, strFormat); - return format(parsedDateTime, strFormat); + return formattedDateTime; + } catch (err) { + // swallow? + } } diff --git a/src/helpers/formatTM.js b/src/helpers/formatTM.js index 48afc843..14567ecc 100644 --- a/src/helpers/formatTM.js +++ b/src/helpers/formatTM.js @@ -5,14 +5,16 @@ export default function formatTM(time, strFormat = 'HH:mm:ss') { return; } - // DICOM Time is stored as HHmmss.SSS, where: - // HH 24 hour time: - // m mm 0..59 Minutes - // s ss 0..59 Seconds - // S SS SSS 0..999 Fractional seconds - // - // See MomentJS: http://momentjs.com/docs/#/parsing/string-format/ - const parsedDateTime = parse(time, 'HHmmss.SSS'); + try { + const inputFormat = 'HHmmss.SSS'; + const strTime = time.toString().substring(0, inputFormat.length); + const parsedDateTime = parse(strTime, 'HHmmss.SSS', new Date(0)); + const formattedDateTime = format(parsedDateTime, strFormat); + + return formattedDateTime; + } catch (err) { + // swallow? + } return format(parsedDateTime, strFormat); }