ScalarsToColors

Introduction

vtkScalarsToColors is a general-purpose base class for objects that convert
scalars to colors. This include vtkLookupTable classes and color transfer
functions. By itself, this class will simply rescale the scalars.

The scalar-to-color mapping can be augmented with an additional uniform alpha
blend. This is used, for example, to blend a vtkActor’s opacity with the
lookup table values.

Specific scalar values may be annotated with text strings that will be
included in color legends using setAnnotations, setAnnotation,
getNumberOfAnnotatedValues, getAnnotatedValue, getAnnotation,
removeAnnotation, and resetAnnotations.

This class also has a method for indicating that the set of annotated values
form a categorical color map; by setting IndexedLookup to true, you indicate
that the annotated values are the only valid values for which entries in the
color table should be returned. In this mode, subclasses should then assign
colors to annotated values by taking the modulus of an annotated value’s
index in the list of annotations with the number of colors in the table.

Methods

areScalarsOpaque

Returns false if scalars are Uint8 LA or RGBA with A < 255,
otherwise rely on getAlpha() in case of direct mapping,
otherwise return isOpaque()

Argument Type Required Description
scalars vtkDataArray Yes
colorMode ColorMode Yes
componentIn Number Yes

build

Perform any processing required (if any) before processing scalars.

checkForAnnotatedValue

Argument Type Required Description
value Yes

convertToRGBA

Argument Type Required Description
colors Yes
numComp Yes
numTuples Yes

extend

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

getAlpha

Specify an additional opacity (alpha) value to blend with.

getAnnotatedValue

Argument Type Required Description
idx Number Yes

getAnnotatedValueIndex

Argument Type Required Description
val Yes

getAnnotatedValueIndexInternal

An unsafe version of vtkScalarsToColors.checkForAnnotatedValue for
internal use (no pointer checks performed)

Argument Type Required Description
value Yes

getAnnotation

Argument Type Required Description
idx Number Yes

getAnnotationColor

Argument Type Required Description
val Yes
rgba Yes

getIndexedColor

Argument Type Required Description
val Yes
rgba Yes

getIndexedLookup

getMappingRange

getMappingRangeByReference

getNumberOfAnnotatedValues

Return the annotated value at a particular index in the list of annotations.

getNumberOfAvailableColors

Get the number of available colors for mapping to.

getRange

getVectorComponent

Get which component of a vector to map to colors.

getVectorMode

getVectorSize

isOpaque

luminanceAlphaToRGBA

Argument Type Required Description
newColors Yes
colors Yes
alpha Number Yes
convtFun Yes

luminanceToRGBA

Argument Type Required Description
newColors Yes
colors Yes
alpha Number Yes
convtFun Yes

mapScalars

Internal methods that map a data array into a 4-component, unsigned char
RGBA array. The color mode determines the behavior of mapping. If
ColorMode.DEFAULT is set, then unsigned char data arrays are treated as
colors (and converted to RGBA if necessary); If ColorMode.DIRECT_SCALARS
is set, then all arrays are treated as colors (integer types are clamped
in the range 0-255, floating point arrays are clamped in the range
0.0-1.0. Note ‘char’ does not have enough values to represent a color so
mapping this type is considered an error); otherwise, the data is mapped
through this instance of ScalarsToColors. The component argument is used
for data arrays with more than one component; it indicates which
component to use to do the blending. When the component argument is -1,
then the this object uses its own selected technique to change a vector
into a scalar to map.

Argument Type Required Description
scalars Yes
colorMode ColorMode Yes
componentIn Number Yes

mapVectorsThroughTable

Map a set of vector values through the table

Argument Type Required Description
input Yes
output Yes
outputFormat ScalarMappingTarget Yes
vectorComponentIn Yes
vectorSizeIn Number Yes

mapVectorsToMagnitude

Argument Type Required Description
input Yes
output Yes
compsToUse Number Yes

newInstance

Method used to create a new instance of vtkScalarsToColors

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

