All files / packages/core/src/RenderingEngine/helpers createVolumeActor.ts

95.45% Statements 21/22
75% Branches 9/12
100% Functions 2/2
95.45% Lines 21/22

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                                                                            91x   91x   91x           91x   91x   91x 22x     91x 91x   91x         91x 2x     91x   91x 19x     91x 69x     91x                 69x         69x                 69x        
import vtkVolume from '@kitware/vtk.js/Rendering/Core/Volume';
 
import { VolumeActor } from './../../types/IActor';
import { VoiModifiedEventDetail } from './../../types/EventTypes';
import { loadVolume } from '../../loaders/volumeLoader';
import createVolumeMapper from './createVolumeMapper';
import BlendModes from '../../enums/BlendModes';
import { triggerEvent } from '../../utilities';
import { Events } from '../../enums';
import setDefaultVolumeVOI from './setDefaultVolumeVOI';
 
interface createVolumeActorInterface {
  volumeId: string;
  callback?: ({
    volumeActor,
    volumeId,
  }: {
    volumeActor: VolumeActor;
    volumeId: string;
  }) => void;
  blendMode?: BlendModes;
}
 
/**
 * Given a volumeId, it creates a vtk volume actor and returns it. If
 * callback is provided, it will be called with the volume actor and the
 * volumeId. If blendMode is provided, it will be set on the volume actor.
 *
 * @param props - createVolumeActorInterface
 * @returns A promise that resolves to a VolumeActor.
 */
async function createVolumeActor(
  props: createVolumeActorInterface,
  element: HTMLDivElement,
  viewportId: string,
  suppressEvents = false,
  useNativeDataType = false
): Promise<VolumeActor> {
  const { volumeId, callback, blendMode } = props;
 
  const imageVolume = await loadVolume(volumeId);
 
  Iif (!imageVolume) {
    throw new Error(
      `imageVolume with id: ${imageVolume.volumeId} does not exist`
    );
  }
 
  const { imageData, vtkOpenGLTexture } = imageVolume;
 
  const volumeMapper = createVolumeMapper(imageData, vtkOpenGLTexture);
 
  if (blendMode) {
    volumeMapper.setBlendMode(blendMode);
  }
 
  const volumeActor = vtkVolume.newInstance();
  volumeActor.setMapper(volumeMapper);
 
  const numberOfComponents = imageData
    .getPointData()
    .getScalars()
    .getNumberOfComponents();
 
  if (numberOfComponents === 3) {
    volumeActor.getProperty().setIndependentComponents(false);
  }
 
  await setDefaultVolumeVOI(volumeActor, imageVolume, useNativeDataType);
 
  if (callback) {
    callback({ volumeActor, volumeId });
  }
 
  if (!suppressEvents) {
    triggerVOIModified(element, viewportId, volumeActor, volumeId);
  }
 
  return volumeActor;
}
 
function triggerVOIModified(
  element: HTMLDivElement,
  viewportId: string,
  volumeActor: VolumeActor,
  volumeId: string
) {
  const voiRange = volumeActor
    .getProperty()
    .getRGBTransferFunction(0)
    .getRange();
 
  const voiModifiedEventDetail: VoiModifiedEventDetail = {
    viewportId,
    range: {
      lower: voiRange[0],
      upper: voiRange[1],
    },
    volumeId,
  };
 
  triggerEvent(element, Events.VOI_MODIFIED, voiModifiedEventDetail);
}
 
export default createVolumeActor;