LookupTable

Introduction

vtkLookupTable is a 2D widget for manipulating a marker prop

Methods

buildSpecialColors

extend

Method used to decorate a given object (publicAPI+model) with vtkLookupTable 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 ILookupTableInitialValues No (default: {})

forceBuild

getAboveRangeColor

getAboveRangeColorByReference

getAlphaRange

getAlphaRangeByReference

getBelowRangeColor

getBelowRangeColorByReference

getHueRange

getHueRangeByReference

getNanColor

getNanColorByReference

getNumberOfAnnotatedValues

getNumberOfAvailableColors

getNumberOfColors

getRange

getSaturationRange

getSaturationRangeByReference

getUseAboveRangeColor

getUseBelowRangeColor

getValueRange

getValueRangeByReference

indexedLookupFunction

Argument Type Required Description
v Yes
table Yes
p Yes

linearIndexLookup

Argument Type Required Description
v Yes
p Yes

linearLookup

Argument Type Required Description
v Yes
table Yes
p Yes

lookupShiftAndScale

Argument Type Required Description
range Yes
p Yes

newInstance

Method used to create a new instance of vtkLookupTable

Argument Type Required Description
initialValues ILookupTableInitialValues No for pre-setting some of its content

setAboveRangeColor

Argument Type Required Description
aboveRangeColor Yes

setAboveRangeColorFrom

Argument Type Required Description
aboveRangeColor Yes

setAlphaRange

Argument Type Required Description
alphaRange Yes

setAlphaRangeFrom

Argument Type Required Description
alphaRange Yes

setBelowRangeColor

Argument Type Required Description
belowRangeColor Yes

setBelowRangeColorFrom

Argument Type Required Description
belowRangeColor Yes

setHueRange

Argument Type Required Description
hueRange Yes

setHueRangeFrom

Argument Type Required Description
hueRange Yes

setNanColor

Argument Type Required Description
nanColor Yes

setNanColorFrom

Argument Type Required Description
nanColor Yes

setNumberOfColors

Argument Type Required Description
numberOfColors Yes

setSaturationRange

Argument Type Required Description
saturationRange Yes

setSaturationRangeFrom

Argument Type Required Description
saturationRange Yes

setTable

Argument Type Required Description
table Yes

setUseAboveRangeColor

Argument Type Required Description
useAboveRangeColor Yes

setUseBelowRangeColor

Argument Type Required Description
useBelowRangeColor Yes

setValueRange

Argument Type Required Description
valueRange Yes

setValueRangeFrom

Argument Type Required Description
valueRange Yes

Source

index.d.ts
import { Range, RGBAColor } from '../../../types';
import vtkScalarsToColors from '../ScalarsToColors';

/**
*
*/
export interface ILookupTableInitialValues {}

