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

75.67% Statements 28/37
45.94% Branches 17/37
66.66% Functions 2/3
75% Lines 27/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      428x                       1323x 1323x 1323x 1323x 1323x 1323x   1323x     1323x 5508x 5508x 5508x 5508x 5508x   5508x 5508x 5508x       1323x 1323x 1323x       1323x 1323x         1323x 1323x 1323x                                   1323x                                           1323x                                    
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 Eif (!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);
}