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: {})

getBackgroundColor

Return the currently set background color.

getBackgroundColorByReference

Return the currently set background color.

getBoundsForSlice

Get bounds for a specified slice.
To be implemented by derived classes.

Argument Type Required Description
slice Number Yes The slice index. If undefined, the current slice is considered.
thickness Number Yes The slice thickness. If undefined, 0 is considered.

getCurrentImage

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

getCustomDisplayExtent

getCustomDisplayExtentByReference

getIsOpaque

getSlice

Get the slice index.

getUseCustomExtents

setBackgroundColor

Argument Type Required Description
color Yes specify background color as an array of 4 values.

setBackgroundColor

Argument Type Required Description
r Yes red component of background color
g Yes green component of background color
b Yes blue component of background color
a Yes opacity component of background color

setBackgroundColorFrom

Argument Type Required Description
color RGBAColor Yes specify the background color to use in RGBA format as an array of 4 values. Values are copied.

setCustomDisplayExtent

Argument Type Required Description
extents Yes specify extents as an array of 6 values [minx, maxx, …]

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 { Bounds, Extent, Nullable, RGBAColor } 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;

/**
* Get bounds for a specified slice.
* To be implemented by derived classes.
* @param {Number} slice The slice index. If undefined, the current slice is considered.
* @param {Number} thickness The slice thickness. If undefined, 0 is considered.
*/
getBoundsForSlice(slice?: number, thickness?: number): Bounds;

/**
* Return the currently set background color.
*/
getBackgroundColor(): RGBAColor;

/**
* Return the currently set background color.
*/
getBackgroundColorByReference(): RGBAColor;

/**
* @param r red component of background color
* @param g green component of background color
* @param b blue component of background color
* @param a opacity component of background color
*/
setBackgroundColor(r: number, g: number, b: number, a: number): boolean;

/**
*
* @param color specify background color as an array of 4 values.
*/
setBackgroundColor(color: RGBAColor): boolean;

/**
*
* @param {RGBAColor} color specify the background color to use
* in RGBA format as an array of 4 values. Values are copied.
*/
setBackgroundColorFrom(color: RGBAColor): boolean;

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

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

/**
*
*/
getCustomDisplayExtent(): Extent;

/**
*
*/
getCustomDisplayExtentByReference(): Extent;

/**
*
* @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 extents specify extents as an array of 6 values [minx, maxx, ...]
*/
setCustomDisplayExtent(customDisplayExtent: Extent): 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';
import { createUninitializedBounds } from 'vtk.js/Sources/Common/Core/Math';

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

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

publicAPI.getIsOpaque = () => true;

publicAPI.getCurrentImage = () => null;

publicAPI.getBoundsForSlice = () => {
macro.vtkErrorMacro(
'vtkAbstractImageMapper.getBoundsForSlice - NOT IMPLEMENTED'
);
return createUninitializedBounds();
};
}

// ----------------------------------------------------------------------------
// 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 };