All files / packages/core/src/cache/classes ImageVolume.ts

96.61% Statements 57/59
66.66% Branches 4/6
100% Functions 11/11
96.55% Lines 56/58

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 155 156 157 158 159 160 161 162                                1x   78x   78x     78x   78x   78x   78x   78x   78x   78x                     78x   78x   78x   78x   78x   78x   78x   156x     156x 78x 78x 78x 78x 78x 78x 78x 78x 78x 78x 78x     78x       78x 7x       1x   238x         23x 23x     23x 23x 23x   23x 99x   99x 99x               104x               65x 65x                       26x                 30x               1x 1x 1x 1x 1x 1x 1x        
import isTypedArray from '../../utilities/isTypedArray';
import { imageIdToURI } from '../../utilities';
import { vtkStreamingOpenGLTexture } from '../../RenderingEngine/vtkClasses';
import type { vtkImageData } from '@kitware/vtk.js/Common/DataModel/ImageData';
import {
  IVolume,
  VolumeScalarData,
  Metadata,
  Point3,
  IImageVolume,
  Mat3,
} from '../../types';
 
/** The base class for volume data. It includes the volume metadata
 * and the volume data along with the loading status.
 */
export class ImageVolume implements IImageVolume {
  private _imageIds: Array<string>;
  private _imageIdsIndexMap = new Map();
  private _imageURIsIndexMap = new Map();
  /** volume scalar data 3D or 4D */
  protected scalarData: VolumeScalarData | Array<VolumeScalarData>;
 
  /** Read-only unique identifier for the volume */
  readonly volumeId: string;
  /** Dimensions of the volume */
  dimensions: Point3;
  /** volume direction in world space */
  direction: Mat3;
  /** volume metadata */
  metadata: Metadata;
  /** volume origin, Note this is an opinionated origin for the volume */
  origin: Point3;
  /** Whether preScaling has been performed on the volume */
  isPrescaled = false;
  /** volume scaling parameters if it contains scaled data */
  scaling?: {
    PET?: {
      // @TODO: Do these values exist?
      SUVlbmFactor?: number;
      SUVbsaFactor?: number;
      // accessed in ProbeTool
      suvbwToSuvlbm?: number;
      suvbwToSuvbsa?: number;
    };
  };
  /** volume size in bytes */
  sizeInBytes?: number; // Seems weird to pass this in? Why not grab it from scalarData.byteLength
  /** volume spacing in 3d world space */
  spacing: Point3;
  /** volume number of voxels */
  numVoxels: number;
  /** volume image data */
  imageData?: vtkImageData;
  /** open gl texture for the volume */
  vtkOpenGLTexture: any; // No good way of referencing vtk classes as they aren't classes.
  /** load status object for the volume */
  loadStatus?: Record<string, any>;
  /** optional reference volume id if the volume is derived from another volume */
  referencedVolumeId?: string;
  /** whether the metadata for the pixel spacing is not undefined  */
  hasPixelSpacing: boolean;
 
  constructor(props: IVolume) {
    this.volumeId = props.volumeId;
    this.metadata = props.metadata;
    this.dimensions = props.dimensions;
    this.spacing = props.spacing;
    this.origin = props.origin;
    this.direction = props.direction;
    this.imageData = props.imageData;
    this.scalarData = props.scalarData;
    this.sizeInBytes = props.sizeInBytes;
    this.vtkOpenGLTexture = vtkStreamingOpenGLTexture.newInstance();
    this.numVoxels =
      this.dimensions[0] * this.dimensions[1] * this.dimensions[2];
 
    Iif (props.scaling) {
      this.scaling = props.scaling;
    }
 
    if (props.referencedVolumeId) {
      this.referencedVolumeId = props.referencedVolumeId;
    }
  }
 
  /** return the image ids for the volume if it is made of separated images */
  public get imageIds(): Array<string> {
    return this._imageIds;
  }
 
  /** updates the image ids */
  public set imageIds(newImageIds: Array<string>) {
    this._imageIds = newImageIds;
    this._reprocessImageIds();
  }
 
  private _reprocessImageIds() {
    this._imageIdsIndexMap.clear();
    this._imageURIsIndexMap.clear();
 
    this._imageIds.forEach((imageId, i) => {
      const imageURI = imageIdToURI(imageId);
 
      this._imageIdsIndexMap.set(imageId, i);
      this._imageURIsIndexMap.set(imageURI, i);
    });
  }
 
  cancelLoading: () => void;
 
  /** return true if it is a 4D volume or false if it is 3D volume */
  public isDynamicVolume(): boolean {
    return false;
  }
 
  /**
   * Return the scalar data for 3D volumes or the active scalar data
   * (current time point) for 4D volumes
   */
  public getScalarData(): VolumeScalarData {
    Eif (isTypedArray(this.scalarData)) {
      return <VolumeScalarData>this.scalarData;
    }
 
    throw new Error('Unknow scalar data type');
  }
 
  /**
   * return the index of a given imageId
   * @param imageId - imageId
   * @returns imageId index
   */
  public getImageIdIndex(imageId: string): number {
    return this._imageIdsIndexMap.get(imageId);
  }
 
  /**
   * return the index of a given imageURI
   * @param imageId - imageURI
   * @returns imageURI index
   */
  public getImageURIIndex(imageURI: string): number {
    return this._imageURIsIndexMap.get(imageURI);
  }
 
  /**
   * destroy the volume and make it unusable
   */
  destroy(): void {
    // TODO: GPU memory associated with volume is not cleared.
    this.vtkOpenGLTexture.releaseGraphicsResources();
    this.vtkOpenGLTexture.destroyTexture();
    this.vtkOpenGLTexture.delete();
    this.imageData.delete();
    this.imageData = null;
    this.scalarData = null;
  }
}
 
export default ImageVolume;