rGBAToRGBA

Argument Type Required Description
newColors Yes
colors Yes
alpha Number Yes
convtFun Yes

rGBToRGBA

Argument Type Required Description
newColors Yes
colors Yes
alpha Number Yes
convtFun Yes

removeAnnotation

Remove an existing entry from the list of annotated values.

Argument Type Required Description
value Yes

resetAnnotations

Remove all existing values and their annotations.

setAlpha

Argument Type Required Description
alpha Number Yes

setAnnotation

Argument Type Required Description
value Yes
annotation Yes

setAnnotations

Argument Type Required Description
values Yes
annotations Yes

setIndexedLookup

Argument Type Required Description
indexedLookup Boolean Yes

setMappingRange

Argument Type Required Description
min Number Yes
max Number Yes

setMappingRange

Argument Type Required Description
mappingRange Range Yes

setMappingRangeFrom

Argument Type Required Description
mappingRange Range Yes

setRange

Argument Type Required Description
min Number Yes
max Number Yes

setVectorComponent

If the mapper does not select which component of a vector to map to
colors, you can specify it here.

Argument Type Required Description
vectorComponent Number Yes The value of the vector mode.

setVectorMode

Change mode that maps vectors by magnitude vs. component. If the mode is
“RGBColors”, then the vectors components are scaled to the range and
passed directly as the colors.

Argument Type Required Description
vectorMode VectorMode Yes The value of the vector mode.

setVectorModeToComponent

Set vectorMode to VectorMode.COMPONENT

setVectorModeToMagnitude

Set vectorMode to VectorMode.MAGNITUDE

setVectorModeToRGBColors

When mapping vectors, consider only the number of components selected by
vectorSize to be part of the vector, and ignore any other components. Set
to -1 to map all components. If this is not set to -1, then you can use
setVectorComponent to set which scalar component will be the first
component in the vector to be mapped.

setVectorSize

When mapping vectors, consider only the number of components selected by
VectorSize to be part of the vector, and ignore any other components.

Argument Type Required Description
vectorSize Number Yes The value of the vectorSize.

updateAnnotatedValueMap

Update the map from annotated values to indices in the array of annotations.

usingLogScale

Source

Constants.d.ts
export declare enum VectorMode {
MAGNITUDE = 0,
COMPONENT = 1,
RGBCOLORS = 2,
}

export declare enum ScalarMappingTarget {
LUMINANCE = 1,
LUMINANCE_ALPHA = 2,
RGB = 3,
RGBA = 4,
}

declare const _default: {
VectorMode: typeof VectorMode;
ScalarMappingTarget: typeof ScalarMappingTarget;
};
export default _default;
Constants.js
export const VectorMode = {
MAGNITUDE: 0,
COMPONENT: 1,
RGBCOLORS: 2,
};

export const ScalarMappingTarget = {
LUMINANCE: 1,
LUMINANCE_ALPHA: 2,
RGB: 3,
RGBA: 4,
};

export default {
VectorMode,
ScalarMappingTarget,
};
index.d.ts
import { vtkObject } from "../../../interfaces";
import { ColorMode } from "../../../Rendering/Core/Mapper/Constants";
import { Range } from "../../../types";
import vtkDataArray from "../DataArray";
import { ScalarMappingTarget, VectorMode } from "./Constants";

/**
*
*/
export interface IScalarsToColorsInitialValues {
alpha?: number;
vectorComponent?: number;
vectorSize?: number;
indexedLookup?: boolean;
}

