All files / packages/core/src/utilities worldToImageCoords.ts

0% Statements 0/16
0% Branches 0/2
0% Functions 0/1
0% Lines 0/16

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                                                                                                                                   
import { vec3 } from 'gl-matrix';
import { metaData } from '..';
import { Point2, Point3 } from '../types';
 
/**
 * Given the imageId, and 3d coordinates on the world space, it returns the continuos
 * image coordinates (IJ) on the image space. The image space is
 * defined with [0,0] being on the top left corner of the top left pixel,
 * the [1,1] being on the bottom right corner of the top left pixel.
 * @param imageId - The image id
 * @param worldCoords - The 3d coordinates on the world.
 * @returns The 2d coordinates on the image.
 *
 */
function worldToImageCoords(
  imageId: string,
  worldCoords: Point3
): Point2 | undefined {
  const imagePlaneModule = metaData.get('imagePlaneModule', imageId);
 
  if (!imagePlaneModule) {
    throw new Error(`No imagePlaneModule found for imageId: ${imageId}`);
  }
 
  // For the image coordinates we need to calculate the transformation matrix
  // from the world coordinates to the image coordinates.
 
  const {
    columnCosines,
    rowCosines,
    imagePositionPatient: origin,
  } = imagePlaneModule;
 
  let { columnPixelSpacing, rowPixelSpacing } = imagePlaneModule;
  // Use ||= to convert null and 0 as well as undefined to 1
  columnPixelSpacing ||= 1;
  rowPixelSpacing ||= 1;
 
  // The origin is the image position patient, but since image coordinates start
  // from [0,0] for the top left hand of the first pixel, and the origin is at the
  // center of the first pixel, we need to account for this.
  const newOrigin = vec3.create();
 
  vec3.scaleAndAdd(newOrigin, origin, columnCosines, -columnPixelSpacing / 2);
  vec3.scaleAndAdd(newOrigin, newOrigin, rowCosines, -rowPixelSpacing / 2);
 
  // Get the subtraction vector from the origin to the world coordinates
  const sub = vec3.create();
  vec3.sub(sub, worldCoords, newOrigin);
 
  // Projected distance of the sub vector onto the rowCosines
  const rowDistance = vec3.dot(sub, rowCosines);
 
  // Projected distance of the sub vector onto the columnCosines
  const columnDistance = vec3.dot(sub, columnCosines);
 
  const imageCoords = [
    rowDistance / rowPixelSpacing,
    columnDistance / columnPixelSpacing,
  ];
 
  return imageCoords as Point2;
}
 
export default worldToImageCoords;