|
1 | 1 | import macro from 'vtk.js/Sources/macros'; |
2 | 2 | import * as vtkMath from 'vtk.js/Sources/Common/Core/Math'; |
3 | 3 | import vtkMatrixBuilder from 'vtk.js/Sources/Common/Core/MatrixBuilder'; |
| 4 | +import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox'; |
4 | 5 | import vtkInteractorStyleManipulator from 'vtk.js/Sources/Interaction/Style/InteractorStyleManipulator'; |
5 | 6 | import vtkMouseCameraTrackballRotateManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballRotateManipulator'; |
6 | 7 | import vtkMouseCameraTrackballPanManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballPanManipulator'; |
7 | 8 | import vtkMouseCameraTrackballZoomManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseCameraTrackballZoomManipulator'; |
8 | 9 | import vtkMouseRangeManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseRangeManipulator'; |
9 | 10 |
|
| 11 | +import { mat4 } from 'gl-matrix'; |
10 | 12 | // ---------------------------------------------------------------------------- |
11 | 13 | // Global methods |
12 | 14 | // ---------------------------------------------------------------------------- |
13 | 15 |
|
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 | | - |
27 | 16 | // ---------------------------------------------------------------------------- |
28 | 17 |
|
29 | 18 | function clamp(value, min, max) { |
@@ -153,14 +142,9 @@ function vtkInteractorStyleMPRSlice(publicAPI, model) { |
153 | 142 |
|
154 | 143 | if (model.volumeMapper) { |
155 | 144 | const range = publicAPI.getSliceRange(); |
156 | | - const bounds = model.volumeMapper.getBounds(); |
157 | 145 |
|
158 | 146 | 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(); |
164 | 148 |
|
165 | 149 | const distance = camera.getDistance(); |
166 | 150 | const dop = camera.getDirectionOfProjection(); |
@@ -193,37 +177,33 @@ function vtkInteractorStyleMPRSlice(publicAPI, model) { |
193 | 177 | if (model.volumeMapper) { |
194 | 178 | const sliceNormal = publicAPI.getSliceNormal(); |
195 | 179 |
|
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)) { |
201 | 181 | return cache.sliceRange; |
202 | 182 | } |
203 | 183 |
|
204 | | - const bounds = model.volumeMapper.getBounds(); |
205 | | - const points = boundsToCorners(bounds); |
206 | | - |
207 | 184 | // Get rotation matrix from normal to +X (since bounds is aligned to XYZ) |
208 | | - const transform = vtkMatrixBuilder |
| 185 | + const sliceOrientation = vtkMatrixBuilder |
209 | 186 | .buildFromDegree() |
210 | 187 | .identity() |
211 | 188 | .rotateFromDirections(sliceNormal, [1, 0, 0]); |
| 189 | + const imageAlongSliceNormal = mat4.create(); |
| 190 | + mat4.multiply( |
| 191 | + imageAlongSliceNormal, |
| 192 | + sliceOrientation.getMatrix(), |
| 193 | + model.volumeMapper.getInputData().getIndexToWorld() |
| 194 | + ); |
212 | 195 |
|
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 | + ); |
214 | 203 |
|
215 | 204 | // 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]; |
227 | 207 |
|
228 | 208 | cache.sliceNormal = sliceNormal; |
229 | 209 | cache.sliceRange = [minX, maxX]; |
|
0 commit comments