All files / packages/tools/src/utilities/rectangleROITool getBoundsIJKFromRectangleAnnotations.ts

0% Statements 0/20
0% Branches 0/9
0% Functions 0/4
0% Lines 0/20

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                                                                                                                                                               
import { utilities as csUtils } from '@cornerstonejs/core';
import type { Types } from '@cornerstonejs/core';
import { getBoundingBoxAroundShapeIJK } from '../boundingBox/getBoundingBoxAroundShape';
import extend2DBoundingBoxInViewAxis from '../boundingBox/extend2DBoundingBoxInViewAxis';
 
type Options = {
  numSlicesToProject?: number;
};
 
function getBoundsIJKFromRectangleAnnotations(
  annotations,
  referenceVolume,
  options = {} as Options
) {
  const AllBoundsIJK = [];
  annotations.forEach((annotation) => {
    const { data } = annotation;
    const { points } = data.handles;
 
    const { imageData, dimensions } = referenceVolume;
 
    let pointsToUse = points;
    // If the tool is a 2D tool but has projection points, use them
    if (data.cachedStats?.projectionPoints) {
      const { projectionPoints } = data.cachedStats;
      pointsToUse = [].concat(...projectionPoints); // cannot use flat() because of typescript compiler right now
    }
 
    const rectangleCornersIJK = pointsToUse.map(
      (world) => csUtils.transformWorldToIndex(imageData, world) as Types.Point3
    );
    let boundsIJK = getBoundingBoxAroundShapeIJK(
      rectangleCornersIJK,
      dimensions
    );
 
    // If the tool is 2D but it is configured to project to X amount of slices
    // Don't project the slices if projectionPoints have been used to define the extents
    if (options.numSlicesToProject && !data.cachedStats?.projectionPoints) {
      boundsIJK = extend2DBoundingBoxInViewAxis(
        boundsIJK,
        options.numSlicesToProject
      );
    }
 
    AllBoundsIJK.push(boundsIJK);
  });
 
  if (AllBoundsIJK.length === 1) {
    return AllBoundsIJK[0];
  }
 
  // Get the intersection of all the bounding boxes
  // This is the bounding box that contains all the ROIs
  const boundsIJK = AllBoundsIJK.reduce(
    (accumulator, currentValue) => {
      return {
        iMin: Math.min(accumulator.iMin, currentValue.iMin),
        jMin: Math.min(accumulator.jMin, currentValue.jMin),
        kMin: Math.min(accumulator.kMin, currentValue.kMin),
        iMax: Math.max(accumulator.iMax, currentValue.iMax),
        jMax: Math.max(accumulator.jMax, currentValue.jMax),
        kMax: Math.max(accumulator.kMax, currentValue.kMax),
      };
    },
    {
      iMin: Infinity,
      jMin: Infinity,
      kMin: Infinity,
      iMax: -Infinity,
      jMax: -Infinity,
      kMax: -Infinity,
    }
  );
 
  return boundsIJK;
}
 
export default getBoundsIJKFromRectangleAnnotations;