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 112 113 114 115 116 117 | import { vec3 } from 'gl-matrix';
import { planar } from '.';
import { metaData } from '..';
import { IStackViewport, Point3 } from '../types';
/**
* Given a point in 3D space and a viewport it returns the index of the closest imageId, it assumes that stack images are sorted according to their sliceLocation
* @param point - [A, B, C] coordinates of the point in 3D space
* @param viewport - The StackViewport to search for the closest imageId
*
* @returns The imageId index of the closest imageId or null if no imageId is found
*/
export default function getClosestStackImageIndexForPoint(
point: Point3,
viewport: IStackViewport
): number | null {
const minimalDistance = calculateMinimalDistanceForStackViewport(
point,
viewport
);
return minimalDistance ? minimalDistance.index : null;
}
//assumes that imageIds are sorted by slice location
export function calculateMinimalDistanceForStackViewport(
point: Point3,
viewport: IStackViewport
): { distance: number; index: number } | null {
const imageIds = viewport.getImageIds();
const currentImageIdIndex = viewport.getCurrentImageIdIndex();
if (imageIds.length === 0) return null;
const getDistance = (imageId: string): null | number => {
const planeMetadata = getPlaneMetadata(imageId);
if (!planeMetadata) return null;
const plane = planar.planeEquation(
planeMetadata.planeNormal,
planeMetadata.imagePositionPatient
);
const distance = planar.planeDistanceToPoint(plane, point);
return distance;
};
const closestStack = {
distance: getDistance(imageIds[currentImageIdIndex]) ?? Infinity,
index: currentImageIdIndex,
};
//check higher indices
const higherImageIds = imageIds.slice(currentImageIdIndex + 1);
for (let i = 0; i < higherImageIds.length; i++) {
const id = higherImageIds[i];
const distance = getDistance(id);
if (distance === null) continue;
if (distance <= closestStack.distance) {
closestStack.distance = distance;
closestStack.index = i + currentImageIdIndex + 1;
} else break;
}
//check lower indices
const lowerImageIds = imageIds.slice(0, currentImageIdIndex);
for (let i = lowerImageIds.length - 1; i >= 0; i--) {
const id = lowerImageIds[i];
const distance = getDistance(id);
if (distance === null || distance === closestStack.distance) continue;
if (distance < closestStack.distance) {
closestStack.distance = distance;
closestStack.index = i;
} else break;
}
return closestStack.distance === Infinity ? null : closestStack;
}
function getPlaneMetadata(imageId: string): null | {
rowCosines: Point3;
columnCosines: Point3;
imagePositionPatient: Point3;
planeNormal: Point3;
} {
const targetImagePlane = metaData.get('imagePlaneModule', imageId);
if (
!targetImagePlane ||
!(
targetImagePlane.rowCosines instanceof Array &&
targetImagePlane.rowCosines.length === 3
) ||
!(
targetImagePlane.columnCosines instanceof Array &&
targetImagePlane.columnCosines.length === 3
) ||
!(
targetImagePlane.imagePositionPatient instanceof Array &&
targetImagePlane.imagePositionPatient.length === 3
)
) {
return null;
}
const {
rowCosines,
columnCosines,
imagePositionPatient,
}: {
rowCosines: Point3;
columnCosines: Point3;
imagePositionPatient: Point3;
} = targetImagePlane;
const rowVec = vec3.set(vec3.create(), ...rowCosines);
const colVec = vec3.set(vec3.create(), ...columnCosines);
const planeNormal = vec3.cross(vec3.create(), rowVec, colVec) as Point3;
return { rowCosines, columnCosines, imagePositionPatient, planeNormal };
}
|