Skip to content

Commit

Permalink
Merge pull request Kitware#1992 from finetjul/reslice-cursor-rotation…
Browse files Browse the repository at this point in the history
…-handle-position

feat(reslicecursorwidget): set rotation handle position distance to c…
  • Loading branch information
finetjul authored Jul 13, 2021
2 parents 9962dd8 + 9606404 commit fb63f20
Show file tree
Hide file tree
Showing 6 changed files with 81 additions and 118 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -150,8 +150,29 @@ function vtkResliceCursorContextRepresentation(publicAPI, model) {
const length = vtkMath.normalize(vector);
axis.line.source.setDirection(vector);
axis.line.source.setHeight(length);
axis.rotation1.source.setCenter(state.getRotationPoint1());
axis.rotation2.source.setCenter(state.getRotationPoint2());

// Rotation handles
const pixelWorldHeight = publicAPI.getPixelWorldHeightAtCoord(center);
const { rendererPixelDims } = model.displayScaleParams;
const minDim = Math.min(rendererPixelDims[0], rendererPixelDims[1]);
const ratio = 0.5;
const distance =
(window.devicePixelRatio * (pixelWorldHeight * ratio * minDim)) / 2;
const rotationHandlePosition = [];
vtkMath.multiplyAccumulate(
center,
vector,
distance,
rotationHandlePosition
);
axis.rotation1.source.setCenter(rotationHandlePosition);
vtkMath.multiplyAccumulate(
center,
vector,
-distance,
rotationHandlePosition
);
axis.rotation2.source.setCenter(rotationHandlePosition);
}

