DataArray

Usage

const data = {};
const dataArray = vtk(data);
alert(dataArray.getNumberOfValues());
alert(dataArray.getValue(10));

getNumberOfComponents(): Number

Return number of components in the array;

getNumberOfValues(): Number

getNumberOfComponents(): Number

getNumberOfTuples(): Number

getBounds(): Number

Get bounds of the array and its components.

getDataType(): String

Type of data in the array, one of:

  • CHAR: ‘Int8Array
  • SIGNED_CHAR: ‘Int8Array
  • UNSIGNED_CHAR: ‘Uint8Array
  • SHORT: ‘Int16Array
  • UNSIGNED_SHORT: ‘Uint16Array
  • INT: ‘Int32Array
  • UNSIGNED_INT: ‘Uint32Array
  • FLOAT: ‘Float32Array
  • DOUBLE: ‘Float64Array

setData(typedArray, numberOfComponents)

Sets values, size, and dataType from typedArray, triggers a dataChange. Number of components is an optional argument and defaults to 1.

Source

Constants.js
export const DataTypeByteSize = {
Int8Array: 1,
Uint8Array: 1,
Uint8ClampedArray: 1,
Int16Array: 2,
Uint16Array: 2,
Int32Array: 4,
Uint32Array: 4,
Float32Array: 4,
Float64Array: 8,
};

export const VtkDataTypes = {
VOID: '', // not sure to know what that should be
CHAR: 'Int8Array',
SIGNED_CHAR: 'Int8Array',
UNSIGNED_CHAR: 'Uint8Array',
SHORT: 'Int16Array',
UNSIGNED_SHORT: 'Uint16Array',
INT: 'Int32Array',
UNSIGNED_INT: 'Uint32Array',
FLOAT: 'Float32Array',
DOUBLE: 'Float64Array',
};

export const DefaultDataType = VtkDataTypes.FLOAT;

export default {
DefaultDataType,
DataTypeByteSize,
VtkDataTypes,
};
index.d.ts
import { VtkDataArray, VtkRange } from '../../../macro';

/**
* Output of the rangeHelper instance
*/
interface VtkStatisticInformation {
min: number;
max: number;
count: number;
sum: number;
mean: number;
}

/**
* Helper class used to compute data range of a set of numbers
*/
interface VtkRangeHelper {
add(value: number): void;
get(): VtkStatisticInformation;
getRange(): VtkRange;
}

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

/**
* Compute range of a given array. The array could be composed of tuples and
* individual component range could be computed as well as magnitude.
*
*
  • const array = [x0, y0, z0, x1, y1, z1, …, xn, yn, zn];
  • const { min: yMin, max: yMax } = computeRange(array, 1, 3);
  • const { min: minMagnitude, max: maxMagnitude } = computeRange(array, -1, 3);
  •  *
    * @param values Array to go through to extract the range from
    * @param component (default: 0) indice to use inside tuple size
    * @param numberOfComponents (default: 1) size of the tuple
    */
    export function computeRange(values: Array<number>, component?: number, numberOfComponents?: number): VtkRange;

    /**
    * Create helper object that can be used to gather min, max, count, sum of
    * a set of values.
    */
    export function createRangeHelper(): VtkRangeHelper

    /**
    * Return the name of a typed array
    *
    *
  • const isFloat32 = (‘Float32Array’ === getDataType(array));

  • const clone = new macro.TYPED_ARRAYSgetDataType(array);
  •  *
    * @param typedArray to extract its type from
    */
    export function getDataType(typedArray: any): string

    /**
    * Return the max norm of a given vtkDataArray
    *
    * @param dataArray to process
    */
    export function getMaxNorm(dataArray: VtkDataArray): number

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

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

    /**
    * Method use to create a new instance of vtkDataArray
    * @param initialValues for pre-setting some of its content
    */
    export function newInstance(initialValues?: object): VtkDataArray;

    /**
    * Constants capturing the number of bytes per element based on its data type.
    */
    export enum DataTypeByteSize {
    Int8Array,
    Uint8Array,
    Uint8ClampedArray,
    Int16Array,
    Uint16Array,
    Int32Array,
    Uint32Array,
    Float32Array,
    Float64Array,
    }

    /**
    * Constants capturing the various VTK data types.
    */
    export enum VtkDataTypes {
    VOID,
    CHAR,
    SIGNED_CHAR,
    UNSIGNED_CHAR,
    SHORT,
    UNSIGNED_SHORT,
    INT,
    UNSIGNED_INT,
    FLOAT,
    DOUBLE,
    }

    /**
    * Default vtkDataArray export
    */
    declare const vtkDataArray: {
    newInstance: typeof newInstance,
    extend: typeof extend,
    // static
    computeRange: typeof computeRange,
    createRangeHelper: typeof createRangeHelper,
    getDataType: typeof getDataType,
    getMaxNorm: typeof getMaxNorm,
    // constants
    DataTypeByteSize: typeof DataTypeByteSize,
    VtkDataTypes: typeof VtkDataTypes,
    DefaultDataType: VtkDataTypes,
    };

    export default vtkDataArray;