export interface vtkScalarsToColors extends vtkObject {

/**
* Perform any processing required (if any) before processing scalars.
*/
build(): void;

/**
*
* @param value
*/
checkForAnnotatedValue(value: any): number;

/**
*
* @param colors
* @param numComp
* @param numTuples
*/
convertToRGBA(colors: any, numComp: number, numTuples: number): void;

/**
* Specify an additional opacity (alpha) value to blend with.
*/
getAlpha(): number;

/**
*
* @param {Number} idx
*/
getAnnotatedValue(idx: number): void;

/**
*
* @param val
*/
getAnnotatedValueIndex(val: any): number;

/**
* An unsafe version of vtkScalarsToColors.checkForAnnotatedValue for
* internal use (no pointer checks performed)
* @param value
*/
getAnnotatedValueIndexInternal(value: any): number;

/**
*
* @param {Number} idx
*/
getAnnotation(idx: number): string;

/**
*
* @param val
* @param rgba
*/
getAnnotationColor(val: any, rgba: any): void;

/**
*
* @param val
* @param rgba
*/
getIndexedColor(val: number, rgba: any): void;

/**
*
*/
getIndexedLookup(): boolean;

/**
*
*/
getMappingRange(): Range;

/**
*
*/
getMappingRangeByReference(): Range;

/**
* Return the annotated value at a particular index in the list of annotations.
*/
getNumberOfAnnotatedValues(): number;

/**
* Get the number of available colors for mapping to.
*/
getNumberOfAvailableColors(): number;

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

/**
* Get which component of a vector to map to colors.
*/
getVectorComponent(): number;

/**
*
*/
getVectorMode(): VectorMode;

/**
*
*/
getVectorSize(): number;

/**
* @see areScalarsOpaque
*/
isOpaque(): boolean;

/**
* Returns false if scalars are Uint8 LA or RGBA with A < 255,
* otherwise rely on getAlpha() in case of direct mapping,
* otherwise return isOpaque()
*
* @see isOpaque, getAlpha
*
* @param {vtkDataArray} scalars
* @param {ColorMode} colorMode
* @param {Number} componentIn
*
*/
areScalarsOpaque(scalars: vtkDataArray, colorMode: ColorMode, componentIn: number): boolean;

/**
*
* @param newColors
* @param colors
* @param {Number} alpha
* @param convtFun
*/
luminanceAlphaToRGBA(newColors: any, colors: any, alpha: number, convtFun: any): void;

/**
*
* @param newColors
* @param colors
* @param {Number} alpha
* @param convtFun
*/
luminanceToRGBA(newColors: any, colors: any, alpha: number, convtFun: any): void;

/**
* Internal methods that map a data array into a 4-component, unsigned char
* RGBA array. The color mode determines the behavior of mapping. If
* ColorMode.DEFAULT is set, then unsigned char data arrays are treated as
* colors (and converted to RGBA if necessary); If ColorMode.DIRECT_SCALARS
* is set, then all arrays are treated as colors (integer types are clamped
* in the range 0-255, floating point arrays are clamped in the range
* 0.0-1.0. Note 'char' does not have enough values to represent a color so
* mapping this type is considered an error); otherwise, the data is mapped
* through this instance of ScalarsToColors. The component argument is used
* for data arrays with more than one component; it indicates which
* component to use to do the blending. When the component argument is -1,
* then the this object uses its own selected technique to change a vector
* into a scalar to map.
* @param scalars
* @param {ColorMode} colorMode
* @param {Number} componentIn
*/
mapScalars(scalars: any, colorMode: ColorMode, componentIn: number): void;

/**
* Map a set of vector values through the table
* @param input
* @param output
* @param {ScalarMappingTarget} outputFormat
* @param vectorComponentIn
* @param {Number} vectorSizeIn
*/
mapVectorsThroughTable(input: any, output: any, outputFormat: ScalarMappingTarget, vectorComponentIn: number, vectorSizeIn: number): void;

/**
*
* @param input
* @param output
* @param {Number} compsToUse
*/
mapVectorsToMagnitude(input: any, output: any, compsToUse: number): void;

/**
*
* @param newColors
* @param colors
* @param {Number} alpha
* @param convtFun
*/
rGBAToRGBA(newColors: any, colors: any, alpha: number, convtFun: any): void;

/**
*
* @param newColors
* @param colors
* @param {Number} alpha
* @param convtFun
*/
rGBToRGBA(newColors: any, colors: any, alpha: number, convtFun: any): void;

/**
* Remove an existing entry from the list of annotated values.
* @param value
*/
removeAnnotation(value: any): boolean;

/**
* Remove all existing values and their annotations.
*/
resetAnnotations(): void;

/**
*
* @param {Number} alpha
*/
setAlpha(alpha: number): boolean;

/**
*
* @param value
* @param annotation
*/
setAnnotation(value: any, annotation: any): number;

/**
*
* @param values
* @param annotations
*/
setAnnotations(values: any, annotations: any): void;

/**
*
* @param {Boolean} indexedLookup
*/
setIndexedLookup(indexedLookup: boolean): boolean;

/**
*
* @param {Range} mappingRange
*/
setMappingRange(mappingRange: Range): boolean;

/**
*
* @param {Number} min
* @param {Number} max
*/
setMappingRange(min: number, max: number): boolean;

/**
*
* @param {Range} mappingRange
*/
setMappingRangeFrom(mappingRange: Range): boolean;

/**
*
* @param {Number} min
* @param {Number} max
*/
setRange(min: number, max: number): boolean;

/**
* If the mapper does not select which component of a vector to map to
* colors, you can specify it here.
* @param {Number} vectorComponent The value of the vector mode.
*/
setVectorComponent(vectorComponent: number): boolean;

/**
* Change mode that maps vectors by magnitude vs. component. If the mode is
* "RGBColors", then the vectors components are scaled to the range and
* passed directly as the colors.
* @param {VectorMode} vectorMode The value of the vector mode.
*/
setVectorMode(vectorMode: VectorMode): boolean;

/**
* Set vectorMode to `VectorMode.MAGNITUDE`
*/
setVectorModeToMagnitude(): boolean;

/**
* Set vectorMode to `VectorMode.COMPONENT`
*/
setVectorModeToComponent(): boolean;

/**
* When mapping vectors, consider only the number of components selected by
* `vectorSize` to be part of the vector, and ignore any other components. Set
* to -1 to map all components. If this is not set to -1, then you can use
* `setVectorComponent` to set which scalar component will be the first
* component in the vector to be mapped.
*/
setVectorModeToRGBColors(): boolean;

/**
* When mapping vectors, consider only the number of components selected by
* VectorSize to be part of the vector, and ignore any other components.
* @param {Number} vectorSize The value of the vectorSize.
*/
setVectorSize(vectorSize: number): boolean;

/**
* Update the map from annotated values to indices in the array of annotations.
*/
updateAnnotatedValueMap(): boolean;

/**
*
*/
usingLogScale(): boolean;
}

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

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

