All files / core/src/RenderingEngine/GenericViewport/Planar planarCPUVolumeSamplingUtils.ts

6.25% Statements 2/32
0% Branches 0/13
0% Functions 0/8
6.66% Lines 2/30

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          128x 128x                                                                                                                                                                            
import { vec3 } from 'gl-matrix';
import type { IImageVolume, Point3 } from '../../../types';
 
export type IndexMajorAxis = { axis: 0 | 1 | 2; sign: 1 | -1 };
 
export const SOURCE_SLICE_INDEX_TOLERANCE = 1e-4;
export const NEAREST_VOXEL_TIE_EPSILON = 1e-6;
 
function dot(a: Point3, b: Point3): number {
  return vec3.dot(a as unknown as vec3, b as unknown as vec3);
}
 
export function getIndexMajorAxis(
  volume: IImageVolume,
  worldVector: Point3,
  majorThreshold = 0.995
): IndexMajorAxis | undefined {
  const row = volume.direction.slice(0, 3) as Point3;
  const col = volume.direction.slice(3, 6) as Point3;
  const scan = volume.direction.slice(6, 9) as Point3;
  const components = [
    dot(worldVector, row),
    dot(worldVector, col),
    dot(worldVector, scan),
  ] as [number, number, number];
  const absComponents = components.map((value) => Math.abs(value)) as [
    number,
    number,
    number,
  ];
  const maxValue = Math.max(...absComponents);
  const axis = absComponents.indexOf(maxValue) as 0 | 1 | 2;
 
  if (maxValue < majorThreshold) {
    return;
  }
 
  const secondary = absComponents
    .filter((_value, index) => index !== axis)
    .some((value) => value > 1 - majorThreshold);
 
  if (secondary) {
    return;
  }
 
  return {
    axis,
    sign: components[axis] >= 0 ? 1 : -1,
  };
}
 
export function getSpatiallyClampedContinuousCoordinate(
  dimension: number,
  value: number
): number | undefined {
  const upperBound = dimension - 0.5;
 
  if (
    value < -0.5 - SOURCE_SLICE_INDEX_TOLERANCE ||
    value > upperBound + SOURCE_SLICE_INDEX_TOLERANCE
  ) {
    return;
  }
 
  return Math.min(dimension - 1, Math.max(0, value));
}
 
export function getNearestVoxelIndex(continuousIndex: number): number {
  return Math.floor(continuousIndex + 0.5 - NEAREST_VOXEL_TIE_EPSILON);
}
 
export function getSpatiallyClampedContinuousIndex(
  dimensions: Point3,
  continuousIndex: Point3
): Point3 | undefined {
  const clampedIndex = [0, 0, 0] as Point3;
 
  for (let axis = 0; axis < 3; axis++) {
    const clampedCoordinate = getSpatiallyClampedContinuousCoordinate(
      dimensions[axis],
      continuousIndex[axis]
    );
 
    if (clampedCoordinate === undefined) {
      return;
    }
 
    clampedIndex[axis] = clampedCoordinate;
  }
 
  return clampedIndex;
}