export interface vtkLookupTable extends vtkScalarsToColors {
/**
*
*/
buildSpecialColors(): void;

/**
*
*/
forceBuild(): void;

/**
*
*/
getAboveRangeColor(): RGBAColor;

/**
*
*/
getAboveRangeColorByReference(): RGBAColor;

/**
*
*/
getAlphaRange(): Range;

/**
*
*/
getAlphaRangeByReference(): Range;

/**
*
*/
getBelowRangeColor(): RGBAColor;

/**
*
*/
getBelowRangeColorByReference(): RGBAColor;

/**
*
*/
getHueRange(): Range;

/**
*
*/
getHueRangeByReference(): Range;

/**
*
*/
getNanColor(): RGBAColor;

/**
*
*/
getNanColorByReference(): RGBAColor;

/**
*
*/
getNumberOfAnnotatedValues(): number;

/**
*
*/
getNumberOfAvailableColors(): number;

/**
*
*/
getNumberOfColors(): number;

/**
*
*/
getRange(): Range;

/**
*
*/
getSaturationRange(): Range;

/**
*
*/
getSaturationRangeByReference(): Range;

/**
*
*/
getUseAboveRangeColor(): boolean;

/**
*
*/
getUseBelowRangeColor(): boolean;

/**
*
*/
getValueRange(): Range;

/**
*
*/
getValueRangeByReference(): Range;

/**
*
* @param v
* @param table
* @param p
*/
indexedLookupFunction(v: number, table: any, p: object): RGBAColor;

/**
*
* @param v
* @param p
*/
linearIndexLookup(v: number, p: object): number;

/**
*
* @param v
* @param table
* @param p
*/
linearLookup(v: number, table: any, p: object): RGBAColor;

/**
*
* @param range
* @param p
*/
lookupShiftAndScale(range: Range, p: object): boolean;

/**
*
* @param aboveRangeColor
*/
setAboveRangeColor(aboveRangeColor: RGBAColor): boolean;

/**
*
* @param aboveRangeColor
*/
setAboveRangeColorFrom(aboveRangeColor: RGBAColor): boolean;

/**
*
* @param alphaRange
*/
setAlphaRange(alphaRange: Range): boolean;

/**
*
* @param alphaRange
*/
setAlphaRangeFrom(alphaRange: Range): boolean;

/**
*
* @param belowRangeColor
*/
setBelowRangeColor(belowRangeColor: RGBAColor): boolean;

/**
*
* @param belowRangeColor
*/
setBelowRangeColorFrom(belowRangeColor: RGBAColor): boolean;

/**
*
* @param hueRange
*/
setHueRange(hueRange: Range): boolean;

/**
*
* @param hueRange
*/
setHueRangeFrom(hueRange: Range): boolean;

/**
*
* @param nanColor
*/
setNanColor(nanColor: RGBAColor): boolean;

/**
*
* @param nanColor
*/
setNanColorFrom(nanColor: RGBAColor): boolean;

/**
*
* @param numberOfColors
*/
setNumberOfColors(numberOfColors: number): boolean;

/**
*
* @param saturationRange
*/
setSaturationRange(saturationRange: Range): boolean;

/**
*
* @param saturationRange
*/
setSaturationRangeFrom(saturationRange: Range): boolean;

/**
*
* @param table
*/
setTable(table: any): boolean;

/**
*
* @param useAboveRangeColor
*/
setUseAboveRangeColor(useAboveRangeColor: boolean): boolean;

/**
*
* @param useBelowRangeColor
*/
setUseBelowRangeColor(useBelowRangeColor: boolean): boolean;

/**
*
* @param valueRange
*/
setValueRange(valueRange: Range): boolean;

/**
*
* @param valueRange
*/
setValueRangeFrom(valueRange: Range): boolean;
}

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

/**
* Method used to create a new instance of vtkLookupTable
* @param {ILookupTableInitialValues} [initialValues] for pre-setting some of its content
*/
export function newInstance(
initialValues?: ILookupTableInitialValues
): vtkLookupTable;

/**
* vtkLookupTable is a 2D widget for manipulating a marker prop
*/
export declare const vtkLookupTable: {
newInstance: typeof newInstance;
extend: typeof extend;
};
export default vtkLookupTable;
index.js
import macro from 'vtk.js/Sources/macros';
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
import vtkScalarsToColors from 'vtk.js/Sources/Common/Core/ScalarsToColors';
import { ScalarMappingTarget } from 'vtk.js/Sources/Common/Core/ScalarsToColors/Constants';

import { VtkDataTypes } from 'vtk.js/Sources/Common/Core/DataArray/Constants';

const { vtkErrorMacro } = macro;

// ----------------------------------------------------------------------------
// Global methods
// ----------------------------------------------------------------------------

// Add module-level functions or api that you want to expose statically via
// the next section...

// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------

const BELOW_RANGE_COLOR_INDEX = 0;
const ABOVE_RANGE_COLOR_INDEX = 1;
const NAN_COLOR_INDEX = 2;

// ----------------------------------------------------------------------------
// vtkMyClass methods
// ----------------------------------------------------------------------------

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