/**
* vtkScalarsToColors is a general-purpose base class for objects that convert
* scalars to colors. This include vtkLookupTable classes and color transfer
* functions. By itself, this class will simply rescale the scalars.
*
* The scalar-to-color mapping can be augmented with an additional uniform alpha
* blend. This is used, for example, to blend a vtkActor's opacity with the
* lookup table values.
*
* Specific scalar values may be annotated with text strings that will be
* included in color legends using `setAnnotations`, `setAnnotation`,
* `getNumberOfAnnotatedValues`, `getAnnotatedValue`, `getAnnotation`,
* `removeAnnotation`, and `resetAnnotations`.
*
* This class also has a method for indicating that the set of annotated values
* form a categorical color map; by setting IndexedLookup to true, you indicate
* that the annotated values are the only valid values for which entries in the
* color table should be returned. In this mode, subclasses should then assign
* colors to annotated values by taking the modulus of an annotated value's
* index in the list of annotations with the number of colors in the table.
*/
export declare const vtkScalarsToColors: {
newInstance: typeof newInstance;
extend: typeof extend;
VectorMode: typeof VectorMode;
ScalarMappingTarget: typeof VectorMode;
}
export default vtkScalarsToColors;
index.js
import macro from 'vtk.js/Sources/macros';
import vtkDataArray from 'vtk.js/Sources/Common/Core/DataArray';
import Constants from 'vtk.js/Sources/Common/Core/ScalarsToColors/Constants';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper/Constants'; // Need to go inside Constants otherwise dependency loop

