@cornerstonejs/core
Version:
Cornerstone3D Core
111 lines (110 loc) • 4.58 kB
JavaScript
import vtkMath from '@kitware/vtk.js/Common/Core/Math.js';
import { MPR_CAMERA_VALUES } from '../../../constants/index.js';
import { OrientationAxis } from '../../../enums/index.js';
import { getConfiguration } from '../../../init.js';
import { getCubeSizeInView } from '../../../utilities/getPlaneCubeIntersectionDimensions.js';
import { getVolumeCenterIJK } from '../../Viewport.js';
const VOLUME_3D_RADIUS_MULTIPLIER = 10;
export function getInitialVolume3DCamera(ctx, imageVolume) {
const imageData = imageVolume.imageData;
if (!imageData) {
return;
}
const vtkCamera = ctx.vtk.renderer.getActiveCamera();
const orientation = getOrientationVectors({
fallbackViewPlaneNormal: vtkCamera.getViewPlaneNormal(),
fallbackViewUp: vtkCamera.getViewUp(),
imageVolume,
orientation: ctx.viewport.options.orientation,
});
const { viewPlaneNormal, viewUp } = orientation;
const bounds = imageData.getBounds();
const focalPoint = [0, 0, 0];
const dimensions = imageData.getDimensions();
const middleIJK = getVolumeCenterIJK(dimensions, imageData.getDirection(), viewPlaneNormal);
imageData.indexToWorld(middleIJK, focalPoint);
const { widthWorld, heightWorld } = getCubeSizeInView(imageData, viewPlaneNormal, viewUp);
const canvasWidth = ctx.vtk.canvas.width || ctx.viewport.element.clientWidth || 1;
const canvasHeight = ctx.vtk.canvas.height || ctx.viewport.element.clientHeight || 1;
const boundsAspectRatio = widthWorld / heightWorld;
const canvasAspectRatio = canvasWidth / canvasHeight;
const scaleFactor = boundsAspectRatio / canvasAspectRatio;
const insetImageMultiplier = getConfiguration().rendering?.useLegacyCameraFOV
? 1.1
: 1;
const parallelScale = scaleFactor < 1
? (insetImageMultiplier * heightWorld) / 2
: (insetImageMultiplier * heightWorld * scaleFactor) / 2;
const radius = getBoundsRadius(bounds) * VOLUME_3D_RADIUS_MULTIPLIER;
const distance = insetImageMultiplier * radius;
const viewUpToUse = Math.abs(vtkMath.dot(viewUp, viewPlaneNormal)) > 0.999
? [-viewUp[2], viewUp[0], viewUp[1]]
: viewUp;
const position = [
focalPoint[0] + distance * viewPlaneNormal[0],
focalPoint[1] + distance * viewPlaneNormal[1],
focalPoint[2] + distance * viewPlaneNormal[2],
];
if ('setPhysicalScale' in vtkCamera) {
vtkCamera.setPhysicalScale(radius);
vtkCamera.setPhysicalTranslation(-focalPoint[0], -focalPoint[1], -focalPoint[2]);
}
return {
focalPoint,
parallelProjection: ctx.viewport.options.parallelProjection ?? true,
parallelScale,
position,
viewAngle: 90,
viewPlaneNormal,
viewUp: viewUpToUse,
};
}
function getOrientationVectors(args) {
const { fallbackViewPlaneNormal, fallbackViewUp, imageVolume, orientation } = args;
if (!orientation) {
return {
viewPlaneNormal: fallbackViewPlaneNormal,
viewUp: fallbackViewUp,
};
}
if (typeof orientation === 'object' && orientation.viewPlaneNormal) {
return {
viewPlaneNormal: [...orientation.viewPlaneNormal],
viewUp: orientation.viewUp
? [...orientation.viewUp]
: fallbackViewUp,
};
}
if (orientation === OrientationAxis.ACQUISITION) {
const { direction } = imageVolume;
return {
viewPlaneNormal: direction.slice(6, 9).map((x) => -x),
viewUp: direction.slice(3, 6).map((x) => -x),
};
}
const cameraValues = orientation === OrientationAxis.AXIAL_REFORMAT
? MPR_CAMERA_VALUES.axial
: orientation === OrientationAxis.SAGITTAL_REFORMAT
? MPR_CAMERA_VALUES.sagittal
: orientation === OrientationAxis.CORONAL_REFORMAT
? MPR_CAMERA_VALUES.coronal
: typeof orientation === 'string'
? MPR_CAMERA_VALUES[orientation]
: undefined;
if (!cameraValues) {
return {
viewPlaneNormal: fallbackViewPlaneNormal,
viewUp: fallbackViewUp,
};
}
return {
viewPlaneNormal: [...cameraValues.viewPlaneNormal],
viewUp: [...cameraValues.viewUp],
};
}
function getBoundsRadius(bounds) {
const width = (bounds[1] - bounds[0]) ** 2;
const height = (bounds[3] - bounds[2]) ** 2;
const depth = (bounds[5] - bounds[4]) ** 2;
return Math.sqrt(width + height + depth || 1) * 0.5;
}