/**
Expand Down Expand Up @@ -247,7 +268,6 @@ function vtkResliceCursorContextRepresentation(publicAPI, model) {
const axis2State = state[getAxis2]();

let activeLineState = null;
let activeRotationPointName = '';
let methodName = '';

switch (prop) {
Expand All @@ -261,22 +281,18 @@ function vtkResliceCursorContextRepresentation(publicAPI, model) {
break;
case model.pipelines.axes[0].rotation1.actor:
activeLineState = axis1State;
activeRotationPointName = 'RotationPoint1';
methodName = InteractionMethodsName.RotateLine;
break;
case model.pipelines.axes[0].rotation2.actor:
activeLineState = axis1State;
activeRotationPointName = 'RotationPoint2';
methodName = InteractionMethodsName.RotateLine;
break;
case model.pipelines.axes[1].rotation1.actor:
activeLineState = axis2State;
activeRotationPointName = 'RotationPoint1';
methodName = InteractionMethodsName.RotateLine;
break;
case model.pipelines.axes[1].rotation2.actor:
activeLineState = axis2State;
activeRotationPointName = 'RotationPoint2';
methodName = InteractionMethodsName.RotateLine;
break;
default:
Expand All @@ -285,7 +301,6 @@ function vtkResliceCursorContextRepresentation(publicAPI, model) {
}

state.setActiveLineState(activeLineState);
state.setActiveRotationPointName(activeRotationPointName);
state.setUpdateMethodName(methodName);

return state;
Expand All @@ -296,33 +311,39 @@ function vtkResliceCursorContextRepresentation(publicAPI, model) {
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
axis1Name: '',
axis2Name: '',
coincidentTopologyParameters: {
Point: {
factor: -1.0,
offset: -1.0,
},
Line: {
factor: -1.5,
offset: -1.5,
function defaultValues(initialValues) {
return {
axis1Name: '',
axis2Name: '',
coincidentTopologyParameters: {
Point: {
factor: -1.0,
offset: -1.0,
},
Line: {
factor: -1.5,
offset: -1.5,
},
Polygon: {
factor: -2.0,
offset: -2.0,
},
},
Polygon: {
factor: -2.0,
offset: -2.0,
},
},
rotationEnabled: true,
scaleInPixels: true,
viewType: null,
};
rotationEnabled: true,
rotationHandlePosition: 0.5,
scaleInPixels: true,
viewType: null,
...initialValues,
};
}

// ----------------------------------------------------------------------------

export function extend(publicAPI, model, initialValues = {}) {
Object.assign(model, defaultValues(initialValues));
vtkWidgetRepresentation.extend(publicAPI, model, initialValues);
Object.assign(model, DEFAULT_VALUES, initialValues);

macro.setGet(publicAPI, model, ['rotationHandlePosition']);

// Object specific methods
vtkResliceCursorContextRepresentation(publicAPI, model);
Expand Down
2 changes: 0 additions & 2 deletions Sources/Widgets/Widgets3D/ResliceCursorWidget/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ These sub states contain :

- activeLineState: Used in the behavior.js file in order to get the attribute of the selected line

- activeRotationPointName: Used in the behavior.js file in order to get the selected rotation point

- image: vtkImage used to place the reslice cursor

- activeViewType: Used in the behavior.js file in order to get the current view
Expand Down
15 changes: 7 additions & 8 deletions Sources/Widgets/Widgets3D/ResliceCursorWidget/behavior.js
Original file line number Diff line number Diff line change
Expand Up @@ -316,20 +316,19 @@ export default function widgetBehavior(publicAPI, model) {
);

const center = model.widgetState.getCenter();
const previousWorldPosition = activeLine[
`get${model.widgetState.getActiveRotationPointName()}`
]();

const previousVectorToOrigin = [0, 0, 0];
vtkMath.subtract(previousWorldPosition, center, previousVectorToOrigin);
vtkMath.normalize(previousVectorToOrigin);
const previousLineDirection = vtkMath.subtract(
activeLine.getPoint1(),
activeLine.getPoint2(),
[]
);
vtkMath.normalize(previousLineDirection);

const currentVectorToOrigin = [0, 0, 0];
vtkMath.subtract(worldCoords, center, currentVectorToOrigin);
vtkMath.normalize(currentVectorToOrigin);

const radianAngle = vtkMath.signedAngleBetweenVectors(
previousVectorToOrigin,
previousLineDirection,
currentVectorToOrigin,
planeNormal
);
Expand Down
51 changes: 17 additions & 34 deletions Sources/Widgets/Widgets3D/ResliceCursorWidget/example/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import vtkActor from 'vtk.js/Sources/Rendering/Core/Actor';
import vtkAnnotatedCubeActor from 'vtk.js/Sources/Rendering/Core/AnnotatedCubeActor';
import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
import vtkHttpDataSetReader from 'vtk.js/Sources/IO/Core/HttpDataSetReader';
import vtkGenericRenderWindow from 'vtk.js/Sources/Rendering/Misc/GenericRenderWindow';
import vtkImageData from 'vtk.js/Sources/Common/DataModel/ImageData';
import vtkImageMapper from 'vtk.js/Sources/Rendering/Core/ImageMapper';
import vtkImageReslice from 'vtk.js/Sources/Imaging/Core/ImageReslice';
Expand All @@ -15,11 +16,7 @@ import vtkInteractorStyleImage from 'vtk.js/Sources/Interaction/Style/Interactor
import vtkInteractorStyleTrackballCamera from 'vtk.js/Sources/Interaction/Style/InteractorStyleTrackballCamera';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import vtkOutlineFilter from 'vtk.js/Sources/Filters/General/OutlineFilter';
import vtkOpenGLRenderWindow from 'vtk.js/Sources/Rendering/OpenGL/RenderWindow';
import vtkOrientationMarkerWidget from 'vtk.js/Sources/Interaction/Widgets/OrientationMarkerWidget';
import vtkRenderer from 'vtk.js/Sources/Rendering/Core/Renderer';
import vtkRenderWindow from 'vtk.js/Sources/Rendering/Core/RenderWindow';
import vtkRenderWindowInteractor from 'vtk.js/Sources/Rendering/Core/RenderWindowInteractor';
import vtkResliceCursorWidget from 'vtk.js/Sources/Widgets/Widgets3D/ResliceCursorWidget';
import vtkWidgetManager from 'vtk.js/Sources/Widgets/Core/WidgetManager';

Expand Down Expand Up @@ -59,25 +56,9 @@ const showDebugActors = true;
// ----------------------------------------------------------------------------

const container = document.querySelector('body');
const table = document.createElement('table');
table.setAttribute('id', 'table');
container.appendChild(table);

// Define first line that will contains control panel
const trLine0 = document.createElement('tr');
trLine0.setAttribute('id', 'line0');
table.appendChild(trLine0);
const controlContainer = document.createElement('div');
trLine0.appendChild(controlContainer);
controlContainer.innerHTML = controlPanel;

const trLine1 = document.createElement('tr');
trLine1.setAttribute('id', 'line1');
table.appendChild(trLine1);

const trLine2 = document.createElement('tr');
trLine2.setAttribute('id', 'line2');
table.appendChild(trLine2);
container.appendChild(controlContainer);

// ----------------------------------------------------------------------------
// Setup rendering code
Expand Down Expand Up @@ -125,25 +106,28 @@ function createRGBStringFromRGBValues(rgb) {
}

widgetState.setOpacity(0.6);
widgetState.setSphereRadius(10);

const initialPlanesState = { ...widgetState.getPlanes() };

let view3D = null;

for (let i = 0; i < 4; i++) {
const element = document.createElement('td');

if (i % 2 === 0) {
trLine2.appendChild(element);
} else {
trLine1.appendChild(element);
}

const element = document.createElement('div');
element.setAttribute('class', 'view');
element.style.width = '50%';
element.style.height = '300px';
element.style.display = 'inline-block';
container.appendChild(element);

const grw = vtkGenericRenderWindow.newInstance();
grw.setContainer(element);
grw.resize();
const obj = {
renderWindow: vtkRenderWindow.newInstance(),
renderer: vtkRenderer.newInstance(),
GLWindow: vtkOpenGLRenderWindow.newInstance(),
interactor: vtkRenderWindowInteractor.newInstance(),
renderWindow: grw.getRenderWindow(),
renderer: grw.getRenderer(),
GLWindow: grw.getOpenGLRenderWindow(),
interactor: grw.getInteractor(),
widgetManager: vtkWidgetManager.newInstance(),
};

Expand All @@ -152,7 +136,6 @@ for (let i = 0; i < 4; i++) {
obj.renderWindow.addRenderer(obj.renderer);
obj.renderWindow.addView(obj.GLWindow);
obj.renderWindow.setInteractor(obj.interactor);
obj.GLWindow.setContainer(element);
obj.interactor.setView(obj.GLWindow);
obj.interactor.initialize();
obj.interactor.bindEvents(element);
Expand Down
38 changes: 7 additions & 31 deletions Sources/Widgets/Widgets3D/ResliceCursorWidget/helpers.js
Original file line number Diff line number Diff line change
Expand Up @@ -132,7 +132,7 @@ export function rotateVector(vectorToBeRotated, axis, angle) {
}

// Update the extremities and the rotation point coordinate of the line
function updateLine(lineState, center, axis, lineLength, rotationLength) {
function updateLine(lineState, center, axis, lineLength) {
const p1 = [
center[0] - lineLength * axis[0],
center[1] - lineLength * axis[1],
Expand All @@ -143,21 +143,9 @@ function updateLine(lineState, center, axis, lineLength, rotationLength) {
center[1] + lineLength * axis[1],
center[2] + lineLength * axis[2],
];
const rotationP1 = [
center[0] - rotationLength * axis[0],
center[1] - rotationLength * axis[1],
center[2] - rotationLength * axis[2],
];
const rotationP2 = [
center[0] + rotationLength * axis[0],
center[1] + rotationLength * axis[1],
center[2] + rotationLength * axis[2],
];

lineState.setPoint1(p1);
lineState.setPoint2(p2);
lineState.setRotationPoint1(rotationP1);
lineState.setRotationPoint2(rotationP2);
}

// Update the reslice cursor state according to the three planes normals and the origin
Expand All @@ -173,12 +161,6 @@ export function updateState(widgetState) {

const bounds = widgetState.getImage().getBounds();
const center = widgetState.getCenter();
// Factor used to define where the rotation point will be displayed
// according to the plane size where there will be visible
const factor = 0.5 * 0.85;
const xRotationLength = (bounds[1] - bounds[0]) * factor;
const yRotationLength = (bounds[3] - bounds[2]) * factor;
const zRotationLength = (bounds[5] - bounds[4]) * factor;

// Length of the principal diagonal.
const pdLength = 20 * 0.5 * vtkBoundingBox.getDiagonalLength(bounds);
Expand All @@ -187,45 +169,39 @@ export function updateState(widgetState) {
widgetState.getAxisXinY(),
center,
xyIntersectionLineAxis,
pdLength,
zRotationLength
pdLength
);
updateLine(
widgetState.getAxisYinX(),
center,
xyIntersectionLineAxis,
pdLength,
zRotationLength
pdLength
);

updateLine(
widgetState.getAxisYinZ(),
center,
yzIntersectionLineAxis,
pdLength,
xRotationLength
pdLength
);
updateLine(
widgetState.getAxisZinY(),
center,
yzIntersectionLineAxis,
pdLength,
xRotationLength
pdLength
);

updateLine(
widgetState.getAxisXinZ(),
center,
xzIntersectionLineAxis,
pdLength,
yRotationLength
pdLength
);
updateLine(
widgetState.getAxisZinX(),
center,
xzIntersectionLineAxis,
pdLength,
yRotationLength
pdLength
);
}

Expand Down
Loading

0 comments on commit fb63f20

Please sign in to comment.