const { ScalarMappingTarget, VectorMode } = Constants;
const { VtkDataTypes } = vtkDataArray;
const { ColorMode } = vtkMapper;
const { vtkErrorMacro } = macro;

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

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

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

function intColorToUChar(c) {
return c;
}
function floatColorToUChar(c) {
return Math.floor(c * 255.0 + 0.5);
}

// ----------------------------------------------------------------------------
// vtkScalarsToColors methods
// ----------------------------------------------------------------------------

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

publicAPI.setVectorModeToMagnitude = () =>
publicAPI.setVectorMode(VectorMode.MAGNITUDE);
publicAPI.setVectorModeToComponent = () =>
publicAPI.setVectorMode(VectorMode.COMPONENT);
publicAPI.setVectorModeToRGBColors = () =>
publicAPI.setVectorMode(VectorMode.RGBCOLORS);

publicAPI.build = () => {};

publicAPI.isOpaque = () => true;

//----------------------------------------------------------------------------
publicAPI.setAnnotations = (values, annotations) => {
if ((values && !annotations) || (!values && annotations)) {
return;
}

if (values && annotations && values.length !== annotations.length) {
vtkErrorMacro(
'Values and annotations do not have the same number of tuples so ignoring'
);
return;
}

model.annotationArray = [];

if (annotations && values) {
const num = annotations.length;
for (let i = 0; i < num; i++) {
model.annotationArray.push({
value: values[i],
annotation: String(annotations[i]),
});
}
}

publicAPI.updateAnnotatedValueMap();
publicAPI.modified();
};

//----------------------------------------------------------------------------
publicAPI.setAnnotation = (value, annotation) => {
let i = publicAPI.checkForAnnotatedValue(value);
let modified = false;
if (i >= 0) {
if (model.annotationArray[i].annotation !== annotation) {
model.annotationArray[i].annotation = annotation;
modified = true;
}
} else {
model.annotationArray.push({ value, annotation });
i = model.annotationArray.length - 1;
modified = true;
}
if (modified) {
publicAPI.updateAnnotatedValueMap();
publicAPI.modified();
}
return i;
};

//----------------------------------------------------------------------------
publicAPI.getNumberOfAnnotatedValues = () => model.annotationArray.length;

//----------------------------------------------------------------------------
publicAPI.getAnnotatedValue = (idx) => {
if (idx < 0 || idx >= model.annotationArray.length) {
return null;
}
return model.annotationArray[idx].value;
};

//----------------------------------------------------------------------------
publicAPI.getAnnotation = (idx) => {
if (model.annotationArray[idx] === undefined) {
return null;
}
return model.annotationArray[idx].annotation;
};

//----------------------------------------------------------------------------
publicAPI.getAnnotatedValueIndex = (val) =>
model.annotationArray.length ? publicAPI.checkForAnnotatedValue(val) : -1;

//----------------------------------------------------------------------------
publicAPI.removeAnnotation = (value) => {
const i = publicAPI.checkForAnnotatedValue(value);
const needToRemove = i >= 0;
if (needToRemove) {
model.annotationArray.splice(i, 1);
publicAPI.updateAnnotatedValueMap();
publicAPI.modified();
}
return needToRemove;
};

//----------------------------------------------------------------------------
publicAPI.resetAnnotations = () => {
model.annotationArray = [];
model.annotatedValueMap = [];
publicAPI.modified();
};

//----------------------------------------------------------------------------
publicAPI.getAnnotationColor = (val, rgba) => {
if (model.indexedLookup) {
const i = publicAPI.getAnnotatedValueIndex(val);
publicAPI.getIndexedColor(i, rgba);
} else {
publicAPI.getColor(parseFloat(val), rgba);
rgba[3] = 1.0;
}
};

