Skip to content

Commit

Permalink
Merge pull request #511 from agirault/range-manipulator
Browse files Browse the repository at this point in the history
Range manipulator
  • Loading branch information
jourdain authored Jan 18, 2018
2 parents 99c853a + f0debde commit 74d161c
Show file tree
Hide file tree
Showing 6 changed files with 330 additions and 45 deletions.
32 changes: 4 additions & 28 deletions Sources/Interaction/Manipulators/CameraManipulator/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import macro from 'vtk.js/Sources/macro';
import vtkMouseManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseManipulator';

// ----------------------------------------------------------------------------
// vtkCameraManipulator methods
Expand All @@ -8,14 +9,6 @@ function vtkCameraManipulator(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkCameraManipulator');

publicAPI.startInteraction = () => {};
publicAPI.endInteraction = () => {};
publicAPI.onButtonDown = (interactor) => {};
publicAPI.onButtonUp = (interactor) => {};
publicAPI.onAnimation = (interactor, renderer) => {};
publicAPI.onKeyUp = (interactor) => {};
publicAPI.onKeyDown = (interactor) => {};

//-------------------------------------------------------------------------
publicAPI.computeDisplayCenter = (iObserver) => {
const pt = iObserver.computeWorldToDisplay(
Expand All @@ -33,38 +26,21 @@ function vtkCameraManipulator(publicAPI, model) {
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
manipulatorName: 'goldschlager',

button: 1,
shift: false,
control: false,
alt: false,

center: [0, 0, 0],
rotationFactor: 1,
displayCenter: [0, 0],

pinch: false,
};

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

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

// Object methods
macro.obj(publicAPI, model);
// Inheritance
vtkMouseManipulator.extend(publicAPI, model, initialValues);

// Create get-set macros
macro.setGet(publicAPI, model, [
'manipulatorName',
'button',
'shift',
'control',
'alt',
'rotationFactor',
'pinch',
]);
macro.setGet(publicAPI, model, ['rotationFactor']);

macro.setGetArray(publicAPI, model, ['displayCenter'], 2);

Expand Down
62 changes: 62 additions & 0 deletions Sources/Interaction/Manipulators/MouseManipulator/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
import macro from 'vtk.js/Sources/macro';

// ----------------------------------------------------------------------------
// vtkMouseManipulator methods
// ----------------------------------------------------------------------------

function vtkMouseManipulator(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkMouseManipulator');

publicAPI.startInteraction = () => {};
publicAPI.endInteraction = () => {};
publicAPI.onButtonDown = (interactor) => {};
publicAPI.onButtonUp = (interactor) => {};
publicAPI.onAnimation = (interactor, renderer) => {};
publicAPI.onKeyUp = (interactor) => {};
publicAPI.onKeyDown = (interactor) => {};
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
manipulatorName: 'goldschlager',

button: 1,
shift: false,
control: false,
alt: false,
pinch: false,
};

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

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

// Object methods
macro.obj(publicAPI, model);

// Create get-set macros
macro.setGet(publicAPI, model, [
'manipulatorName',
'button',
'shift',
'control',
'alt',
'pinch',
]);

// Object specific methods
vtkMouseManipulator(publicAPI, model);
}

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

export const newInstance = macro.newInstance(extend, 'vtkMouseManipulator');

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

export default Object.assign({ newInstance, extend });
81 changes: 81 additions & 0 deletions Sources/Interaction/Manipulators/RangeManipulator/example/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,81 @@
import 'vtk.js/Sources/favicon';

import vtkFullScreenRenderWindow from 'vtk.js/Sources/Rendering/Misc/FullScreenRenderWindow';
import vtkRTAnalyticSource from 'vtk.js/Sources/Filters/Sources/RTAnalyticSource';
import vtkImageMapper from 'vtk.js/Sources/Rendering/Core/ImageMapper';
import vtkImageSlice from 'vtk.js/Sources/Rendering/Core/ImageSlice';
import vtkInteractorStyleManipulator from 'vtk.js/Sources/Interaction/Style/InteractorStyleManipulator';

import Manipulators from 'vtk.js/Sources/Interaction/Manipulators';

// ----------------------------------------------------------------------------
// Standard rendering code setup
// ----------------------------------------------------------------------------

const fullScreenRenderer = vtkFullScreenRenderWindow.newInstance();
const renderer = fullScreenRenderer.getRenderer();
const renderWindow = fullScreenRenderer.getRenderWindow();

// ----------------------------------------------------------------------------
// Example code
// ----------------------------------------------------------------------------

const rtSource = vtkRTAnalyticSource.newInstance();
rtSource.setWholeExtent(0, 200, 0, 200, 0, 200);
rtSource.setCenter(100, 100, 100);
rtSource.setStandardDeviation(0.3);

const mapper = vtkImageMapper.newInstance();
mapper.setInputConnection(rtSource.getOutputPort());

const actor = vtkImageSlice.newInstance();
actor.getProperty().setColorWindow(100);
actor.getProperty().setColorLevel(50);
actor.setMapper(mapper);

const data = rtSource.getOutputData();
const range = data
.getPointData()
.getScalars()
.getRange();
const wMin = 1;
const wMax = range[1] - range[0];
const wCurrent = actor.getProperty().getColorWindow();
const wCallback = actor.getProperty().setColorWindow;
const lMin = range[0];
const lMax = range[1];
const lCurrent = actor.getProperty().getColorLevel();
const lCallback = actor.getProperty().setColorLevel;
const bounds = data.getBounds();
const zMin = bounds[4];
const zMax = bounds[5];
const zCurrent = mapper.getZSlice();
const zCallback = mapper.setZSlice;

const rangeManipulator = Manipulators.vtkRangeManipulator.newInstance({
button: 1,
pinch: true,
});
rangeManipulator.setVerticalListener(wMin, wMax, wCurrent, 1, wCallback);
rangeManipulator.setHorizontalListener(lMin, lMax, lCurrent, 1, lCallback);
rangeManipulator.setScrollListener(zMin, zMax, zCurrent, 1, zCallback);

const iStyle = vtkInteractorStyleManipulator.newInstance();
iStyle.addManipulator(rangeManipulator);
renderWindow.getInteractor().setInteractorStyle(iStyle);

renderer.getActiveCamera().setParallelProjection(true);
renderer.addActor(actor);
renderer.resetCamera();
renderWindow.render();

// -----------------------------------------------------------
// Make some variables global so that you can inspect and
// modify objects in your browser's developer console:
// -----------------------------------------------------------

global.source = rtSource;
global.mapper = mapper;
global.actor = actor;
global.renderer = renderer;
global.renderWindow = renderWindow;
158 changes: 158 additions & 0 deletions Sources/Interaction/Manipulators/RangeManipulator/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
import macro from 'vtk.js/Sources/macro';
import vtkMouseManipulator from 'vtk.js/Sources/Interaction/Manipulators/MouseManipulator';

// ----------------------------------------------------------------------------
// vtkRangeManipulator methods
// ----------------------------------------------------------------------------

function vtkRangeManipulator(publicAPI, model) {
// Set our className
model.classHierarchy.push('vtkRangeManipulator');

//-------------------------------------------------------------------------
function processDelta(listener, delta) {
let normDelta = delta;
normDelta *= (listener.max - listener.min) / listener.step + 1;
let value = listener.value + normDelta;

const difference = value - listener.min;
const stepsToDifference = Math.round(difference / listener.step);
value = listener.min + listener.step * stepsToDifference;
value = Math.max(value, listener.min);
value = Math.min(value, listener.max);

listener.callback(value);
listener.value = value;
}

//-------------------------------------------------------------------------
publicAPI.setHorizontalListener = (min, max, value, step, callback) => {
model.horizontalListener = { min, max, value, step, callback };
publicAPI.modified();
};

//-------------------------------------------------------------------------
publicAPI.setVerticalListener = (min, max, value, step, callback) => {
model.verticalListener = { min, max, value, step, callback };
publicAPI.modified();
};

//-------------------------------------------------------------------------
publicAPI.setScrollListener = (min, max, value, step, callback) => {
model.scrollListener = { min, max, value, step, callback };
publicAPI.modified();
};

//-------------------------------------------------------------------------
publicAPI.removeHorizontalListener = () => {
if (model.verticalListener) {
delete model.verticalListener;
publicAPI.modified();
}
};

//-------------------------------------------------------------------------
publicAPI.removeVerticalListener = () => {
if (model.horizontalListener) {
delete model.horizontalListener;
publicAPI.modified();
}
};

//-------------------------------------------------------------------------
publicAPI.removeScrollListener = () => {
if (model.scrollListener) {
delete model.scrollListener;
publicAPI.modified();
}
};

//-------------------------------------------------------------------------
publicAPI.removeAllListeners = () => {
publicAPI.removeHorizontalListener();
publicAPI.removeVerticalListener();
publicAPI.removesCrollListener();
};

//-------------------------------------------------------------------------
publicAPI.onAnimation = (interactor, renderer) => {
if (!model.verticalListener && !model.horizontalListener) {
return;
}

const lastPtr = interactor.getPointerIndex();
const pos = interactor.getAnimationEventPosition(lastPtr);
const lastPos = interactor.getLastAnimationEventPosition(lastPtr);

if (!pos || !lastPos || !renderer) {
return;
}

// Scale by viewport size
const size = interactor.getView().getViewportSize(renderer);

if (model.horizontalListener) {
const dx = (pos.x - lastPos.x) / size[0];
processDelta(model.horizontalListener, dx);
}
if (model.verticalListener) {
const dy = (pos.y - lastPos.y) / size[1];
processDelta(model.verticalListener, dy);
}
};

//-------------------------------------------------------------------------
publicAPI.onPinch = (interactor) => {
if (!model.scrollListener) {
return;
}

const interactorStyle = interactor.getInteractorStyle();
let renderer = interactorStyle.getCurrentRenderer();

if (!renderer) {
const pos = interactor.getAnimationEventPosition(
interactor.getPointerIndex()
);
renderer = interactor.findPokedRenderer(pos);
if (!renderer) {
return;
}
}

const scale = interactor.getScale();
const lastScale = interactor.getLastScale();
const delta = 1.0 - scale / lastScale;
processDelta(model.scrollListener, delta);
};
}

// ----------------------------------------------------------------------------
// Object factory
// ----------------------------------------------------------------------------

const DEFAULT_VALUES = {
horizontalListener: null,
verticalListener: null,
scrollListener: null,
};

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

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

// Inheritance
vtkMouseManipulator.extend(publicAPI, model, initialValues);

// Object specific methods
vtkRangeManipulator(publicAPI, model);
}

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

export const newInstance = macro.newInstance(extend, 'vtkRangeManipulator');

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

export default Object.assign({ newInstance, extend });
4 changes: 4 additions & 0 deletions Sources/Interaction/Manipulators/index.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
import vtkCameraManipulator from './CameraManipulator';
import vtkMouseManipulator from './MouseManipulator';
import vtkRangeManipulator from './RangeManipulator';
import vtkSliceManipulator from './SliceManipulator';
import vtkTrackballMultiRotate from './TrackballMultiRotate';
import vtkTrackballPan from './TrackballPan';
Expand All @@ -9,6 +11,8 @@ import vtkTrackballZoomToMouse from './TrackballZoomToMouse';

export default {
vtkCameraManipulator,
vtkMouseManipulator,
vtkRangeManipulator,
vtkSliceManipulator,
vtkTrackballMultiRotate,
vtkTrackballPan,
Expand Down
Loading

0 comments on commit 74d161c

Please sign in to comment.