index.js
import Constants from 'vtk.js/Sources/Common/Core/DataArray/Constants';
import * as macro from 'vtk.js/Sources/macro';
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';

const { DefaultDataType } = Constants;
const TUPLE_HOLDER = [];

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

function createRangeHelper() {
let min = Number.MAX_VALUE;
let max = -Number.MAX_VALUE;
let count = 0;
let sum = 0;

return {
add(value) {
if (min > value) {
min = value;
}
if (max < value) {
max = value;
}
count++;
sum += value;
},
get() {
return { min, max, count, sum, mean: sum / count };
},
getRange() {
return { min, max };
},
};
}

function computeRange(values, component = 0, numberOfComponents = 1) {
const helper = createRangeHelper();
const size = values.length;
let value = 0;

if (component < 0 && numberOfComponents > 1) {
// Compute magnitude
for (let i = 0; i < size; i += numberOfComponents) {
value = 0;
for (let j = 0; j < numberOfComponents; j++) {
value += values[i + j] * values[i + j];
}
value **= 0.5;
helper.add(value);
}
return helper.getRange();
}

const offset = component < 0 ? 0 : component;
for (let i = offset; i < size; i += numberOfComponents) {
helper.add(values[i]);
}

return helper.getRange();
}

function ensureRangeSize(rangeArray, size = 0) {
const ranges = rangeArray || [];
// Pad ranges with null value to get the
while (ranges.length <= size) {
ranges.push(null);
}
return ranges;
}

function getDataType(typedArray) {
// Expects toString() to return "[object ...Array]"
return Object.prototype.toString.call(typedArray).slice(8, -1);
}

function getMaxNorm(normArray) {
const numComps = normArray.getNumberOfComponents();
let maxNorm = 0.0;
for (let i = 0; i < normArray.getNumberOfTuples(); ++i) {
const norm = vtkMath.norm(normArray.getTuple(i), numComps);
if (norm > maxNorm) {
maxNorm = norm;
}
}
return maxNorm;
}

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

export const STATIC = {
computeRange,
createRangeHelper,
getDataType,
getMaxNorm,
};

// ----------------------------------------------------------------------------
// vtkDataArray methods
// ----------------------------------------------------------------------------

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

function dataChange() {
model.ranges = null;
publicAPI.modified();
}

publicAPI.getElementComponentSize = () => model.values.BYTES_PER_ELEMENT;

// Description:
// Return the data component at the location specified by tupleIdx and
// compIdx.
publicAPI.getComponent = (tupleIdx, compIdx = 0) =>
model.values[tupleIdx * model.numberOfComponents + compIdx];

// Description:
// Set the data component at the location specified by tupleIdx and compIdx
// to value.
// Note that i is less than NumberOfTuples and j is less than
// NumberOfComponents. Make sure enough memory has been allocated
// (use SetNumberOfTuples() and SetNumberOfComponents()).
publicAPI.setComponent = (tupleIdx, compIdx, value) => {
if (value !== model.values[tupleIdx * model.numberOfComponents + compIdx]) {
model.values[tupleIdx * model.numberOfComponents + compIdx] = value;
dataChange();
}
};

publicAPI.getData = () => model.values;

publicAPI.getRange = (componentIndex = -1) => {
const rangeIdx =
componentIndex < 0 ? model.numberOfComponents : componentIndex;
let range = null;

if (!model.ranges) {
model.ranges = ensureRangeSize(model.ranges, model.numberOfComponents);
}
range = model.ranges[rangeIdx];

if (range) {
model.rangeTuple[0] = range.min;
model.rangeTuple[1] = range.max;
return model.rangeTuple;
}

// Need to compute ranges...
range = computeRange(
model.values,
componentIndex,
model.numberOfComponents
);
model.ranges[rangeIdx] = range;
model.rangeTuple[0] = range.min;
model.rangeTuple[1] = range.max;
return model.rangeTuple;
};

