AbstractImageMapper

Introduction

vtkImageMapper provides 2D image display support for vtk.
It can be associated with a vtkImageSlice prop and placed within a Renderer.

This class resolves coincident topology with the same methods as vtkMapper.

Methods

extend

Method use to decorate a given object (publicAPI+model) with vtkAbstractImageMapper characteristics.

Argument Type Required Description
publicAPI Yes object on which methods will be bounds (public)
model Yes object on which data structure will be bounds (protected)
initialValues IAbstractImageMapperInitialValues No (default: {})

getCurrentImage

Return currently active image for the mapper. Overridden by deriving classes.

getIsOpaque

getSlice

Get the slice index.

getUseCustomExtents

setCustomDisplayExtent

Argument Type Required Description
x1 Number Yes The x coordinate of the first point.
x2 Number Yes The x coordinate of the second point.
y1 Number Yes The y coordinate of the first point.
y2 Number Yes The y coordinate of the second point.
z1 Number Yes The z coordinate of the first point.
z2 Number Yes The z coordinate of the second point.

setCustomDisplayExtentFrom

Argument Type Required Description
customDisplayExtent Yes

setSlice

Argument Type Required Description
slice Number Yes The slice index.

setUseCustomExtents

Argument Type Required Description
useCustomExtents Boolean Yes

Source

helper.js
import { vec3 } from 'gl-matrix';
import vtkPlane from 'vtk.js/Sources/Common/DataModel/Plane';

/**
* Perform plane-line intersection, where the line is defined by two points (p1, p2),
* and the plane is defined by the imageData and slice number.
*
* @param {Vector3} p1
* @param {Vector3} p2
* @param {vtkImageMapper|vtkImageArrayMapper} mapper
*/
function doPicking(p1, p2, mapper) {
const imageData = mapper.getCurrentImage();
const extent = imageData.getExtent();

// Slice origin
const ijk = [extent[0], extent[2], extent[4]];
const { ijkMode } = mapper.getClosestIJKAxis();
let nSlice = mapper.isA('vtkImageArrayMapper')
? mapper.getSubSlice()
: mapper.getSlice();
if (ijkMode !== mapper.getSlicingMode()) {
// If not IJK slicing, get the IJK slice from the XYZ position/slice
nSlice = mapper.getSliceAtPosition(nSlice);
}
ijk[ijkMode] += nSlice;
const worldOrigin = [0, 0, 0];
imageData.indexToWorld(ijk, worldOrigin);

// Normal computation
ijk[ijkMode] += 1;
const worldNormal = [0, 0, 0];
imageData.indexToWorld(ijk, worldNormal);
worldNormal[0] -= worldOrigin[0];
worldNormal[1] -= worldOrigin[1];
worldNormal[2] -= worldOrigin[2];
vec3.normalize(worldNormal, worldNormal);

const intersect = vtkPlane.intersectWithLine(
p1,
p2,
worldOrigin,
worldNormal
);
if (intersect.intersection) {
const point = intersect.x;
const absoluteIJK = [0, 0, 0];
imageData.worldToIndex(point, absoluteIJK);
// `t` is the parametric position along the line
// defined in Plane.intersectWithLine
return {
t: intersect.t,
absoluteIJK,
};
}
return null;
}

/**
* Implement point picking for image plane.
* The plane is defined by the imageData and current slice number,
* set in the input mapper.
*
* @param {Vector3} p1
* @param {Vector3} p2
* @param {vtkImageMapper|vtkImageArrayMapper} mapper
*/
export function intersectWithLineForPointPicking(p1, p2, mapper) {
const pickingData = doPicking(p1, p2, mapper);
if (pickingData) {
const imageData = mapper.getCurrentImage();
const extent = imageData.getExtent();

// Get closer integer ijk
// NB: point picking means closest slice, means rounding
const ijk = [
Math.round(pickingData.absoluteIJK[0]),
Math.round(pickingData.absoluteIJK[1]),
Math.round(pickingData.absoluteIJK[2]),
];

// Are we outside our actual extent
if (
ijk[0] < extent[0] ||
ijk[0] > extent[1] ||
ijk[1] < extent[2] ||
ijk[1] > extent[3] ||
ijk[2] < extent[4] ||
ijk[2] > extent[5]
) {
return null;
}

return {
t: pickingData.t,
ijk,
};
}
return null;
}

