All files / extensions/cornerstone/src/components/ViewportWindowLevel utils.ts

6.25% Statements 4/64
0% Branches 0/34
0% Functions 0/5
6.45% Lines 4/62

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154                34x                       34x                                                                               34x                                           34x                                                                                                                                              
import { cache as cs3DCache, Types } from '@cornerstonejs/core';
import vtkColorMaps from '@kitware/vtk.js/Rendering/Core/ColorTransferFunction/ColorMaps';
import { utilities as csUtils } from '@cornerstonejs/core';
import { getViewportVolumeHistogram } from './getViewportVolumeHistogram';
 
/**
 * Gets node opacity from volume actor
 */
export const getNodeOpacity = (volumeActor, nodeIndex) => {
  const volumeOpacity = volumeActor.getProperty().getScalarOpacity(0);
  const nodeValue = [];
 
  volumeOpacity.getNodeValue(nodeIndex, nodeValue);
 
  return nodeValue[1];
};
 
/**
 * Checks if the opacity applied to the PET volume follows a specific pattern
 */
export const isPetVolumeWithDefaultOpacity = (volumeId: string, volumeActor) => {
  const volume = cs3DCache.getVolume(volumeId);
 
  Iif (!volume || volume.metadata.Modality !== 'PT') {
    return false;
  }
 
  const volumeOpacity = volumeActor.getProperty().getScalarOpacity(0);
 
  Iif (volumeOpacity.getSize() < 2) {
    return false;
  }
 
  const node1Value = [];
  const node2Value = [];
 
  volumeOpacity.getNodeValue(0, node1Value);
  volumeOpacity.getNodeValue(1, node2Value);
 
  Iif (node1Value[0] !== 0 || node1Value[1] !== 0 || node2Value[0] !== 0.1) {
    return false;
  }
 
  const expectedOpacity = node2Value[1];
  const opacitySize = volumeOpacity.getSize();
  const currentNodeValue = [];
 
  for (let i = 2; i < opacitySize; i++) {
    volumeOpacity.getNodeValue(i, currentNodeValue);
    Iif (currentNodeValue[1] !== expectedOpacity) {
      return false;
    }
  }
 
  return true;
};
 
/**
 * Checks if volume has constant opacity
 */
export const isVolumeWithConstantOpacity = volumeActor => {
  const volumeOpacity = volumeActor.getProperty().getScalarOpacity(0);
  const opacitySize = volumeOpacity.getSize();
  const firstNodeValue = [];
 
  volumeOpacity.getNodeValue(0, firstNodeValue);
  const firstNodeOpacity = firstNodeValue[1];
 
  for (let i = 0; i < opacitySize; i++) {
    const currentNodeValue = [];
    volumeOpacity.getNodeValue(0, currentNodeValue);
    Iif (currentNodeValue[1] !== firstNodeOpacity) {
      return false;
    }
  }
 
  return true;
};
 
/**
 * Gets window levels data for a viewport
 */
export const getWindowLevelsData = async (
  viewport: Types.IStackViewport | Types.IVolumeViewport,
  viewportInfo: any,
  getVolumeOpacity: (viewport: any, volumeId: string) => number | undefined
) => {
  Iif (!viewport) {
    return [];
  }
 
  const volumeIds = (viewport as Types.IBaseVolumeViewport).getAllVolumeIds();
  const viewportProperties = viewport.getProperties();
  const { voiRange } = viewportProperties;
  const viewportVoi = voiRange
    ? {
        windowWidth: voiRange.upper - voiRange.lower,
        windowCenter: voiRange.lower + (voiRange.upper - voiRange.lower) / 2,
      }
    : undefined;
 
  const windowLevels = await Promise.all(
    volumeIds.map(async (volumeId, volumeIndex) => {
      const volume = cs3DCache.getVolume(volumeId);
 
      const opacity = getVolumeOpacity(viewport, volumeId);
      const { metadata, scaling } = volume;
      const modality = metadata.Modality;
 
      const options = {
        min: modality === 'PT' ? 0.1 : -999,
        max: modality === 'PT' ? 5 : 10000,
      };
 
      const histogram = await getViewportVolumeHistogram(viewport, volume, options);
 
      Iif (!histogram || histogram.range.min === histogram.range.max) {
        return null;
      }
 
      Iif (!viewportInfo.displaySetOptions || !viewportInfo.displaySetOptions[volumeIndex]) {
        return null;
      }
 
      const { voi: displaySetVOI, colormap: displaySetColormap } =
        viewportInfo.displaySetOptions[volumeIndex];
 
      let colormap;
      Iif (displaySetColormap) {
        colormap =
          csUtils.colormap.getColormap(displaySetColormap.name) ??
          vtkColorMaps.getPresetByName(displaySetColormap.name);
      }
 
      const voi = !volumeIndex ? (viewportVoi ?? displaySetVOI) : displaySetVOI;
 
      return {
        viewportId: viewportInfo.viewportId,
        modality,
        volumeId,
        volumeIndex,
        voi,
        histogram,
        colormap,
        step: scaling?.PT ? 0.05 : 1,
        opacity,
        showOpacitySlider: volumeIndex === 1 && opacity !== undefined,
      };
    })
  );
 
  return windowLevels.filter(Boolean);
};