@cornerstonejs/core
Version:
Cornerstone3D Core
113 lines (112 loc) • 5.24 kB
JavaScript
import { vec3 } from 'gl-matrix';
import * as metaData from '../metaData.js';
import { MetadataModules } from '../enums/index.js';
import { getConfiguration } from '../init.js';
const DEFAULT_THICKNESS_SINGLE_SLICE = 1;
function getPixelSpacingForCubicVoxel(metadata) {
if (metadata.columnPixelSpacing !== undefined) {
return metadata.columnPixelSpacing;
}
if (metadata.rowPixelSpacing !== undefined) {
return metadata.rowPixelSpacing;
}
if (metadata.pixelSpacing?.[1] !== undefined) {
return metadata.pixelSpacing[1];
}
if (metadata.pixelSpacing?.[0] !== undefined) {
return metadata.pixelSpacing[0];
}
return undefined;
}
export default function calculateSpacingBetweenImageIds(imageIds) {
const { imagePositionPatient: referenceImagePositionPatient, imageOrientationPatient, } = metaData.get(MetadataModules.IMAGE_PLANE, imageIds[0]);
if (imageIds.length === 1) {
const { sliceThickness, spacingBetweenSlices, columnPixelSpacing, rowPixelSpacing, pixelSpacing, } = metaData.get(MetadataModules.IMAGE_PLANE, imageIds[0]);
if (sliceThickness)
return sliceThickness;
if (spacingBetweenSlices)
return spacingBetweenSlices;
const pixelSpacingValue = getPixelSpacingForCubicVoxel({
columnPixelSpacing,
rowPixelSpacing,
pixelSpacing,
});
if (pixelSpacingValue !== undefined) {
return pixelSpacingValue;
}
return DEFAULT_THICKNESS_SINGLE_SLICE;
}
const rowCosineVec = vec3.fromValues(imageOrientationPatient[0], imageOrientationPatient[1], imageOrientationPatient[2]);
const colCosineVec = vec3.fromValues(imageOrientationPatient[3], imageOrientationPatient[4], imageOrientationPatient[5]);
const scanAxisNormal = vec3.create();
vec3.cross(scanAxisNormal, rowCosineVec, colCosineVec);
const refIppVec = vec3.fromValues(referenceImagePositionPatient[0], referenceImagePositionPatient[1], referenceImagePositionPatient[2]);
const usingWadoUri = imageIds[0].split(':')[0] === 'wadouri';
let spacing;
function getDistance(imageId) {
const { imagePositionPatient } = metaData.get(MetadataModules.IMAGE_PLANE, imageId);
const positionVector = vec3.create();
const ippVec = vec3.fromValues(imagePositionPatient[0], imagePositionPatient[1], imagePositionPatient[2]);
vec3.sub(positionVector, refIppVec, ippVec);
return vec3.dot(positionVector, scanAxisNormal);
}
if (!usingWadoUri) {
const distanceImagePairs = imageIds.map((imageId) => {
const distance = getDistance(imageId);
return {
distance,
imageId,
};
});
distanceImagePairs.sort((a, b) => b.distance - a.distance);
const numImages = distanceImagePairs.length;
spacing =
Math.abs(distanceImagePairs[numImages - 1].distance -
distanceImagePairs[0].distance) /
(numImages - 1);
}
else {
const prefetchedImageIds = [
imageIds[0],
imageIds[Math.floor(imageIds.length / 2)],
];
const metadataForMiddleImage = metaData.get(MetadataModules.IMAGE_PLANE, prefetchedImageIds[1]);
if (!metadataForMiddleImage) {
throw new Error('Incomplete metadata required for volume construction.');
}
const positionVector = vec3.create();
const middleIppVec = vec3.fromValues(metadataForMiddleImage.imagePositionPatient[0], metadataForMiddleImage.imagePositionPatient[1], metadataForMiddleImage.imagePositionPatient[2]);
vec3.sub(positionVector, refIppVec, middleIppVec);
const distanceBetweenFirstAndMiddleImages = vec3.dot(positionVector, scanAxisNormal);
spacing =
Math.abs(distanceBetweenFirstAndMiddleImages) /
Math.floor(imageIds.length / 2);
}
const { sliceThickness, spacingBetweenSlices, columnPixelSpacing, rowPixelSpacing, pixelSpacing, } = metaData.get(MetadataModules.IMAGE_PLANE, imageIds[0]);
const { strictZSpacingForVolumeViewport } = getConfiguration().rendering;
if ((spacing === 0 || isNaN(spacing)) && !strictZSpacingForVolumeViewport) {
if (spacingBetweenSlices) {
console.debug('Could not calculate spacing. Using spacingBetweenSlices');
spacing = spacingBetweenSlices;
}
else if (sliceThickness) {
console.debug('Could not calculate spacing and no spacingBetweenSlices. Using sliceThickness');
spacing = sliceThickness;
}
else {
const pixelSpacingValue = getPixelSpacingForCubicVoxel({
columnPixelSpacing,
rowPixelSpacing,
pixelSpacing,
});
if (pixelSpacingValue) {
spacing = pixelSpacingValue;
}
else {
console.debug(`Could not calculate spacing and no pixel spacing found. Using default thickness (${DEFAULT_THICKNESS_SINGLE_SLICE} mm)`);
spacing = DEFAULT_THICKNESS_SINGLE_SLICE;
}
}
}
return spacing;
}