/**
* Implement cell picking for image plane.
* The plane is defined by the imageData and current slice number,
* set in the input mapper.
*
* @param {Vector3} p1
* @param {Vector3} p2
* @param {vtkImageMapper|vtkImageArrayMapper} mapper
*/
export function intersectWithLineForCellPicking(p1, p2, mapper) {
const pickingData = doPicking(p1, p2, mapper);
if (pickingData) {
const imageData = mapper.getCurrentImage();
const extent = imageData.getExtent();
const absIJK = pickingData.absoluteIJK;

// Get closer integer ijk
// NB: cell picking means closest voxel, means flooring
const ijk = [
Math.floor(absIJK[0]),
Math.floor(absIJK[1]),
Math.floor(absIJK[2]),
];

// Are we outside our actual extent
if (
ijk[0] < extent[0] ||
ijk[0] > extent[1] - 1 ||
ijk[1] < extent[2] ||
ijk[1] > extent[3] - 1 ||
ijk[2] < extent[4] ||
// handle single-slice images
ijk[2] > (extent[5] ? extent[5] - 1 : extent[5])
) {
return null;
}

// Parametric coordinates within cell
const pCoords = [
absIJK[0] - ijk[0],
absIJK[1] - ijk[1],
absIJK[2] - ijk[2],
];

return {
t: pickingData.t,
ijk,
pCoords,
};
}
return null;
}
index.d.ts
import vtkAbstractMapper3D, { IAbstractMapper3DInitialValues } from "../AbstractMapper3D";
import vtkImageData from "../../../Common/DataModel/ImageData";
import { Nullable } from "../../../types";


export interface IAbstractImageMapperInitialValues extends IAbstractMapper3DInitialValues {
customDisplayExtent?: number[];
useCustomExtents?: boolean;
slice?: number;
}

export interface vtkAbstractImageMapper extends vtkAbstractMapper3D {

/**
*
*/
getIsOpaque(): boolean;

/**
* Return currently active image for the mapper. Overridden by deriving classes.
*/
getCurrentImage(): Nullable<vtkImageData>;

/**
* Get the slice index.
*/
getSlice(): number;

/**
*
* @param {Number} slice The slice index.
*/
setSlice(slice: number): boolean;

/**
*
*/
getUseCustomExtents(): boolean;

/**
*
* @param {Boolean} useCustomExtents
*/
setUseCustomExtents(useCustomExtents: boolean): boolean;

/**
*
* @param {Number} x1 The x coordinate of the first point.
* @param {Number} x2 The x coordinate of the second point.
* @param {Number} y1 The y coordinate of the first point.
* @param {Number} y2 The y coordinate of the second point.
* @param {Number} z1 The z coordinate of the first point.
* @param {Number} z2 The z coordinate of the second point.
*/
setCustomDisplayExtent(x1: number, x2: number, y1: number, y2: number, z1: number, z2: number): boolean;

/**
*
* @param customDisplayExtent
*/
setCustomDisplayExtentFrom(customDisplayExtent: number[]): boolean;
}

/**
* Method use to decorate a given object (publicAPI+model) with vtkAbstractImageMapper characteristics.
*
* @param publicAPI object on which methods will be bounds (public)
* @param model object on which data structure will be bounds (protected)
* @param {IAbstractImageMapperInitialValues} [initialValues] (default: {})
*/
export function extend(publicAPI: object, model: object, initialValues?: IAbstractImageMapperInitialValues): void;

/**
* vtkImageMapper provides 2D image display support for vtk.
* It can be associated with a vtkImageSlice prop and placed within a Renderer.
*
* This class resolves coincident topology with the same methods as vtkMapper.
*/
export declare const vtkAbstractImageMapper: {
extend: typeof extend;
}
export default vtkAbstractImageMapper;
index.js
import macro from 'vtk.js/Sources/macros';
import vtkAbstractMapper3D from 'vtk.js/Sources/Rendering/Core/AbstractMapper3D';

// ----------------------------------------------------------------------------
// vtkAbstractImageMapper methods
// ----------------------------------------------------------------------------

function vtkAbstractImageMapper(publicAPI, model) {
model.classHierarchy.push('vtkAbstractImageMapper');

publicAPI.getIsOpaque = () => true;

publicAPI.getCurrentImage = () => null;
}

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

const DEFAULT_VALUES = {
slice: 0,
customDisplayExtent: [0, 0, 0, 0, 0, 0],
useCustomExtents: false,
backgroundColor: [0, 0, 0, 1],
};

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

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

// Build VTK API
vtkAbstractMapper3D.extend(publicAPI, model, initialValues);

macro.setGet(publicAPI, model, ['slice', 'useCustomExtents']);
macro.setGetArray(publicAPI, model, ['customDisplayExtent'], 6);
macro.setGetArray(publicAPI, model, ['backgroundColor'], 4);

vtkAbstractImageMapper(publicAPI, model);
}

// ----------------------------------------------------------------------------
export default { extend };