publicAPI.setRange = (rangeValue, componentIndex) => {
if (!model.ranges) {
model.ranges = ensureRangeSize(model.ranges, model.numberOfComponents);
}
const range = { min: rangeValue.min, max: rangeValue.max };

model.ranges[componentIndex] = range;
model.rangeTuple[0] = range.min;
model.rangeTuple[1] = range.max;

return model.rangeTuple;
};

publicAPI.setTuple = (idx, tuple) => {
const offset = idx * model.numberOfComponents;
for (let i = 0; i < model.numberOfComponents; i++) {
model.values[offset + i] = tuple[i];
}
};

publicAPI.getTuple = (idx, tupleToFill = TUPLE_HOLDER) => {
const numberOfComponents = model.numberOfComponents || 1;
if (tupleToFill.length !== numberOfComponents) {
tupleToFill.length = numberOfComponents;
}
const offset = idx * numberOfComponents;
// Check most common component sizes first
// to avoid doing a for loop if possible
if (numberOfComponents === 1) {
tupleToFill[0] = model.values[offset];
} else if (numberOfComponents === 2) {
tupleToFill[0] = model.values[offset];
tupleToFill[1] = model.values[offset + 1];
} else if (numberOfComponents === 3) {
tupleToFill[0] = model.values[offset];
tupleToFill[1] = model.values[offset + 1];
tupleToFill[2] = model.values[offset + 2];
} else if (numberOfComponents === 4) {
tupleToFill[0] = model.values[offset];
tupleToFill[1] = model.values[offset + 1];
tupleToFill[2] = model.values[offset + 2];
tupleToFill[3] = model.values[offset + 3];
} else {
for (let i = 0; i < numberOfComponents; i++) {
tupleToFill[i] = model.values[offset + i];
}
}
return tupleToFill;
};

publicAPI.getTupleLocation = (idx = 1) => idx * model.numberOfComponents;
publicAPI.getNumberOfComponents = () => model.numberOfComponents;
publicAPI.getNumberOfValues = () => model.values.length;
publicAPI.getNumberOfTuples = () =>
model.values.length / model.numberOfComponents;
publicAPI.getDataType = () => model.dataType;
/* eslint-disable no-use-before-define */
publicAPI.newClone = () =>
newInstance({
empty: true,
name: model.name,
dataType: model.dataType,
numberOfComponents: model.numberOfComponents,
});
/* eslint-enable no-use-before-define */

publicAPI.getName = () => {
if (!model.name) {
publicAPI.modified();
model.name = `vtkDataArray${publicAPI.getMTime()}`;
}
return model.name;
};

publicAPI.setData = (typedArray, numberOfComponents) => {
model.values = typedArray;
model.size = typedArray.length;
model.dataType = getDataType(typedArray);
if (numberOfComponents) {
model.numberOfComponents = numberOfComponents;
}
if (model.size % model.numberOfComponents !== 0) {
model.numberOfComponents = 1;
}
dataChange();
};

// Override serialization support
publicAPI.getState = () => {
const jsonArchive = Object.assign({}, model, {
vtkClass: publicAPI.getClassName(),
});

// Convert typed array to regular array
jsonArchive.values = Array.from(jsonArchive.values);
delete jsonArchive.buffer;

// Clean any empty data
Object.keys(jsonArchive).forEach((keyName) => {
if (!jsonArchive[keyName]) {
delete jsonArchive[keyName];
}
});

// Sort resulting object by key name
const sortedObj = {};
Object.keys(jsonArchive)
.sort()
.forEach((name) => {
sortedObj[name] = jsonArchive[name];
});

// Remove mtime
if (sortedObj.mtime) {
delete sortedObj.mtime;
}

return sortedObj;
};
}

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

const DEFAULT_VALUES = {
name: '',
numberOfComponents: 1,
size: 0,
dataType: DefaultDataType,
rangeTuple: [0, 0],
// values: null,
// ranges: null,
};

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

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

if (!model.empty && !model.values && !model.size) {
throw new TypeError(
'Cannot create vtkDataArray object without: size > 0, values'
);
}

if (!model.values) {
model.values = new window[model.dataType](model.size);
} else if (Array.isArray(model.values)) {
model.values = window[model.dataType].from(model.values);
}

if (model.values) {
model.size = model.values.length;
model.dataType = getDataType(model.values);
}

// Object methods
macro.obj(publicAPI, model);
macro.set(publicAPI, model, ['name', 'numberOfComponents']);

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

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

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

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

export default Object.assign({ newInstance, extend }, STATIC, Constants);