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

100% Statements 17/17
87.5% Branches 14/16
100% Functions 2/2
100% Lines 17/17

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                                                              1500x       75x   75x   75x               75x   75x   75x 22x     75x 75x                   75x 19x     75x 53x                       53x           53x                 53x        
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
): Promise<VolumeActor> {
  const { volumeId, callback, blendMode } = props;
 
  const imageVolume = 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
  // format volumes
  if (imageVolume.imageIds) {
    await setDefaultVolumeVOI(volumeActor, imageVolume);
  }
 
  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)
    // @ts-ignore: vtk d ts problem
    .getRange();
 
  const voiModifiedEventDetail: VoiModifiedEventDetail = {
    viewportId,
    range: {
      lower: voiRange[0],
      upper: voiRange[1],
    },
    volumeId,
  };
 
  triggerEvent(element, Events.VOI_MODIFIED, voiModifiedEventDetail);
}
 
export default createVolumeActor;