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

93.75% Statements 30/32
79.16% Branches 19/24
100% Functions 5/5
100% Lines 25/25

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                                                              77x     693x 77x 77x   77x   77x   154x           77x   77x   77x 22x     77x 77x         77x 154x       77x 19x     77x 55x 77x   77x 1x               55x         55x                 55x        
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,
  use16BitTexture = false
): Promise<VolumeActor> {
  const { volumeId, callback, blendMode } = props;
 
  const imageVolumeE = await loadVolume(volumeId);
 
  if (!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);
 
  // If the volume is composed of imageIds, we can apply a default VOI based
  // on either the metadata or the min/max of the middle slice. Example of other
  // types of volumes which might not be composed of imageIds would be e.g., nrrd, nifti
  E// format volumes
  if (imageVolume.imageIds) {
    await setDefaultVolumeVOI(volumeActor, imageVolume, use16BitTexture);
  }
 
  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;