//----------------------------------------------------------------------------
// Description:
// Return true if all of the values defining the mapping have an opacity
// equal to 1. Default implementation return true.
publicAPI.isOpaque = () => {
if (model.opaqueFlagBuildTime.getMTime() < publicAPI.getMTime()) {
let opaque = true;
if (model.nanColor[3] < 1.0) {
opaque = 0;
}
if (model.useBelowRangeColor && model.belowRangeColor[3] < 1.0) {
opaque = 0;
}
if (model.useAboveRangeColor && model.aboveRangeColor[3] < 1.0) {
opaque = 0;
}
for (let i = 3; i < model.table.length && opaque; i += 4) {
if (model.table[i] < 255) {
opaque = false;
}
}
model.opaqueFlag = opaque;
model.opaqueFlagBuildTime.modified();
}

return model.opaqueFlag;
};

publicAPI.usingLogScale = () => false;

//----------------------------------------------------------------------------
// Don't count special colors (min, max, NaN) as available colors
publicAPI.getNumberOfAvailableColors = () => model.table.length / 4 - 3;

//----------------------------------------------------------------------------
// Apply shift/scale to the scalar value v and return the index.
publicAPI.linearIndexLookup = (v, p) => {
let dIndex = 0;
const nv = Number(v);

if (nv < p.range[0]) {
dIndex = p.maxIndex + BELOW_RANGE_COLOR_INDEX + 1.5;
} else if (nv > p.range[1]) {
dIndex = p.maxIndex + ABOVE_RANGE_COLOR_INDEX + 1.5;
} else {
dIndex = (nv + p.shift) * p.scale;

// This conditional is needed because when v is very close to
// p.Range[1], it may map above p.MaxIndex in the linear mapping
// above.
dIndex = dIndex < p.maxIndex ? dIndex : p.maxIndex;
}

return Math.floor(dIndex);
};

publicAPI.linearLookup = (v, table, p) => {
let index = 0;
if (vtkMath.isNan(v)) {
index = Math.floor(p.maxIndex + 1.5 + NAN_COLOR_INDEX);
} else {
index = publicAPI.linearIndexLookup(v, p);
}
const offset = 4 * index;
return table.slice(offset, offset + 4);
};

publicAPI.indexedLookupFunction = (v, table, p) => {
let index = publicAPI.getAnnotatedValueIndexInternal(v);
if (index === -1) {
index = model.numberOfColors + NAN_COLOR_INDEX;
}
const offset = 4 * index;
return [
table[offset],
table[offset + 1],
table[offset + 2],
table[offset + 3],
];
};

//----------------------------------------------------------------------------
publicAPI.lookupShiftAndScale = (range, p) => {
p.shift = -range[0];
p.scale = Number.MAX_VALUE;
if (range[1] > range[0]) {
p.scale = (p.maxIndex + 1) / (range[1] - range[0]);
}
};

// Public API methods
publicAPI.mapScalarsThroughTable = (
input,
output,
outFormat,
inputOffset
) => {
let lookupFunc = publicAPI.linearLookup;
if (model.indexedLookup) {
lookupFunc = publicAPI.indexedLookupFunction;
}

const trange = publicAPI.getMappingRange();

const p = {
maxIndex: publicAPI.getNumberOfColors() - 1,
range: trange,
shift: 0.0,
scale: 0.0,
};
publicAPI.lookupShiftAndScale(trange, p);

const alpha = publicAPI.getAlpha();
const length = input.getNumberOfTuples();
const inIncr = input.getNumberOfComponents();

const outputV = output.getData();
const inputV = input.getData();

if (alpha >= 1.0) {
if (outFormat === ScalarMappingTarget.RGBA) {
for (let i = 0; i < length; i++) {
const cptr = lookupFunc(
inputV[i * inIncr + inputOffset],
model.table,
p
);
outputV[i * 4] = cptr[0];
outputV[i * 4 + 1] = cptr[1];
outputV[i * 4 + 2] = cptr[2];
outputV[i * 4 + 3] = cptr[3];
}
}
} else {
/* eslint-disable no-lonely-if */
if (outFormat === ScalarMappingTarget.RGBA) {
for (let i = 0; i < length; i++) {
const cptr = lookupFunc(
inputV[i * inIncr + inputOffset],
model.table,
p
);
outputV[i * 4] = cptr[0];
outputV[i * 4 + 1] = cptr[1];
outputV[i * 4 + 2] = cptr[2];
outputV[i * 4 + 3] = Math.floor(cptr[3] * alpha + 0.5);
}
}
} // alpha blending
};

