All files / packages/tools/src/utilities/boundingBox getBoundingBoxAroundShape.ts

81.08% Statements 30/37
59.45% Branches 22/37
100% Functions 3/3
80.55% Lines 29/36

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      1x                       17x 17x 17x 17x 17x 17x   17x     17x 68x 68x 68x 68x 68x   68x 68x 68x       17x 9x 9x       9x 9x         9x 9x 9x         8x                         17x                                           9x                               8x    
import type { Types } from '@cornerstonejs/core';
import { CONSTANTS } from '@cornerstonejs/core';
 
const { EPSILON } = CONSTANTS;
 
/** Bounding box type */
type BoundingBox =
  | [Types.Point2, Types.Point2, null]
  | [Types.Point2, Types.Point2, Types.Point2];
 
function calculateBoundingBox(
  points,
  dimensions,
  isWorld = false
): BoundingBox {
  let xMin = Infinity;
  let xMax = isWorld ? -Infinity : 0;
  let yMin = Infinity;
  let yMax = isWorld ? -Infinity : 0;
  let zMin = Infinity;
  let zMax = isWorld ? -Infinity : 0;
 
  const is3D = points[0]?.length === 3;
 
  // use for loop for performance
  for (let i = 0; i < points.length; i++) {
    const p = points[i];
    xMin = Math.min(p[0], xMin);
    xMax = Math.max(p[0], xMax);
    yMin = Math.min(p[1], yMin);
    yMax = Math.max(p[1], yMax);
 
    Eif (is3D) {
      zMin = Math.min(p[2] ?? zMin, zMin);
      zMax = Math.max(p[2] ?? zMax, zMax);
    }
  }
 
  if (dimensions) {
    xMin = Math.max(isWorld ? dimensions[0] + EPSILON : 0, xMin);
    xMax = Math.min(
      isWorld ? dimensions[0] - EPSILON : dimensions[0] - 1,
      xMax
    );
    yMin = Math.max(isWorld ? dimensions[1] + EPSILON : 0, yMin);
    yMax = Math.min(
      isWorld ? dimensions[1] - EPSILON : dimensions[1] - 1,
      yMax
    );
 
    Eif (is3D && dimensions.length === 3) {
      zMin = Math.max(isWorld ? dimensions[2] + EPSILON : 0, zMin);
      zMax = Math.min(
        isWorld ? dimensions[2] - EPSILON : dimensions[2] - 1,
        zMax
      );
    }
  } else Iif (!isWorld) {
    // still need to bound to 0 and Infinity if no dimensions are provided for ijk
    xMin = Math.max(0, xMin);
    xMax = Math.min(Infinity, xMax);
    yMin = Math.max(0, yMin);
    yMax = Math.min(Infinity, yMax);
 
    if (is3D) {
      zMin = Math.max(0, zMin);
      zMax = Math.min(Infinity, zMax);
    }
  }
 
  return is3D
    ? [
        [xMin, xMax],
        [yMin, yMax],
        [zMin, zMax],
      ]
    : [[xMin, xMax], [yMin, yMax], null];
}
 
/**
 * With a given vertices (points) coordinates in 2D or 3D in IJK, it calculates the minimum and maximum
 * coordinate in each axis, and returns them. If clipBounds are provided it also
 * clip the min, max to the provided width, height and depth
 *
 * @param points - shape corner points coordinates either in IJK (image coordinate)
 * @param dimensions - bounds to clip the min, max
 * @returns [[xMin,xMax],[yMin,yMax], [zMin,zMax]]
 */
export function getBoundingBoxAroundShapeIJK(
  points: Types.Point2[] | Types.Point3[],
  dimensions?: Types.Point2 | Types.Point3
): BoundingBox {
  return calculateBoundingBox(points, dimensions, false);
}
 
/**
 * With a given vertices (points) coordinates in 2D or 3D in World Coordinates, it calculates the minimum and maximum
 * coordinate in each axis, and returns them. If clipBounds are provided it also
 * clip the min, max to the provided width, height and depth
 *
 * @param points - shape corner points coordinates either in IJK (image coordinate)
 * @param clipBounds - bounds to clip the min, max
 * @returns [[xMin,xMax],[yMin,yMax], [zMin,zMax]]
 */
export function getBoundingBoxAroundShapeWorld(
  points: Types.Point2[] | Types.Point3[],
  clipBounds?: Types.Point2 | Types.Point3
): BoundingBox {
  return calculateBoundingBox(points, clipBounds, true);
}