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 | 1x 1440x 720x 240x 240x 240x 240x 240x 240x 1920x 240x 240x 240x 240x 240x 240x 1920x 1920x 480x 1920x 445x 240x | import vtkMatrixBuilder from '@kitware/vtk.js/Common/Core/MatrixBuilder'; import getVolumeActorCorners from './getVolumeActorCorners'; import type { VolumeActor, Point3, ActorSliceRange } from '../types'; import { EPSILON } from '../constants'; const SMALL_EPSILON = EPSILON * EPSILON; const isOne = (v) => Math.abs(Math.abs(v) - 1) < SMALL_EPSILON; const isUnit = (v, off) => isOne(v[off]) || isOne(v[off + 1]) || isOne(v[off + 2]); const isOrthonormal = (v) => isUnit(v, 0) && isUnit(v, 3) && isUnit(v, 6); /** * Given a `vtkVolumeActor`, and a normal direction, * calculate the range of slices in the focal normal direction that encapsulate * the volume. Also project the `focalPoint` onto this range. * * @param volumeActor - The `vtkVolumeActor`. * @param viewPlaneNormal - The normal to the camera view. * @param focalPoint - The focal point of the camera. * * @returns an object containing the `min`, `max` and `current` * positions in the normal direction. */ export default function getSliceRange( volumeActor: VolumeActor, viewPlaneNormal: Point3, focalPoint: Point3 ): ActorSliceRange { const imageData = volumeActor.getMapper().getInputData(); let corners; const direction = imageData.getDirection(); Eif (isOrthonormal(direction)) { // This logic is only valid when the IJK vectors are unit vectors corners = getVolumeActorCorners(volumeActor); } else { // This logic works for both unit and non-unit vectors, but is slower const [dx, dy, dz] = imageData.getDimensions(); const cornersIdx = [ [0, 0, 0], [dx - 1, 0, 0], [0, dy - 1, 0], [dx - 1, dy - 1, 0], [0, 0, dz - 1], [dx - 1, 0, dz - 1], [0, dy - 1, dz - 1], [dx - 1, dy - 1, dz - 1], ]; corners = cornersIdx.map((it) => imageData.indexToWorld(it)); } // Get rotation matrix from normal to +X (since bounds is aligned to XYZ) const transform = vtkMatrixBuilder .buildFromDegree() .identity() .rotateFromDirections(viewPlaneNormal, [1, 0, 0]); corners.forEach((pt) => transform.apply(pt)); const transformedFocalPoint = [...focalPoint]; transform.apply(transformedFocalPoint); const currentSlice = transformedFocalPoint[0]; // range is now maximum X distance let minX = Infinity; let maxX = -Infinity; for (let i = 0; i < 8; i++) { const x = corners[i][0]; if (x > maxX) { maxX = x; } if (x < minX) { minX = x; } } return { min: minX, max: maxX, current: currentSlice, actor: volumeActor, viewPlaneNormal, focalPoint, }; } |