//----------------------------------------------------------------------------
publicAPI.checkForAnnotatedValue = (value) =>
publicAPI.getAnnotatedValueIndexInternal(value);

//----------------------------------------------------------------------------
// An unsafe version of vtkScalarsToColors::CheckForAnnotatedValue for
// internal use (no pointer checks performed)
publicAPI.getAnnotatedValueIndexInternal = (value) => {
if (model.annotatedValueMap[value] !== undefined) {
const na = model.annotationArray.length;
return model.annotatedValueMap[value] % na;
}
// Treat as a NaN
return -1;
};

//----------------------------------------------------------------------------
publicAPI.getIndexedColor = (val, rgba) => {
rgba[0] = 0.0;
rgba[1] = 0.0;
rgba[2] = 0.0;
rgba[3] = 0.0;
};

//----------------------------------------------------------------------------
publicAPI.updateAnnotatedValueMap = () => {
model.annotatedValueMap = [];

const na = model.annotationArray.length;
for (let i = 0; i < na; i++) {
model.annotatedValueMap[model.annotationArray[i].value] = i;
}
};

// Description:
// Internal methods that map a data array into a 4-component,
// unsigned char RGBA array. The color mode determines the behavior
// of mapping. If ColorMode.DEFAULT is set, then unsigned char
// data arrays are treated as colors (and converted to RGBA if
// necessary); If ColorMode.DIRECT_SCALARS is set, then all arrays
// are treated as colors (integer types are clamped in the range 0-255,
// floating point arrays are clamped in the range 0.0-1.0. Note 'char' does
// not have enough values to represent a color so mapping this type is
// considered an error);
// otherwise, the data is mapped through this instance
// of ScalarsToColors. The component argument is used for data
// arrays with more than one component; it indicates which component
// to use to do the blending. When the component argument is -1,
// then the this object uses its own selected technique to change a
// vector into a scalar to map.
publicAPI.mapScalars = (scalars, colorMode, componentIn) => {
const numberOfComponents = scalars.getNumberOfComponents();

let newColors = null;

// map scalars through lookup table only if needed
if (
(colorMode === ColorMode.DEFAULT &&
scalars.getDataType() === VtkDataTypes.UNSIGNED_CHAR) ||
(colorMode === ColorMode.DIRECT_SCALARS && scalars)
) {
newColors = publicAPI.convertToRGBA(
scalars,
numberOfComponents,
scalars.getNumberOfTuples()
);
} else {
const newscalars = {
type: 'vtkDataArray',
name: 'temp',
numberOfComponents: 4,
dataType: VtkDataTypes.UNSIGNED_CHAR,
};

const s = macro.newTypedArray(
newscalars.dataType,
4 * scalars.getNumberOfTuples()
);
newscalars.values = s;
newscalars.size = s.length;
newColors = vtkDataArray.newInstance(newscalars);

let component = componentIn;

// If mapper did not specify a component, use the VectorMode
if (component < 0 && numberOfComponents > 1) {
publicAPI.mapVectorsThroughTable(
scalars,
newColors,
ScalarMappingTarget.RGBA,
-1,
-1
);
} else {
if (component < 0) {
component = 0;
}
if (component >= numberOfComponents) {
component = numberOfComponents - 1;
}

// Map the scalars to colors
publicAPI.mapScalarsThroughTable(
scalars,
newColors,
ScalarMappingTarget.RGBA,
component
);
}
}

return newColors;
};

publicAPI.mapVectorsToMagnitude = (input, output, compsToUse) => {
const length = input.getNumberOfTuples();
const inIncr = input.getNumberOfComponents();

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

for (let i = 0; i < length; i++) {
let sum = 0.0;
for (let j = 0; j < compsToUse; j++) {
sum += inputV[i * inIncr + j] * inputV[i * inIncr + j];
}
outputV[i] = Math.sqrt(sum);
}
};

