Skip to content

Commit bf29210

Browse files
Zaid-Safadiswederik
authored andcommitted
refactor: standarize vtkInteractorStyleMPRSlice interface as vtk (#43)
1 parent ff31f0b commit bf29210

File tree

5 files changed

+154
-145
lines changed

5 files changed

+154
-145
lines changed

examples/VTKCrosshairsExample.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -134,16 +134,18 @@ class VTKCrosshairsExample extends Component {
134134
default:
135135
case 0:
136136
//Axial
137-
istyle.setSliceNormal([0, 0, 1], [0, -1, 0]);
138-
137+
istyle.setSliceNormal(0, 0, 1);
138+
istyle.setViewUp(0, -1, 0);
139139
break;
140140
case 1:
141141
// sagittal
142-
istyle.setSliceNormal([1, 0, 0], [0, 0, 1]);
142+
istyle.setSliceNormal(1, 0, 0);
143+
istyle.setViewUp(0, 0, 1);
143144
break;
144145
case 2:
145146
// Coronal
146-
istyle.setSliceNormal([0, 1, 0], [0, 0, 1]);
147+
istyle.setSliceNormal(0, 1, 0);
148+
istyle.setViewUp(0, 0, 1);
147149
break;
148150
}
149151

src/Custom/VTKMPRViewport.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -135,7 +135,7 @@ export default class VtkMpr extends Component {
135135
this.renderer.addVolume(this.labelPipeline.actor);
136136

137137
istyle.setVolumeMapper(this.pipeline.mapper);
138-
istyle.setSliceNormal([0, 0, 1]);
138+
istyle.setSliceNormal(0, 0, 1);
139139
const range = istyle.getSliceRange();
140140
istyle.setSlice((range[0] + range[1]) / 2);
141141

@@ -239,7 +239,7 @@ export default class VtkMpr extends Component {
239239

240240
if (prevProps.sliceNormal !== this.props.sliceNormal) {
241241
const istyle = this.istyle;
242-
istyle.setSliceNormal([...this.props.sliceNormal]);
242+
istyle.setSliceNormal(...this.props.sliceNormal);
243243

244244
const range = istyle.getSliceRange();
245245
istyle.setSlice((range[0] + range[1]) / 2);

src/VTKViewport/View2D.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -170,7 +170,7 @@ export default class View2D extends Component {
170170
this.props.interactorStyleVolumeMapper ||
171171
this.props.volumes[0].getMapper();
172172

173-
istyle.setSliceNormal([0, 0, 1]);
173+
istyle.setSliceNormal(0, 0, 1);
174174

175175
istyle.setVolumeMapper(istyleVolumeMapper);
176176
const range = istyle.getSliceRange();

src/VTKViewport/vtkInteractorStyleMPRSlice.js

Lines changed: 143 additions & 104 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,121 @@ function vtkInteractorStyleMPRSlice(publicAPI, model) {
9797
updateScrollManipulator();
9898
}
9999

100+
function isCameraViewInitialized(camera) {
101+
const dist = camera.getDistance();
102+
103+
return (
104+
typeof dist === 'number' && dist === Number(dist) && Number.isFinite(dist)
105+
);
106+
}
107+
108+
function onRotateChanged(args) {
109+
setSliceNormalInternal(args.detail.sliceNormal);
110+
setViewUpInternal(args.detail.sliceViewUp);
111+
}
112+
113+
function setViewUpInternal(viewUp) {
114+
const renderer = model.interactor.getCurrentRenderer();
115+
const camera = renderer.getActiveCamera();
116+
const _viewUp = [...viewUp];
117+
118+
if (model.volumeMapper) {
119+
let mapper = model.volumeMapper;
120+
// get the mapper if the model is actually the actor, not the mapper
121+
if (!model.volumeMapper.getInputData && model.volumeMapper.getMapper) {
122+
mapper = model.volumeMapper.getMapper();
123+
}
124+
let volumeCoordinateSpace = vec9toMat3(
125+
mapper.getInputData().getDirection()
126+
);
127+
// Transpose the volume's coordinate space to create a transformation matrix
128+
vtkMath.transpose3x3(volumeCoordinateSpace, volumeCoordinateSpace);
129+
130+
vtkMath.multiply3x3_vect3(volumeCoordinateSpace, _viewUp, _viewUp);
131+
camera.setViewUp(..._viewUp);
132+
}
133+
}
134+
135+
// in world space
136+
function setSliceNormalInternal(normal) {
137+
const renderer = model.interactor.getCurrentRenderer();
138+
const camera = renderer.getActiveCamera();
139+
140+
//copy arguments for internal editing so we don't cause sideeffects
141+
const _normal = [...normal];
142+
143+
if (model.volumeMapper) {
144+
vtkMath.normalize(_normal);
145+
let mapper = model.volumeMapper;
146+
// get the mapper if the model is actually the actor, not the mapper
147+
if (!model.volumeMapper.getInputData && model.volumeMapper.getMapper) {
148+
mapper = model.volumeMapper.getMapper();
149+
}
150+
let volumeCoordinateSpace = vec9toMat3(
151+
mapper.getInputData().getDirection()
152+
);
153+
// Transpose the volume's coordinate space to create a transformation matrix
154+
vtkMath.transpose3x3(volumeCoordinateSpace, volumeCoordinateSpace);
155+
// Convert the provided normal into the volume's space
156+
vtkMath.multiply3x3_vect3(volumeCoordinateSpace, _normal, _normal);
157+
let center = camera.getFocalPoint();
158+
let dist = camera.getDistance();
159+
let angle = camera.getViewAngle();
160+
161+
if (!isCameraViewInitialized(camera)) {
162+
const bounds = model.volumeMapper.getBounds();
163+
// diagonal will be used as "width" of camera scene
164+
const diagonal = Math.sqrt(
165+
vtkMath.distance2BetweenPoints(
166+
[bounds[0], bounds[2], bounds[4]],
167+
[bounds[1], bounds[3], bounds[5]]
168+
)
169+
);
170+
171+
// center will be used as initial focal point
172+
center = [
173+
(bounds[0] + bounds[1]) / 2.0,
174+
(bounds[2] + bounds[3]) / 2.0,
175+
(bounds[4] + bounds[5]) / 2.0,
176+
];
177+
178+
angle = 90;
179+
180+
// distance from camera to focal point
181+
dist = diagonal / (2 * Math.tan((angle / 360) * Math.PI));
182+
}
183+
184+
const cameraPos = [
185+
center[0] - _normal[0] * dist,
186+
center[1] - _normal[1] * dist,
187+
center[2] - _normal[2] * dist,
188+
];
189+
190+
// set viewUp based on DOP rotation
191+
// const oldDop = camera.getDirectionOfProjection();
192+
// const transform = vtkMatrixBuilder
193+
// .buildFromDegree()
194+
// .identity()
195+
// .rotateFromDirections(oldDop, _normal);
196+
197+
// transform.apply(_viewUp);
198+
199+
const { slabThickness } = model;
200+
201+
camera.setPosition(...cameraPos);
202+
camera.setDistance(dist);
203+
// should be set after pos and distance
204+
camera.setDirectionOfProjection(..._normal);
205+
camera.setViewAngle(angle);
206+
camera.setClippingRange(
207+
dist - slabThickness / 2,
208+
dist + slabThickness / 2
209+
);
210+
211+
publicAPI.setCenterOfRotation(center);
212+
}
213+
}
214+
100215
publicAPI.setViewport = viewportData => {
101216
if (model.viewportData) {
102217
const oldWindow = model.viewportData.getEventWindow();
@@ -111,20 +226,15 @@ function vtkInteractorStyleMPRSlice(publicAPI, model) {
111226
}
112227

113228
if (viewportData) {
114-
setSliceNormalInternal(
115-
viewportData.getInitialSliceNormal(),
116-
viewportData.getInitialViewUp()
117-
);
229+
setSliceNormalInternal(viewportData.getInitialSliceNormal());
230+
setViewUpInternal(viewportData.getInitialViewUp());
231+
118232
viewportData
119233
.getEventWindow()
120234
.addEventListener(EVENTS.VIEWPORT_ROTATED, onRotateChanged);
121235
}
122236
};
123237

124-
function onRotateChanged(args) {
125-
setSliceNormalInternal(args.detail.sliceNormal, args.detail.sliceViewUp);
126-
}
127-
128238
publicAPI.getViewport = () => model.viewportData;
129239

130240
let cameraSub = null;
@@ -195,10 +305,8 @@ function vtkInteractorStyleMPRSlice(publicAPI, model) {
195305
const viewportData = publicAPI.getViewport();
196306

197307
if (viewportData) {
198-
setSliceNormalInternal(
199-
viewportData.getInitialSliceNormal(),
200-
viewportData.getInitialViewUp()
201-
);
308+
setSliceNormalInternal(viewportData.getInitialSliceNormal());
309+
setViewUpInternal(viewportData.getInitialViewUp());
202310
}
203311

204312
updateScrollManipulator();
@@ -327,111 +435,42 @@ function vtkInteractorStyleMPRSlice(publicAPI, model) {
327435
return [0, 0, 0];
328436
};
329437

330-
function isCameraViewInitialized(camera) {
331-
const dist = camera.getDistance();
332-
333-
return (
334-
typeof dist === 'number' && dist === Number(dist) && Number.isFinite(dist)
335-
);
336-
}
337-
338-
publicAPI.setSliceNormal = (normal, viewUp = [0, 1, 0]) => {
438+
publicAPI.setSliceNormal = (...normal) => {
339439
const viewportData = publicAPI.getViewport();
340440

341441
if (viewportData) {
342-
viewportData.setInitialOrientation(normal, viewUp);
442+
viewportData.setInitialOrientation(
443+
normal,
444+
viewportData.getInitialViewUp()
445+
);
343446
}
344447

345-
setSliceNormalInternal(normal, viewUp);
448+
setSliceNormalInternal(normal);
346449
};
347450

348-
// in world space
349-
function setSliceNormalInternal(normal, viewUp = [0, 1, 0]) {
350-
const renderer = model.interactor.getCurrentRenderer();
351-
const camera = renderer.getActiveCamera();
352-
353-
// Copy arguments to the model, so they can be GET-ed later
354-
model.sliceNormal = [...normal];
355-
model.viewUp = [...viewUp];
356-
357-
//copy arguments for internal editing so we don't cause sideeffects
358-
const _normal = [...normal];
359-
const _viewUp = [...viewUp];
360-
361-
if (model.volumeMapper) {
362-
vtkMath.normalize(_normal);
363-
let mapper = model.volumeMapper;
364-
// get the mapper if the model is actually the actor, not the mapper
365-
if (!model.volumeMapper.getInputData && model.volumeMapper.getMapper) {
366-
mapper = model.volumeMapper.getMapper();
367-
}
368-
let volumeCoordinateSpace = vec9toMat3(
369-
mapper.getInputData().getDirection()
370-
);
371-
// Transpose the volume's coordinate space to create a transformation matrix
372-
vtkMath.transpose3x3(volumeCoordinateSpace, volumeCoordinateSpace);
373-
// Convert the provided normal into the volume's space
374-
vtkMath.multiply3x3_vect3(volumeCoordinateSpace, _normal, _normal);
375-
let center = camera.getFocalPoint();
376-
let dist = camera.getDistance();
377-
let angle = camera.getViewAngle();
378-
379-
if (!isCameraViewInitialized(camera)) {
380-
const bounds = model.volumeMapper.getBounds();
381-
// diagonal will be used as "width" of camera scene
382-
const diagonal = Math.sqrt(
383-
vtkMath.distance2BetweenPoints(
384-
[bounds[0], bounds[2], bounds[4]],
385-
[bounds[1], bounds[3], bounds[5]]
386-
)
387-
);
388-
389-
// center will be used as initial focal point
390-
center = [
391-
(bounds[0] + bounds[1]) / 2.0,
392-
(bounds[2] + bounds[3]) / 2.0,
393-
(bounds[4] + bounds[5]) / 2.0,
394-
];
395-
396-
angle = 90;
397-
398-
// distance from camera to focal point
399-
dist = diagonal / (2 * Math.tan((angle / 360) * Math.PI));
400-
}
401-
402-
const cameraPos = [
403-
center[0] - _normal[0] * dist,
404-
center[1] - _normal[1] * dist,
405-
center[2] - _normal[2] * dist,
406-
];
407-
408-
// set viewUp based on DOP rotation
409-
// const oldDop = camera.getDirectionOfProjection();
410-
// const transform = vtkMatrixBuilder
411-
// .buildFromDegree()
412-
// .identity()
413-
// .rotateFromDirections(oldDop, _normal);
451+
publicAPI.getViewUp = () => {
452+
if (model.volumeMapper && model.interactor) {
453+
const renderer = model.interactor.getCurrentRenderer();
454+
const camera = renderer.getActiveCamera();
414455

415-
// transform.apply(_viewUp);
456+
return camera.getViewUp();
457+
}
416458

417-
vtkMath.multiply3x3_vect3(volumeCoordinateSpace, _viewUp, _viewUp);
459+
return [0, 0, 0];
460+
};
418461

419-
const { slabThickness } = model;
462+
publicAPI.setViewUp = (...viewUp) => {
463+
const viewportData = publicAPI.getViewport();
420464

421-
camera.setPosition(...cameraPos);
422-
camera.setDistance(dist);
423-
// should be set after pos and distance
424-
camera.setDirectionOfProjection(..._normal);
425-
camera.setViewUp(..._viewUp);
426-
camera.setViewAngle(angle);
427-
camera.setClippingRange(
428-
dist - slabThickness / 2,
429-
dist + slabThickness / 2
465+
if (viewportData) {
466+
viewportData.setInitialOrientation(
467+
viewportData.getInitialSliceNormal(),
468+
viewUp
430469
);
431-
432-
publicAPI.setCenterOfRotation(center);
433470
}
434-
}
471+
472+
setViewUpInternal(viewUp);
473+
};
435474

436475
publicAPI.setSlabThickness = slabThickness => {
437476
model.slabThickness = slabThickness;

0 commit comments

Comments
 (0)