publicAPI.forceBuild = () => {
let hinc = 0.0;
let sinc = 0.0;
let vinc = 0.0;
let ainc = 0.0;

const maxIndex = model.numberOfColors - 1;

if (maxIndex) {
hinc = (model.hueRange[1] - model.hueRange[0]) / maxIndex;
sinc = (model.saturationRange[1] - model.saturationRange[0]) / maxIndex;
vinc = (model.valueRange[1] - model.valueRange[0]) / maxIndex;
ainc = (model.alphaRange[1] - model.alphaRange[0]) / maxIndex;
}

model.table.length = 4 * maxIndex + 16;

const hsv = [];
const rgba = [];
for (let i = 0; i <= maxIndex; i++) {
hsv[0] = model.hueRange[0] + i * hinc;
hsv[1] = model.saturationRange[0] + i * sinc;
hsv[2] = model.valueRange[0] + i * vinc;

vtkMath.hsv2rgb(hsv, rgba);
rgba[3] = model.alphaRange[0] + i * ainc;

// case VTK_RAMP_LINEAR:
model.table[i * 4] = rgba[0] * 255.0 + 0.5;
model.table[i * 4 + 1] = rgba[1] * 255.0 + 0.5;
model.table[i * 4 + 2] = rgba[2] * 255.0 + 0.5;
model.table[i * 4 + 3] = rgba[3] * 255.0 + 0.5;
}

publicAPI.buildSpecialColors();

model.buildTime.modified();
};

publicAPI.setTable = (table) => {
// Handle JS array (assume 2D array)
if (Array.isArray(table)) {
const nbComponents = table[0].length;
model.numberOfColors = table.length;
const colorOffset = 4 - nbComponents;
let offset = 0;
// fill table
for (let i = 0; i < model.numberOfColors; i++) {
model.table[i * 4] = 255;
model.table[i * 4 + 1] = 255;
model.table[i * 4 + 2] = 255;
model.table[i * 4 + 3] = 255;
}
// extract colors
for (let i = 0; i < table.length; i++) {
const color = table[i];
for (let j = 0; j < nbComponents; j++) {
model.table[offset++] = color[j];
}
offset += colorOffset;
}
publicAPI.buildSpecialColors();
model.insertTime.modified();
publicAPI.modified();
return true;
}

if (table.getNumberOfComponents() !== 4) {
vtkErrorMacro('Expected 4 components for RGBA colors');
return false;
}
if (table.getDataType() !== VtkDataTypes.UNSIGNED_CHAR) {
vtkErrorMacro('Expected unsigned char values for RGBA colors');
return false;
}
model.numberOfColors = table.getNumberOfTuples();
const data = table.getData();
model.table.length = data.length;
for (let i = 0; i < data.length; i++) {
model.table[i] = data[i];
}

publicAPI.buildSpecialColors();
model.insertTime.modified();
publicAPI.modified();
return true;
};