//----------------------------------------------------------------------------
// Map a set of vector values through the table
publicAPI.mapVectorsThroughTable = (
input,
output,
outputFormat,
vectorComponentIn,
vectorSizeIn
) => {
let vectorMode = publicAPI.getVectorMode();
let vectorSize = vectorSizeIn;
let vectorComponent = vectorComponentIn;
const inComponents = input.getNumberOfComponents();

if (vectorMode === VectorMode.COMPONENT) {
// make sure vectorComponent is within allowed range
if (vectorComponent === -1) {
// if set to -1, use default value provided by table
vectorComponent = publicAPI.getVectorComponent();
}
if (vectorComponent < 0) {
vectorComponent = 0;
}
if (vectorComponent >= inComponents) {
vectorComponent = inComponents - 1;
}
} else {
// make sure vectorSize is within allowed range
if (vectorSize === -1) {
// if set to -1, use default value provided by table
vectorSize = publicAPI.getVectorSize();
}
if (vectorSize <= 0) {
vectorComponent = 0;
vectorSize = inComponents;
} else {
if (vectorComponent < 0) {
vectorComponent = 0;
}
if (vectorComponent >= inComponents) {
vectorComponent = inComponents - 1;
}
if (vectorComponent + vectorSize > inComponents) {
vectorSize = inComponents - vectorComponent;
}
}

if (
vectorMode === VectorMode.MAGNITUDE &&
(inComponents === 1 || vectorSize === 1)
) {
vectorMode = VectorMode.COMPONENT;
}
}

// increment input pointer to the first component to map
let inputOffset = 0;
if (vectorComponent > 0) {
inputOffset = vectorComponent;
}

// map according to the current vector mode
switch (vectorMode) {
case VectorMode.COMPONENT: {
publicAPI.mapScalarsThroughTable(
input,
output,
outputFormat,
inputOffset
);
break;
}

case VectorMode.RGBCOLORS: {
// publicAPI.mapColorsToColors(
// input, output, inComponents, vectorSize,
// outputFormat);
break;
}

// MAGNITUDE is considered default
case VectorMode.MAGNITUDE:
default: {
const magValues = vtkDataArray.newInstance({
numberOfComponents: 1,
values: new Float32Array(input.getNumberOfTuples()),
});

publicAPI.mapVectorsToMagnitude(input, magValues, vectorSize);
publicAPI.mapScalarsThroughTable(magValues, output, outputFormat, 0);
break;
}
}
};

publicAPI.luminanceToRGBA = (newColors, colors, alpha, convtFun) => {
const a = convtFun(alpha);

const values = colors.getData();
const newValues = newColors.getData();
const size = values.length;
const component = 0;
const tuple = 1;

let count = 0;
for (let i = component; i < size; i += tuple) {
const l = convtFun(values[i]);
newValues[count * 4] = l;
newValues[count * 4 + 1] = l;
newValues[count * 4 + 2] = l;
newValues[count * 4 + 3] = a;
count++;
}
};

publicAPI.luminanceAlphaToRGBA = (newColors, colors, alpha, convtFun) => {
const values = colors.getData();
const newValues = newColors.getData();
const size = values.length;
const component = 0;
const tuple = 2;

let count = 0;
for (let i = component; i < size; i += tuple) {
const l = convtFun(values[i]);
newValues[count] = l;
newValues[count + 1] = l;
newValues[count + 2] = l;
newValues[count + 3] = convtFun(values[i + 1]) * alpha;
count += 4;
}
};

publicAPI.rGBToRGBA = (newColors, colors, alpha, convtFun) => {
const a = floatColorToUChar(alpha);

const values = colors.getData();
const newValues = newColors.getData();
const size = values.length;
const component = 0;
const tuple = 3;

let count = 0;
for (let i = component; i < size; i += tuple) {
newValues[count * 4] = convtFun(values[i]);
newValues[count * 4 + 1] = convtFun(values[i + 1]);
newValues[count * 4 + 2] = convtFun(values[i + 2]);
newValues[count * 4 + 3] = a;
count++;
}
};

