All files / core/src/RenderingEngine/helpers createVolumeSliceActor.ts

0% Statements 0/42
0% Branches 0/23
0% Functions 0/2
0% Lines 0/42

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                                                                                                                                                                                                                                       
import vtkPlane from '@kitware/vtk.js/Common/DataModel/Plane';
import vtkImageSlice from '@kitware/vtk.js/Rendering/Core/ImageSlice';
import { vtkSharedImageResliceMapper } from '../vtkClasses';
import type { ImageActor } from '../../types/IActor';
import type { VoiModifiedEventDetail } from '../../types/EventTypes';
import { loadVolume } from '../../loaders/volumeLoader';
import triggerEvent from '../../utilities/triggerEvent';
import { Events } from '../../enums';
import setDefaultVolumeVOI from './setDefaultVolumeVOI';
 
interface CreateVolumeSliceActorOptions {
  volumeId: string;
  callback?: ({
    volumeActor,
    volumeId,
  }: {
    volumeActor: ImageActor;
    volumeId: string;
  }) => void;
}
 
async function createVolumeSliceActor(
  props: CreateVolumeSliceActorOptions,
  element: HTMLDivElement,
  viewportId: string,
  suppressEvents = false
): Promise<{ actor: ImageActor; slicePlane: vtkPlane }> {
  const { volumeId, callback } = props;
  const imageVolume = await loadVolume(volumeId);
 
  if (!imageVolume) {
    throw new Error(`imageVolume with id: ${volumeId} does not exist`);
  }
 
  const { imageData, vtkOpenGLTexture } = imageVolume;
  const loadStatus = imageVolume.loadStatus as { loaded?: boolean } | undefined;
  const slicePlane = vtkPlane.newInstance();
  const mapper = vtkSharedImageResliceMapper.newInstance();
 
  if (!loadStatus || loadStatus.loaded) {
    vtkOpenGLTexture.modified();
  }
 
  mapper.setInputData(imageData);
  mapper.setSlicePlane(slicePlane);
  mapper.setSlabThickness(0);
  mapper.setScalarTexture?.(vtkOpenGLTexture);
  mapper.modified();
 
  const actor = vtkImageSlice.newInstance();
  actor.setMapper(mapper);
 
  const imageDataMetadata = imageData.get('numberOfComponents') as
    | { numberOfComponents?: number }
    | undefined;
  const numberOfComponents = imageDataMetadata?.numberOfComponents ?? 1;
 
  if (numberOfComponents > 1) {
    actor.getProperty().setIndependentComponents(false);
  }
 
  const imageProperty = actor.getProperty();
  imageProperty.set({ viewportId }, true);
 
  await setDefaultVolumeVOI(actor, imageVolume);
 
  const defaultWindow = imageProperty.getColorWindow?.();
  const defaultLevel = imageProperty.getColorLevel?.();
 
  if (defaultWindow === 255 && defaultLevel === 127.5) {
    const scalarRange = imageVolume.voxelManager?.getRange?.();
 
    if (scalarRange?.length === 2) {
      imageProperty.setColorWindow(scalarRange[1] - scalarRange[0]);
      imageProperty.setColorLevel((scalarRange[1] + scalarRange[0]) / 2);
    }
  }
 
  if (callback) {
    callback({ volumeActor: actor, volumeId });
  }
 
  if (!suppressEvents) {
    triggerVOIModified(element, viewportId, actor, volumeId);
  }
 
  return { actor, slicePlane };
}
 
function triggerVOIModified(
  element: HTMLDivElement,
  viewportId: string,
  actor: ImageActor,
  volumeId: string
) {
  const transferFunction = actor.getProperty().getRGBTransferFunction(0);
 
  if (!transferFunction) {
    return;
  }
 
  const voiRange = transferFunction.getRange();
  const voiModifiedEventDetail: VoiModifiedEventDetail = {
    viewportId,
    range: {
      lower: voiRange[0],
      upper: voiRange[1],
    },
    volumeId,
  };
 
  triggerEvent(element, Events.VOI_MODIFIED, voiModifiedEventDetail);
}
 
export default createVolumeSliceActor;