publicAPI.buildSpecialColors = () => {
// Add "special" colors (NaN, below range, above range) to table here.
const { numberOfColors } = model;

const tptr = model.table;
let base = (numberOfColors + BELOW_RANGE_COLOR_INDEX) * 4;

// Below range color
if (model.useBelowRangeColor || numberOfColors === 0) {
tptr[base] = model.belowRangeColor[0] * 255.0 + 0.5;
tptr[base + 1] = model.belowRangeColor[1] * 255.0 + 0.5;
tptr[base + 2] = model.belowRangeColor[2] * 255.0 + 0.5;
tptr[base + 3] = model.belowRangeColor[3] * 255.0 + 0.5;
} else {
// Duplicate the first color in the table.
tptr[base] = tptr[0];
tptr[base + 1] = tptr[1];
tptr[base + 2] = tptr[2];
tptr[base + 3] = tptr[3];
}

// Above range color
base = (numberOfColors + ABOVE_RANGE_COLOR_INDEX) * 4;
if (model.useAboveRangeColor || numberOfColors === 0) {
tptr[base] = model.aboveRangeColor[0] * 255.0 + 0.5;
tptr[base + 1] = model.aboveRangeColor[1] * 255.0 + 0.5;
tptr[base + 2] = model.aboveRangeColor[2] * 255.0 + 0.5;
tptr[base + 3] = model.aboveRangeColor[3] * 255.0 + 0.5;
} else {
// Duplicate the last color in the table.
tptr[base] = tptr[4 * (numberOfColors - 1) + 0];
tptr[base + 1] = tptr[4 * (numberOfColors - 1) + 1];
tptr[base + 2] = tptr[4 * (numberOfColors - 1) + 2];
tptr[base + 3] = tptr[4 * (numberOfColors - 1) + 3];
}

// Always use NanColor
base = (numberOfColors + NAN_COLOR_INDEX) * 4;
tptr[base] = model.nanColor[0] * 255.0 + 0.5;
tptr[base + 1] = model.nanColor[1] * 255.0 + 0.5;
tptr[base + 2] = model.nanColor[2] * 255.0 + 0.5;
tptr[base + 3] = model.nanColor[3] * 255.0 + 0.5;
};

publicAPI.build = () => {
if (
model.table.length < 1 ||
(publicAPI.getMTime() > model.buildTime.getMTime() &&
model.insertTime.getMTime() <= model.buildTime.getMTime())
) {
publicAPI.forceBuild();
}
};

if (model.table.length > 0) {
// Ensure that special colors are properly included in the table
publicAPI.buildSpecialColors();

// ensure insertTime is more recently modified than buildTime if
// a table is provided via the constructor
model.insertTime.modified();
}
}

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

const DEFAULT_VALUES = {
numberOfColors: 256,
// table: null,

hueRange: [0.0, 0.66667],
saturationRange: [1.0, 1.0],
valueRange: [1.0, 1.0],
alphaRange: [1.0, 1.0],

nanColor: [0.5, 0.0, 0.0, 1.0],
belowRangeColor: [0.0, 0.0, 0.0, 1.0],
aboveRangeColor: [1.0, 1.0, 1.0, 1.0],
useAboveRangeColor: false,
useBelowRangeColor: false,

alpha: 1.0,
// buildTime: null,
// opaqueFlagBuildTime: null,
// insertTime: null,
};

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

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

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

// Internal objects initialization
if (!model.table) {
model.table = [];
}

model.buildTime = {};
macro.obj(model.buildTime);

model.opaqueFlagBuildTime = {};
macro.obj(model.opaqueFlagBuildTime, { mtime: 0 });

model.insertTime = {};
macro.obj(model.insertTime, { mtime: 0 });

// Create get-only macros
macro.get(publicAPI, model, ['buildTime']);

// Create get-set macros
macro.setGet(publicAPI, model, [
'numberOfColors',
'useAboveRangeColor',
'useBelowRangeColor',
]);

// Create set macros for array (needs to know size)
macro.setArray(
publicAPI,
model,
['alphaRange', 'hueRange', 'saturationRange', 'valueRange'],
2
);

macro.setArray(
publicAPI,
model,
['nanColor', 'belowRangeColor', 'aboveRangeColor'],
4
);

// Create get macros for array
macro.getArray(publicAPI, model, [
'hueRange',
'saturationRange',
'valueRange',
'alphaRange',
'nanColor',
'belowRangeColor',
'aboveRangeColor',
]);

// For more macro methods, see "Sources/macros.js"

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

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

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

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

export default { newInstance, extend };