publicAPI.rGBAToRGBA = (newColors, colors, alpha, convtFun) => {
const values = colors.getData();
const newValues = newColors.getData();
const size = values.length;
const component = 0;
const tuple = 4;

let count = 0;
for (let i = component; i < size; i += tuple) {
newValues[count * 4] = convtFun(values[i]);
newValues[count * 4 + 1] = convtFun(values[i + 1]);
newValues[count * 4 + 2] = convtFun(values[i + 2]);
newValues[count * 4 + 3] = convtFun(values[i + 3]) * alpha;
count++;
}
};

//----------------------------------------------------------------------------
publicAPI.convertToRGBA = (colors, numComp, numTuples) => {
let { alpha } = model;
if (
numComp === 4 &&
alpha >= 1.0 &&
colors.getDataType() === VtkDataTypes.UNSIGNED_CHAR
) {
return colors;
}

const newColors = vtkDataArray.newInstance({
numberOfComponents: 4,
empty: true,
size: 4 * numTuples,
dataType: VtkDataTypes.UNSIGNED_CHAR,
});

if (numTuples <= 0) {
return newColors;
}

alpha = alpha > 0 ? alpha : 0;
alpha = alpha < 1 ? alpha : 1;

let convtFun = intColorToUChar;
if (
colors.getDataType() === VtkDataTypes.FLOAT ||
colors.getDataType() === VtkDataTypes.DOUBLE
) {
convtFun = floatColorToUChar;
}

switch (numComp) {
case 1:
publicAPI.luminanceToRGBA(newColors, colors, alpha, convtFun);
break;

case 2:
publicAPI.luminanceAlphaToRGBA(newColors, colors, convtFun);
break;

case 3:
publicAPI.rGBToRGBA(newColors, colors, alpha, convtFun);
break;

case 4:
publicAPI.rGBAToRGBA(newColors, colors, alpha, convtFun);
break;

default:
vtkErrorMacro('Cannot convert colors');
return null;
}

return newColors;
};

publicAPI.usingLogScale = () => false;

publicAPI.getNumberOfAvailableColors = () => 256 * 256 * 256;

publicAPI.setRange = (min, max) => publicAPI.setMappingRange(min, max);
publicAPI.getRange = () => publicAPI.getMappingRange();

publicAPI.areScalarsOpaque = (scalars, colorMode, componentIn) => {
if (!scalars) {
return publicAPI.isOpaque();
}

const numberOfComponents = scalars.getNumberOfComponents();

// map scalars through lookup table only if needed
if (
(colorMode === ColorMode.DEFAULT &&
scalars.getDataType() === VtkDataTypes.UNSIGNED_CHAR) ||
colorMode === ColorMode.DIRECT_SCALARS
) {
// we will be using the scalars directly, so look at the number of
// components and the range
if (numberOfComponents === 3 || numberOfComponents === 1) {
return model.alpha >= 1.0;
}
// otherwise look at the range of the alpha channel
const range = scalars.getRange(numberOfComponents - 1);
return range[0] === 255;
}

return true;
};
}

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

const DEFAULT_VALUES = {
alpha: 1.0,
vectorComponent: 0,
vectorSize: -1,
vectorMode: VectorMode.COMPONENT,
mappingRange: null,
annotationArray: null,
annotatedValueMap: null,
indexedLookup: false,
};

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

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

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

model.mappingRange = [0, 255];
model.annotationArray = [];
model.annotatedValueMap = [];

// Create get-set macros
macro.setGet(publicAPI, model, [
'vectorSize',
'vectorComponent',
'vectorMode',
'alpha',
'indexedLookup',
]);

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

// Create get macros for array
macro.getArray(publicAPI, model, ['mappingRange']);

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

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

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

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

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

export default { newInstance, extend, ...Constants };