Skip to content

Commit 2d38c85

Browse files
committed
fix(interactorstylemprslice): fix getSliceRange when input image has orientation matrix
getBounds() rotates the extent, however it produces new corner points. Those new corner points were used to compute the slice range along the slice normal . Instead we keep the original extent corner points to apply the image direction along the slice normal.
1 parent be41863 commit 2d38c85

File tree

2 files changed

+28
-48
lines changed
  • Sources
    • Common/DataModel/BoundingBox
    • Interaction/Style/InteractorStyleMPRSlice

2 files changed

+28
-48
lines changed

Sources/Common/DataModel/BoundingBox/index.js

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -285,14 +285,14 @@ function oppositeSign(a, b) {
285285
}
286286

287287
export function getCorners(bounds, corners) {
288-
let count = 0;
289-
for (let ix = 0; ix < 2; ix++) {
290-
for (let iy = 2; iy < 4; iy++) {
291-
for (let iz = 4; iz < 6; iz++) {
292-
corners[count++] = [bounds[ix], bounds[iy], bounds[iz]];
293-
}
294-
}
295-
}
288+
corners[0] = [bounds[0], bounds[2], bounds[4]];
289+
corners[1] = [bounds[0], bounds[2], bounds[5]];
290+
corners[2] = [bounds[0], bounds[3], bounds[4]];
291+
corners[3] = [bounds[0], bounds[3], bounds[5]];
292+
corners[4] = [bounds[1], bounds[2], bounds[4]];
293+
corners[5] = [bounds[1], bounds[2], bounds[5]];
294+
corners[6] = [bounds[1], bounds[3], bounds[4]];
295+
corners[7] = [bounds[1], bounds[3], bounds[5]];
296296
return corners;
297297
}
298298

Sources/Interaction/Style/InteractorStyleMPRSlice/index.js

Lines changed: 20 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,29 +1,18 @@
11
import macro from 'vtk.js/Sources/macros';
22
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
33
import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder';
4+
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';
45
import vtkInteractorStyleManipulator from 'vtk.js/Sources/Interaction/Style/InteractorStyleManipulator';
56
import vtkMouseCameraTrackballRotateManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballRotateManipulator';
67
import vtkMouseCameraTrackballPanManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballPanManipulator';
78
import vtkMouseCameraTrackballZoomManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballZoomManipulator';
89
import vtkMouseRangeManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseRangeManipulator';
910

11+
import { mat4 } from 'gl-matrix';
1012
// ----------------------------------------------------------------------------
1113
// Global methods
1214
// ----------------------------------------------------------------------------
1315

14-
function boundsToCorners(bounds) {
15-
return [
16-
[bounds[0], bounds[2], bounds[4]],
17-
[bounds[0], bounds[2], bounds[5]],
18-
[bounds[0], bounds[3], bounds[4]],
19-
[bounds[0], bounds[3], bounds[5]],
20-
[bounds[1], bounds[2], bounds[4]],
21-
[bounds[1], bounds[2], bounds[5]],
22-
[bounds[1], bounds[3], bounds[4]],
23-
[bounds[1], bounds[3], bounds[5]],
24-
];
25-
}
26-
2716
// ----------------------------------------------------------------------------
2817

2918
function clamp(value, min, max) {
@@ -153,14 +142,9 @@ function vtkInteractorStyleMPRSlice(publicAPI, model) {
153142

154143
if (model.volumeMapper) {
155144
const range = publicAPI.getSliceRange();
156-
const bounds = model.volumeMapper.getBounds();
157145

158146
const clampedSlice = clamp(slice, ...range);
159-
const center = [
160-
(bounds[0] + bounds[1]) / 2.0,
161-
(bounds[2] + bounds[3]) / 2.0,
162-
(bounds[4] + bounds[5]) / 2.0,
163-
];
147+
const center = model.volumeMapper.getCenter();
164148

165149
const distance = camera.getDistance();
166150
const dop = camera.getDirectionOfProjection();
@@ -193,37 +177,33 @@ function vtkInteractorStyleMPRSlice(publicAPI, model) {
193177
if (model.volumeMapper) {
194178
const sliceNormal = publicAPI.getSliceNormal();
195179

196-
if (
197-
sliceNormal[0] === cache.sliceNormal[0] &&
198-
sliceNormal[1] === cache.sliceNormal[1] &&
199-
sliceNormal[2] === cache.sliceNormal[2]
200-
) {
180+
if (vtkMath.areEquals(sliceNormal, cache.sliceNormal)) {
201181
return cache.sliceRange;
202182
}
203183

204-
const bounds = model.volumeMapper.getBounds();
205-
const points = boundsToCorners(bounds);
206-
207184
// Get rotation matrix from normal to +X (since bounds is aligned to XYZ)
208-
const transform = vtkMatrixBuilder
185+
const sliceOrientation = vtkMatrixBuilder
209186
.buildFromDegree()
210187
.identity()
211188
.rotateFromDirections(sliceNormal, [1, 0, 0]);
189+
const imageAlongSliceNormal = mat4.create();
190+
mat4.multiply(
191+
imageAlongSliceNormal,
192+
sliceOrientation.getMatrix(),
193+
model.volumeMapper.getInputData().getIndexToWorld()
194+
);
212195

213-
points.forEach((pt) => transform.apply(pt));
196+
// Transform the 8 corners of the input data's bounding box
197+
// to rotate into the slice plane space without the intermediate
198+
// axis-aligned box (provided by getBounds) which would grow the bounds.
199+
const transformedBounds = vtkBoundingBox.transformBounds(
200+
model.volumeMapper.getInputData().getSpatialExtent(),
201+
imageAlongSliceNormal
202+
);
214203

215204
// range is now maximum X distance
216-
let minX = Infinity;
217-
let maxX = -Infinity;
218-
for (let i = 0; i < 8; i++) {
219-
const x = points[i][0];
220-
if (x > maxX) {
221-
maxX = x;
222-
}
223-
if (x < minX) {
224-
minX = x;
225-
}
226-
}
205+
const minX = transformedBounds[0];
206+
const maxX = transformedBounds[1];
227207

228208
cache.sliceNormal = sliceNormal;
229209
cache.sliceRange = [minX, maxX];

0 commit comments

Comments
 (0)