From b8f3e397d07ee7d0dde662a7f550572364a51d62 Mon Sep 17 00:00:00 2001 From: "danil.mazurkin" Date: Mon, 7 Aug 2023 15:47:32 +1000 Subject: [PATCH 1/2] Add volume rendering --- Sources/Common/Core/DataArray/index.js | 481 ++++++----- Sources/Common/DataModel/ImageData/index.js | 407 ++++----- .../Common/DataModel/StructuredData/index.js | 46 +- Sources/Rendering/Core/CellPicker/index.js | 795 +++++++++++++----- .../Rendering/Core/VolumeProperty/index.js | 323 ++++--- 5 files changed, 1298 insertions(+), 754 deletions(-) diff --git a/Sources/Common/Core/DataArray/index.js b/Sources/Common/Core/DataArray/index.js index b758c998a31..7c6dafad276 100644 --- a/Sources/Common/Core/DataArray/index.js +++ b/Sources/Common/Core/DataArray/index.js @@ -1,96 +1,125 @@ -import Constants from 'vtk.js/Sources/Common/Core/DataArray/Constants'; -import * as macro from 'vtk.js/Sources/macros'; -import * as vtkMath from 'vtk.js/Sources/Common/Core/Math'; +import _defineProperty from '@babel/runtime/helpers/defineProperty'; +import Constants from './DataArray/Constants.js'; +import { newInstance as newInstance$1, newTypedArray, newTypedArrayFrom, obj, set, vtkErrorMacro as vtkErrorMacro$1 } from '../../macros.js'; +import { n as norm } from './Math/index.js'; -const { vtkErrorMacro } = macro; -const { DefaultDataType } = Constants; +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } -// ---------------------------------------------------------------------------- +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } +var vtkErrorMacro = vtkErrorMacro$1; +var DefaultDataType = Constants.DefaultDataType; // ---------------------------------------------------------------------------- // Global methods // ---------------------------------------------------------------------------- - // Original source from https://www.npmjs.com/package/compute-range // Modified to accept type arrays + function fastComputeRange(arr, offset, numberOfComponents) { - const len = arr.length; - let min; - let max; - let x; - let i; + var len = arr.length; + var min; + var max; + var x; + var i; if (len === 0) { - return { min: Number.MAX_VALUE, max: -Number.MAX_VALUE }; + return { + min: Number.MAX_VALUE, + max: -Number.MAX_VALUE + }; } + min = arr[offset]; max = min; + for (i = offset; i < len; i += numberOfComponents) { x = arr[i]; + if (x < min) { min = x; } else if (x > max) { max = x; } } - return { min, max }; -} + return { + min: min, + max: max + }; +} /** * @deprecated please use fastComputeRange instead */ -function createRangeHelper() { - let min = Number.MAX_VALUE; - let max = -Number.MAX_VALUE; - let count = 0; - let sum = 0; + +function createRangeHelper() { + var min = Number.MAX_VALUE; + var max = -Number.MAX_VALUE; + var count = 0; + var sum = 0; return { - add(value) { + add: function 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 }; + get: function get() { + return { + min: min, + max: max, + count: count, + sum: sum, + mean: sum / count + }; }, + getRange: function getRange() { + return { + min: min, + max: max + }; + } }; } -function computeRange(values, component = 0, numberOfComponents = 1) { +function computeRange(values) { + var component = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var numberOfComponents = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : 1; + if (component < 0 && numberOfComponents > 1) { // Compute magnitude - const size = values.length; - const numberOfValues = size / numberOfComponents; - const data = new Float64Array(numberOfValues); - for (let i = 0, j = 0; i < numberOfValues; ++i) { - for (let nextJ = j + numberOfComponents; j < nextJ; ++j) { + var size = values.length; + var numberOfValues = size / numberOfComponents; + var data = new Float64Array(numberOfValues); + + for (var i = 0, j = 0; i < numberOfValues; ++i) { + var _i; + + for (var nextJ = j + numberOfComponents; j < nextJ; ++j) { data[i] += values[j] * values[j]; } - data[i] **= 0.5; + + _i = i, data[_i] = Math.pow(data[_i], 0.5); } + return fastComputeRange(data, 0, 1); } - return fastComputeRange( - values, - component < 0 ? 0 : component, - numberOfComponents - ); + return fastComputeRange(values, component < 0 ? 0 : component, numberOfComponents); } -function ensureRangeSize(rangeArray, size = 0) { - const ranges = rangeArray || []; - // Pad ranges with null value to get the +function ensureRangeSize(rangeArray) { + var size = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var ranges = rangeArray || []; // Pad ranges with null value to get the + while (ranges.length <= size) { ranges.push(null); } + return ranges; } @@ -100,51 +129,55 @@ function getDataType(typedArray) { } function getMaxNorm(normArray) { - const numComps = normArray.getNumberOfComponents(); - let maxNorm = 0.0; - const tuple = new Array(numComps); - for (let i = 0; i < normArray.getNumberOfTuples(); ++i) { + var numComps = normArray.getNumberOfComponents(); + var maxNorm = 0.0; + var tuple = new Array(numComps); + + for (var i = 0; i < normArray.getNumberOfTuples(); ++i) { normArray.getTuple(i, tuple); - const norm = vtkMath.norm(tuple, numComps); - if (norm > maxNorm) { - maxNorm = norm; + var norm$1 = norm(tuple, numComps); + + if (norm$1 > maxNorm) { + maxNorm = norm$1; } } + return maxNorm; -} +} // ---------------------------------------------------------------------------- // Static API // ---------------------------------------------------------------------------- -export const STATIC = { - computeRange, - createRangeHelper, - fastComputeRange, - getDataType, - getMaxNorm, -}; -// ---------------------------------------------------------------------------- +var STATIC = { + computeRange: computeRange, + createRangeHelper: createRangeHelper, + fastComputeRange: fastComputeRange, + getDataType: getDataType, + getMaxNorm: getMaxNorm, + // createDataArray: createDataArray, +}; // ---------------------------------------------------------------------------- // vtkDataArray methods // ---------------------------------------------------------------------------- function vtkDataArray(publicAPI, model) { // Set our className model.classHierarchy.push('vtkDataArray'); - /** * Resize model.values and copy the old values to the new array. * @param {Number} requestedNumTuples Final expected number of tuples; must be >= 0 * @returns {Boolean} True if a resize occured, false otherwise */ + function resize(requestedNumTuples) { if (requestedNumTuples < 0) { return false; } - const numComps = publicAPI.getNumberOfComponents(); - const curNumTuples = model.values.length / (numComps > 0 ? numComps : 1); + var numComps = publicAPI.getNumberOfComponents(); + var curNumTuples = model.values.length / (numComps > 0 ? numComps : 1); + if (requestedNumTuples === curNumTuples) { return true; } @@ -153,16 +186,13 @@ function vtkDataArray(publicAPI, model) { // Requested size is bigger than current size. Allocate enough // memory to fit the requested size and be more than double the // currently allocated memory. - const oldValues = model.values; - model.values = macro.newTypedArray( - model.dataType, - (requestedNumTuples + curNumTuples) * numComps - ); + var oldValues = model.values; + model.values = newTypedArray(model.dataType, (requestedNumTuples + curNumTuples) * numComps); model.values.set(oldValues); return true; - } + } // Requested size is smaller than currently allocated size + - // Requested size is smaller than currently allocated size if (model.size > requestedNumTuples * numComps) { model.size = requestedNumTuples * numComps; publicAPI.dataChange(); @@ -171,252 +201,296 @@ function vtkDataArray(publicAPI, model) { return true; } - publicAPI.dataChange = () => { + publicAPI.dataChange = function () { model.ranges = null; publicAPI.modified(); }; - - publicAPI.resize = (requestedNumTuples) => { + + publicAPI.resize = function (requestedNumTuples) { resize(requestedNumTuples); - const newSize = requestedNumTuples * publicAPI.getNumberOfComponents(); + var newSize = requestedNumTuples * publicAPI.getNumberOfComponents(); + if (model.size !== newSize) { model.size = newSize; publicAPI.dataChange(); return true; } + return false; - }; + }; // FIXME, to rename into "clear()" or "reset()" - // FIXME, to rename into "clear()" or "reset()" - publicAPI.initialize = () => { + + publicAPI.initialize = function () { publicAPI.resize(0); }; - publicAPI.getElementComponentSize = () => model.values.BYTES_PER_ELEMENT; - - // Description: + publicAPI.getElementComponentSize = function () { + return 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]; + + publicAPI.getComponent = function (tupleIdx) { + var compIdx = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + console.log("getComponent tupleIdx = ", tupleIdx); + console.log("getComponent compIdx = ", compIdx); + console.log("getComponent arguments = ", arguments); + console.log("getComponent model.values = ", model.values); + console.log("getComponent model.numberOfComponents = ", model.numberOfComponents); + return 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) => { + + + publicAPI.setComponent = function (tupleIdx, compIdx, value) { if (value !== model.values[tupleIdx * model.numberOfComponents + compIdx]) { model.values[tupleIdx * model.numberOfComponents + compIdx] = value; publicAPI.dataChange(); } }; - publicAPI.getValue = (valueIdx) => { - const idx = valueIdx / model.numberOfComponents; - const comp = valueIdx % model.numberOfComponents; + publicAPI.getValue = function (valueIdx) { + var idx = valueIdx / model.numberOfComponents; + var comp = valueIdx % model.numberOfComponents; return publicAPI.getComponent(idx, comp); }; - publicAPI.setValue = (valueIdx, value) => { - const idx = valueIdx / model.numberOfComponents; - const comp = valueIdx % model.numberOfComponents; + publicAPI.setValue = function (valueIdx, value) { + var idx = valueIdx / model.numberOfComponents; + var comp = valueIdx % model.numberOfComponents; publicAPI.setComponent(idx, comp, value); }; - publicAPI.getData = () => - model.size === model.values.length - ? model.values - : model.values.subarray(0, model.size); + publicAPI.getData = function () { + return model.size === model.values.length ? model.values : model.values.subarray(0, model.size); + }; + + publicAPI.getRange = function () { + var componentIndex = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : -1; + var rangeIdx = componentIndex; - publicAPI.getRange = (componentIndex = -1) => { - let rangeIdx = componentIndex; if (rangeIdx < 0) { // If scalar data, then store in slot 0 (same as componentIndex = 0). // If vector data, then store in last slot. rangeIdx = model.numberOfComponents === 1 ? 0 : model.numberOfComponents; } - let range = null; + var 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... - // Need to compute ranges... - range = computeRange( - publicAPI.getData(), - componentIndex, - model.numberOfComponents - ); + + range = computeRange(publicAPI.getData(), componentIndex, model.numberOfComponents); model.ranges[rangeIdx] = range; model.rangeTuple[0] = range.min; model.rangeTuple[1] = range.max; return model.rangeTuple; }; - publicAPI.setRange = (rangeValue, componentIndex) => { + publicAPI.setRange = function (rangeValue, componentIndex) { if (!model.ranges) { model.ranges = ensureRangeSize(model.ranges, model.numberOfComponents); } - const range = { min: rangeValue.min, max: rangeValue.max }; + var 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++) { + publicAPI.setTuple = function (idx, tuple) { + var offset = idx * model.numberOfComponents; + + for (var i = 0; i < model.numberOfComponents; i++) { model.values[offset + i] = tuple[i]; } }; - publicAPI.setTuples = (idx, tuples) => { - let i = idx * model.numberOfComponents; - const last = Math.min(tuples.length, model.size - i); - for (let j = 0; j < last; ) { + publicAPI.setTuples = function (idx, tuples) { + var i = idx * model.numberOfComponents; + var last = Math.min(tuples.length, model.size - i); + + for (var j = 0; j < last;) { model.values[i++] = tuples[j++]; } }; - publicAPI.insertTuple = (idx, tuple) => { + publicAPI.insertTuple = function (idx, tuple) { if (model.size <= idx * model.numberOfComponents) { model.size = (idx + 1) * model.numberOfComponents; resize(idx + 1); } + publicAPI.setTuple(idx, tuple); return idx; }; - publicAPI.insertTuples = (idx, tuples) => { - const end = idx + tuples.length / model.numberOfComponents; + publicAPI.insertTuples = function (idx, tuples) { + var end = idx + tuples.length / model.numberOfComponents; + if (model.size < end * model.numberOfComponents) { model.size = end * model.numberOfComponents; resize(end); } + publicAPI.setTuples(idx, tuples); return end; }; - publicAPI.insertNextTuple = (tuple) => { - const idx = model.size / model.numberOfComponents; + publicAPI.insertNextTuple = function (tuple) { + var idx = model.size / model.numberOfComponents; return publicAPI.insertTuple(idx, tuple); }; - publicAPI.insertNextTuples = (tuples) => { - const idx = model.size / model.numberOfComponents; + publicAPI.insertNextTuples = function (tuples) { + var idx = model.size / model.numberOfComponents; return publicAPI.insertTuples(idx, tuples); }; - publicAPI.getTuple = (idx, tupleToFill = []) => { - const numberOfComponents = model.numberOfComponents || 1; - const offset = idx * numberOfComponents; - // Check most common component sizes first + publicAPI.getTuple = function (idx) { + var tupleToFill = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + var numberOfComponents = model.numberOfComponents || 1; + var offset = idx * numberOfComponents; // Check most common component sizes first // to avoid doing a for loop if possible + switch (numberOfComponents) { case 4: tupleToFill[3] = model.values[offset + 3]; // eslint-disable-next-line no-fallthrough + case 3: tupleToFill[2] = model.values[offset + 2]; // eslint-disable-next-line no-fallthrough + case 2: tupleToFill[1] = model.values[offset + 1]; // eslint-disable-next-line no-fallthrough + case 1: tupleToFill[0] = model.values[offset]; break; + default: - for (let i = numberOfComponents - 1; i >= 0; --i) { + for (var i = numberOfComponents - 1; i >= 0; --i) { tupleToFill[i] = model.values[offset + i]; } + } + return tupleToFill; }; - publicAPI.getTuples = (fromId, toId) => { - const from = (fromId ?? 0) * model.numberOfComponents; - const to = - (toId ?? publicAPI.getNumberOfTuples()) * model.numberOfComponents; - const arr = publicAPI.getData().subarray(from, to); + publicAPI.getTuples = function (fromId, toId) { + var from = (fromId !== null && fromId !== void 0 ? fromId : 0) * model.numberOfComponents; + var to = (toId !== null && toId !== void 0 ? toId : publicAPI.getNumberOfTuples()) * model.numberOfComponents; + var arr = publicAPI.getData().subarray(from, to); return arr.length > 0 ? arr : null; }; - publicAPI.getTupleLocation = (idx = 1) => idx * model.numberOfComponents; - publicAPI.getNumberOfComponents = () => model.numberOfComponents; - publicAPI.getNumberOfValues = () => model.size; - publicAPI.getNumberOfTuples = () => model.size / model.numberOfComponents; - publicAPI.getDataType = () => model.dataType; + publicAPI.getTupleLocation = function () { + var idx = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 1; + return idx * model.numberOfComponents; + }; + + publicAPI.getNumberOfComponents = function () { + return model.numberOfComponents; + }; + + publicAPI.getNumberOfValues = function () { + return model.size; + }; + + publicAPI.getNumberOfTuples = function () { + return model.size / model.numberOfComponents; + }; + + publicAPI.getDataType = function () { + return model.dataType; + }; /* eslint-disable no-use-before-define */ - publicAPI.newClone = () => - newInstance({ + + + publicAPI.newClone = function () { + return newInstance({ empty: true, name: model.name, dataType: model.dataType, - numberOfComponents: model.numberOfComponents, + numberOfComponents: model.numberOfComponents }); + }; /* eslint-enable no-use-before-define */ - publicAPI.getName = () => { + + publicAPI.getName = function () { if (!model.name) { publicAPI.modified(); - model.name = `vtkDataArray${publicAPI.getMTime()}`; + model.name = "vtkDataArray".concat(publicAPI.getMTime()); } + return model.name; }; - publicAPI.setData = (typedArray, numberOfComponents) => { + publicAPI.setData = function (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; } + publicAPI.dataChange(); - }; + }; // Override serialization support + - // Override serialization support - publicAPI.getState = () => { + publicAPI.getState = function () { if (model.deleted) { return null; } - const jsonArchive = { ...model, vtkClass: publicAPI.getClassName() }; - // Convert typed array to regular array + var jsonArchive = _objectSpread(_objectSpread({}, model), {}, { + vtkClass: publicAPI.getClassName() + }); // Convert typed array to regular array + + jsonArchive.values = Array.from(jsonArchive.values); - delete jsonArchive.buffer; + delete jsonArchive.buffer; // Clean any empty data - // Clean any empty data - Object.keys(jsonArchive).forEach((keyName) => { + Object.keys(jsonArchive).forEach(function (keyName) { if (!jsonArchive[keyName]) { delete jsonArchive[keyName]; } - }); + }); // Sort resulting object by key name - // Sort resulting object by key name - const sortedObj = {}; - Object.keys(jsonArchive) - .sort() - .forEach((name) => { - sortedObj[name] = jsonArchive[name]; - }); + var sortedObj = {}; + Object.keys(jsonArchive).sort().forEach(function (name) { + sortedObj[name] = jsonArchive[name]; + }); // Remove mtime - // Remove mtime if (sortedObj.mtime) { delete sortedObj.mtime; } @@ -424,108 +498,109 @@ function vtkDataArray(publicAPI, model) { return sortedObj; }; - publicAPI.deepCopy = (other) => { + publicAPI.deepCopy = function (other) { publicAPI.shallowCopy(other); publicAPI.setData(other.getData().slice()); }; - publicAPI.interpolateTuple = ( - idx, - source1, - source1Idx, - source2, - source2Idx, - t - ) => { - const numberOfComponents = model.numberOfComponents || 1; - if ( - numberOfComponents !== source1.getNumberOfComponents() || - numberOfComponents !== source2.getNumberOfComponents() - ) { + publicAPI.interpolateTuple = function (idx, source1, source1Idx, source2, source2Idx, t) { + var numberOfComponents = model.numberOfComponents || 1; + + if (numberOfComponents !== source1.getNumberOfComponents() || numberOfComponents !== source2.getNumberOfComponents()) { vtkErrorMacro('numberOfComponents must match'); } - const tuple1 = source1.getTuple(source1Idx); - const tuple2 = source2.getTuple(source2Idx); - const out = []; - out.length = numberOfComponents; - - // Check most common component sizes first + var tuple1 = source1.getTuple(source1Idx); + var tuple2 = source2.getTuple(source2Idx); + var out = []; + out.length = numberOfComponents; // Check most common component sizes first // to avoid doing a for loop if possible + switch (numberOfComponents) { case 4: out[3] = tuple1[3] + (tuple2[3] - tuple1[3]) * t; // eslint-disable-next-line no-fallthrough + case 3: out[2] = tuple1[2] + (tuple2[2] - tuple1[2]) * t; // eslint-disable-next-line no-fallthrough + case 2: out[1] = tuple1[1] + (tuple2[1] - tuple1[1]) * t; // eslint-disable-next-line no-fallthrough + case 1: out[0] = tuple1[0] + (tuple2[0] - tuple1[0]) * t; break; + default: - for (let i = 0; i < numberOfComponents; i++) { + for (var i = 0; i < numberOfComponents; i++) { out[i] = tuple1[i] + (tuple2[i] - tuple1[i]) * t; } + } return publicAPI.insertTuple(idx, out); }; -} - -// ---------------------------------------------------------------------------- +} // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- - // size: The current size of the dataArray. // NOTE: The underlying typed array may be larger than 'size'. -const DEFAULT_VALUES = { + + +var DEFAULT_VALUES = { name: '', numberOfComponents: 1, dataType: DefaultDataType, - rangeTuple: [0, 0], - // size: undefined, + rangeTuple: [0, 0] // size: undefined, // values: null, // ranges: null, -}; -// ---------------------------------------------------------------------------- +}; // ---------------------------------------------------------------------------- -export function extend(publicAPI, model, initialValues = {}) { +function extend(publicAPI, model) { + + var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); + // console.log("arguments = ", arguments); + // console.log("initialValues = ", initialValues); + // console.log("model = ", model); + // console.log("model.values = ", model.values); + // console.log("model.empty = ", model.empty); + // console.log("model.size = ", model.size) + if (!model.empty && !model.values && !model.size) { - throw new TypeError( - 'Cannot create vtkDataArray object without: size > 0, values' - ); + throw new TypeError('Cannot create vtkDataArray object without: size > 0, values'); } if (!model.values) { - model.values = macro.newTypedArray(model.dataType, model.size); + model.values = newTypedArray(model.dataType, model.size); } else if (Array.isArray(model.values)) { - model.values = macro.newTypedArrayFrom(model.dataType, model.values); + model.values = newTypedArrayFrom(model.dataType, model.values); } if (model.values) { + var _model$size; + // Takes the size if provided (can be lower than `model.values`) otherwise the actual length of `values`. - model.size = model.size ?? model.values.length; + model.size = (_model$size = model.size) !== null && _model$size !== void 0 ? _model$size : model.values.length; model.dataType = getDataType(model.values); - } + } // Object methods - // Object methods - macro.obj(publicAPI, model); - macro.set(publicAPI, model, ['name', 'numberOfComponents']); - // Object specific methods - vtkDataArray(publicAPI, model); -} + obj(publicAPI, model); + set(publicAPI, model, ['name', 'numberOfComponents']); // Object specific methods -// ---------------------------------------------------------------------------- + vtkDataArray(publicAPI, model); +} // ---------------------------------------------------------------------------- -export const newInstance = macro.newInstance(extend, 'vtkDataArray'); +var newInstance = newInstance$1(extend, 'vtkDataArray'); // ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- +var vtkDataArray$1 = _objectSpread(_objectSpread({ + newInstance: newInstance, + extend: extend +}, STATIC), Constants); -export default { newInstance, extend, ...STATIC, ...Constants }; +export { STATIC, vtkDataArray$1 as default, extend, newInstance }; diff --git a/Sources/Common/DataModel/ImageData/index.js b/Sources/Common/DataModel/ImageData/index.js index f57aa42e950..993e6261e2f 100644 --- a/Sources/Common/DataModel/ImageData/index.js +++ b/Sources/Common/DataModel/ImageData/index.js @@ -1,14 +1,14 @@ -import macro from 'vtk.js/Sources/macros'; -import * as vtkMath from 'vtk.js/Sources/Common/Core/Math'; -import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox'; -import vtkDataSet from 'vtk.js/Sources/Common/DataModel/DataSet'; -import vtkStructuredData from 'vtk.js/Sources/Common/DataModel/StructuredData'; -import { StructuredType } from 'vtk.js/Sources/Common/DataModel/StructuredData/Constants'; -import { vec3, mat3, mat4 } from 'gl-matrix'; - -const { vtkErrorMacro } = macro; - -// ---------------------------------------------------------------------------- +import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; +import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray'; +import macro from '../../macros.js'; +import { b as roundVector, c as clampVector } from '../Core/Math/index.js'; +import vtkBoundingBox from './BoundingBox.js'; +import vtkDataSet from './DataSet.js'; +import vtkStructuredData from './StructuredData.js'; +import { StructuredType } from './StructuredData/Constants.js'; +import { mat3, mat4, vec3 } from 'gl-matrix'; + +var vtkErrorMacro = macro.vtkErrorMacro; // ---------------------------------------------------------------------------- // vtkImageData methods // ---------------------------------------------------------------------------- @@ -16,51 +16,58 @@ function vtkImageData(publicAPI, model) { // Set our className model.classHierarchy.push('vtkImageData'); - publicAPI.setExtent = (...inExtent) => { + publicAPI.setExtent = function () { if (model.deleted) { vtkErrorMacro('instance deleted - cannot call any method'); return false; } - const extentArray = inExtent.length === 1 ? inExtent[0] : inExtent; + for (var _len = arguments.length, inExtent = new Array(_len), _key = 0; _key < _len; _key++) { + inExtent[_key] = arguments[_key]; + } + + var extentArray = inExtent.length === 1 ? inExtent[0] : inExtent; if (extentArray.length !== 6) { return false; } - const changeDetected = model.extent.some( - (item, index) => item !== extentArray[index] - ); + var changeDetected = model.extent.some(function (item, index) { + return item !== extentArray[index]; + }); if (changeDetected) { model.extent = extentArray.slice(); - model.dataDescription = vtkStructuredData.getDataDescriptionFromExtent( - model.extent - ); + model.dataDescription = vtkStructuredData.getDataDescriptionFromExtent(model.extent); publicAPI.modified(); } + return changeDetected; }; - publicAPI.setDimensions = (...dims) => { - let i; - let j; - let k; + publicAPI.computePointId = function (ijk) { + return vtkStructuredData.computePointIdForExtent(model.extent, ijk); + } + + publicAPI.setDimensions = function () { + var i; + var j; + var k; if (model.deleted) { vtkErrorMacro('instance deleted - cannot call any method'); return; } - if (dims.length === 1) { - const array = dims[0]; + if (arguments.length === 1) { + var array = arguments.length <= 0 ? undefined : arguments[0]; i = array[0]; j = array[1]; k = array[2]; - } else if (dims.length === 3) { - i = dims[0]; - j = dims[1]; - k = dims[2]; + } else if (arguments.length === 3) { + i = arguments.length <= 0 ? undefined : arguments[0]; + j = arguments.length <= 1 ? undefined : arguments[1]; + k = arguments.length <= 2 ? undefined : arguments[2]; } else { vtkErrorMacro('Bad dimension specification'); return; @@ -69,20 +76,19 @@ function vtkImageData(publicAPI, model) { publicAPI.setExtent(0, i - 1, 0, j - 1, 0, k - 1); }; - publicAPI.getDimensions = () => [ - model.extent[1] - model.extent[0] + 1, - model.extent[3] - model.extent[2] + 1, - model.extent[5] - model.extent[4] + 1, - ]; + publicAPI.getDimensions = function () { + return [model.extent[1] - model.extent[0] + 1, model.extent[3] - model.extent[2] + 1, model.extent[5] - model.extent[4] + 1]; + }; - publicAPI.getNumberOfCells = () => { - const dims = publicAPI.getDimensions(); - let nCells = 1; + publicAPI.getNumberOfCells = function () { + var dims = publicAPI.getDimensions(); + var nCells = 1; - for (let i = 0; i < 3; i++) { + for (var i = 0; i < 3; i++) { if (dims[i] === 0) { return 0; } + if (dims[i] > 1) { nCells *= dims[i] - 1; } @@ -91,20 +97,20 @@ function vtkImageData(publicAPI, model) { return nCells; }; - publicAPI.getNumberOfPoints = () => { - const dims = publicAPI.getDimensions(); + publicAPI.getNumberOfPoints = function () { + var dims = publicAPI.getDimensions(); return dims[0] * dims[1] * dims[2]; }; - publicAPI.getPoint = (index) => { - const dims = publicAPI.getDimensions(); + publicAPI.getPoint = function (index) { + var dims = publicAPI.getDimensions(); if (dims[0] === 0 || dims[1] === 0 || dims[2] === 0) { vtkErrorMacro('Requesting a point from an empty image.'); return null; } - const ijk = new Float64Array(3); + var ijk = new Float64Array(3); switch (model.dataDescription) { case StructuredType.EMPTY: @@ -142,7 +148,7 @@ function vtkImageData(publicAPI, model) { case StructuredType.XYZ_GRID: ijk[0] = index % dims[0]; - ijk[1] = (index / dims[0]) % dims[1]; + ijk[1] = index / dims[0] % dims[1]; ijk[2] = index / (dims[0] * dims[1]); break; @@ -151,11 +157,20 @@ function vtkImageData(publicAPI, model) { break; } - const coords = [0, 0, 0]; + var coords = [0, 0, 0]; publicAPI.indexToWorld(ijk, coords); return coords; }; + + publicAPI.getScalarType = function () { + var scalars = publicAPI.getPointData().getScalars(); + + if (!scalars) { + return Number.MAX_VALUE + } + return scalars.getDataType(); + } // vtkCell *GetCell(vtkIdType cellId) VTK_OVERRIDE; // void GetCell(vtkIdType cellId, vtkGenericCell *cell) VTK_OVERRIDE; // void GetCellBounds(vtkIdType cellId, double bounds[6]) VTK_OVERRIDE; @@ -183,104 +198,126 @@ function vtkImageData(publicAPI, model) { // void ComputeBounds() VTK_OVERRIDE; // int GetMaxCellSize() VTK_OVERRIDE {return 8;}; //voxel is the largest - publicAPI.getBounds = () => - publicAPI.extentToBounds(publicAPI.getSpatialExtent()); + publicAPI.getNumberOfScalarComponents = function () { + let scalars = publicAPI.getPointData().getScalars(); + if (scalars) + { + return scalars.getNumberOfComponents(); + } + return 1; + } - publicAPI.extentToBounds = (ex) => - vtkBoundingBox.transformBounds(ex, model.indexToWorld); + publicAPI.getBounds = function () { + return publicAPI.extentToBounds(publicAPI.getSpatialExtent()); + }; + + publicAPI.extentToBounds = function (ex) { + return vtkBoundingBox.transformBounds(ex, model.indexToWorld); + }; - publicAPI.getSpatialExtent = () => - vtkBoundingBox.inflate([...model.extent], 0.5); + publicAPI.getSpatialExtent = function () { + return vtkBoundingBox.inflate(_toConsumableArray(model.extent), 0.5); + }; // Internal, shouldn't need to call this manually. - // Internal, shouldn't need to call this manually. - publicAPI.computeTransforms = () => { - mat4.fromTranslation(model.indexToWorld, model.origin); + publicAPI.computeTransforms = function () { + mat4.fromTranslation(model.indexToWorld, model.origin); model.indexToWorld[0] = model.direction[0]; model.indexToWorld[1] = model.direction[1]; model.indexToWorld[2] = model.direction[2]; - model.indexToWorld[4] = model.direction[3]; model.indexToWorld[5] = model.direction[4]; model.indexToWorld[6] = model.direction[5]; - model.indexToWorld[8] = model.direction[6]; model.indexToWorld[9] = model.direction[7]; model.indexToWorld[10] = model.direction[8]; - mat4.scale(model.indexToWorld, model.indexToWorld, model.spacing); - mat4.invert(model.worldToIndex, model.indexToWorld); }; - publicAPI.indexToWorld = (ain, aout = []) => { + publicAPI.indexToWorld = function (ain) { + var aout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; vec3.transformMat4(aout, ain, model.indexToWorld); return aout; }; + publicAPI.indexToWorldVec3 = publicAPI.indexToWorld; - publicAPI.worldToIndex = (ain, aout = []) => { + publicAPI.worldToIndex = function (ain) { + var aout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; vec3.transformMat4(aout, ain, model.worldToIndex); return aout; }; + publicAPI.worldToIndexVec3 = publicAPI.worldToIndex; - publicAPI.indexToWorldBounds = (bin, bout = []) => - vtkBoundingBox.transformBounds(bin, model.indexToWorld, bout); + publicAPI.indexToWorldBounds = function (bin) { + var bout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + return vtkBoundingBox.transformBounds(bin, model.indexToWorld, bout); + }; + + publicAPI.worldToIndexBounds = function (bin) { + var bout = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; + return vtkBoundingBox.transformBounds(bin, model.worldToIndex, bout); + }; // Make sure the transform is correct - publicAPI.worldToIndexBounds = (bin, bout = []) => - vtkBoundingBox.transformBounds(bin, model.worldToIndex, bout); - // Make sure the transform is correct publicAPI.onModified(publicAPI.computeTransforms); publicAPI.computeTransforms(); - publicAPI.getCenter = () => vtkBoundingBox.getCenter(publicAPI.getBounds()); + publicAPI.getCenter = function () { + return vtkBoundingBox.getCenter(publicAPI.getBounds()); + }; - publicAPI.computeHistogram = (worldBounds, voxelFunc = null) => { - const bounds = [0, 0, 0, 0, 0, 0]; - publicAPI.worldToIndexBounds(worldBounds, bounds); + publicAPI.getPointGradient = function(i, j, k, s, g) { + console.log("soon..") + } - const point1 = [0, 0, 0]; - const point2 = [0, 0, 0]; - vtkBoundingBox.computeCornerPoints(bounds, point1, point2); + publicAPI.getVoxelGradient = function (i, j, k, s, g) { + var gv = new Array(3); + var idx = 0; + + for (var kk = 0; kk < 2; kk++) + { + for (var jj = 0; jj < 2; jj++) + { + for (var ii = 0; ii < 2; ii++) + { + publicAPI.getPointGradient(i + ii, j + jj, k + kk, s, gv); + g.setTuple(idx++, gv); + } + } + } + } - vtkMath.roundVector(point1, point1); - vtkMath.roundVector(point2, point2); - - const dimensions = publicAPI.getDimensions(); - - vtkMath.clampVector( - point1, - [0, 0, 0], - [dimensions[0] - 1, dimensions[1] - 1, dimensions[2] - 1], - point1 - ); - vtkMath.clampVector( - point2, - [0, 0, 0], - [dimensions[0] - 1, dimensions[1] - 1, dimensions[2] - 1], - point2 - ); - - const yStride = dimensions[0]; - const zStride = dimensions[0] * dimensions[1]; - - const pixels = publicAPI.getPointData().getScalars().getData(); - - let maximum = -Infinity; - let minimum = Infinity; - let sumOfSquares = 0; - let isum = 0; - let inum = 0; - - for (let z = point1[2]; z <= point2[2]; z++) { - for (let y = point1[1]; y <= point2[1]; y++) { - let index = point1[0] + y * yStride + z * zStride; - for (let x = point1[0]; x <= point2[0]; x++) { + publicAPI.computeHistogram = function (worldBounds) { + var voxelFunc = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : null; + var bounds = [0, 0, 0, 0, 0, 0]; + publicAPI.worldToIndexBounds(worldBounds, bounds); + var point1 = [0, 0, 0]; + var point2 = [0, 0, 0]; + vtkBoundingBox.computeCornerPoints(bounds, point1, point2); + roundVector(point1, point1); + roundVector(point2, point2); + var dimensions = publicAPI.getDimensions(); + clampVector(point1, [0, 0, 0], [dimensions[0] - 1, dimensions[1] - 1, dimensions[2] - 1], point1); + clampVector(point2, [0, 0, 0], [dimensions[0] - 1, dimensions[1] - 1, dimensions[2] - 1], point2); + var yStride = dimensions[0]; + var zStride = dimensions[0] * dimensions[1]; + var pixels = publicAPI.getPointData().getScalars().getData(); + var maximum = -Infinity; + var minimum = Infinity; + var sumOfSquares = 0; + var isum = 0; + var inum = 0; + + for (var z = point1[2]; z <= point2[2]; z++) { + for (var y = point1[1]; y <= point2[1]; y++) { + var index = point1[0] + y * yStride + z * zStride; + + for (var x = point1[0]; x <= point2[0]; x++) { if (!voxelFunc || voxelFunc([x, y, z], bounds)) { - const pixel = pixels[index]; - + var pixel = pixels[index]; if (pixel > maximum) maximum = pixel; if (pixel < minimum) minimum = pixel; sumOfSquares += pixel * pixel; @@ -293,77 +330,72 @@ function vtkImageData(publicAPI, model) { } } - const average = inum > 0 ? isum / inum : 0; - const variance = inum - ? Math.abs(sumOfSquares / inum - average * average) - : 0; - const sigma = Math.sqrt(variance); - + var average = inum > 0 ? isum / inum : 0; + var variance = inum ? Math.abs(sumOfSquares / inum - average * average) : 0; + var sigma = Math.sqrt(variance); return { - minimum, - maximum, - average, - variance, - sigma, - count: inum, + minimum: minimum, + maximum: maximum, + average: average, + variance: variance, + sigma: sigma, + count: inum }; - }; - - // TODO: use the unimplemented `vtkDataSetAttributes` for scalar length, that is currently also a TODO (GetNumberOfComponents). + }; // TODO: use the unimplemented `vtkDataSetAttributes` for scalar length, that is currently also a TODO (GetNumberOfComponents). // Scalar data could be tuples for color information? - publicAPI.computeIncrements = (extent, numberOfComponents = 1) => { - const increments = []; - let incr = numberOfComponents; - // Calculate array increment offsets + + publicAPI.computeIncrements = function (extent) { + var numberOfComponents = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 1; + var increments = []; + var incr = numberOfComponents; // Calculate array increment offsets // similar to c++ vtkImageData::ComputeIncrements - for (let idx = 0; idx < 3; ++idx) { + + for (var idx = 0; idx < 3; ++idx) { increments[idx] = incr; incr *= extent[idx * 2 + 1] - extent[idx * 2] + 1; } + return increments; }; - /** * @param {Number[]} index the localized `[i,j,k]` pixel array position. Float values will be rounded. * @return {Number} the corresponding flattened index in the scalar array */ - publicAPI.computeOffsetIndex = ([i, j, k]) => { - const extent = publicAPI.getExtent(); - const numberOfComponents = publicAPI - .getPointData() - .getScalars() - .getNumberOfComponents(); - const increments = publicAPI.computeIncrements(extent, numberOfComponents); - // Use the array increments to find the pixel index + + + publicAPI.computeOffsetIndex = function (_ref) { + var _ref2 = _slicedToArray(_ref, 3), + i = _ref2[0], + j = _ref2[1], + k = _ref2[2]; + + var extent = publicAPI.getExtent(); + var numberOfComponents = publicAPI.getPointData().getScalars().getNumberOfComponents(); + var increments = publicAPI.computeIncrements(extent, numberOfComponents); // Use the array increments to find the pixel index // similar to c++ vtkImageData::GetArrayPointer // Math.floor to catch "practically 0" e^-15 scenarios. - return Math.floor( - (Math.round(i) - extent[0]) * increments[0] + - (Math.round(j) - extent[2]) * increments[1] + - (Math.round(k) - extent[4]) * increments[2] - ); - }; + return Math.floor((Math.round(i) - extent[0]) * increments[0] + (Math.round(j) - extent[2]) * increments[1] + (Math.round(k) - extent[4]) * increments[2]); + }; /** * @param {Number[]} xyz the [x,y,z] Array in world coordinates * @return {Number|NaN} the corresponding pixel's index in the scalar array */ - publicAPI.getOffsetIndexFromWorld = (xyz) => { - const extent = publicAPI.getExtent(); - const index = publicAPI.worldToIndex(xyz); - // Confirm indexed i,j,k coords are within the bounds of the volume - for (let idx = 0; idx < 3; ++idx) { + + publicAPI.getOffsetIndexFromWorld = function (xyz) { + var extent = publicAPI.getExtent(); + var index = publicAPI.worldToIndex(xyz); // Confirm indexed i,j,k coords are within the bounds of the volume + + for (var idx = 0; idx < 3; ++idx) { if (index[idx] < extent[idx * 2] || index[idx] > extent[idx * 2 + 1]) { - vtkErrorMacro( - `GetScalarPointer: Pixel ${index} is not in memory. Current extent = ${extent}` - ); + vtkErrorMacro("GetScalarPointer: Pixel ".concat(index, " is not in memory. Current extent = ").concat(extent)); return NaN; } - } + } // Assumed the index here is within 0 <-> scalarData.length, but doesn't hurt to check upstream + - // Assumed the index here is within 0 <-> scalarData.length, but doesn't hurt to check upstream return publicAPI.computeOffsetIndex(index); }; /** @@ -371,50 +403,48 @@ function vtkImageData(publicAPI, model) { * @param {Number?} comp the scalar component index for multi-component scalars * @return {Number|NaN} the corresponding pixel's scalar value */ - publicAPI.getScalarValueFromWorld = (xyz, comp = 0) => { - const numberOfComponents = publicAPI - .getPointData() - .getScalars() - .getNumberOfComponents(); + + + publicAPI.getScalarValueFromWorld = function (xyz) { + var comp = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : 0; + var numberOfComponents = publicAPI.getPointData().getScalars().getNumberOfComponents(); + if (comp < 0 || comp >= numberOfComponents) { - vtkErrorMacro( - `GetScalarPointer: Scalar Component ${comp} is not within bounds. Current Scalar numberOfComponents: ${numberOfComponents}` - ); + vtkErrorMacro("GetScalarPointer: Scalar Component ".concat(comp, " is not within bounds. Current Scalar numberOfComponents: ").concat(numberOfComponents)); return NaN; } - const offsetIndex = publicAPI.getOffsetIndexFromWorld(xyz); + + var offsetIndex = publicAPI.getOffsetIndexFromWorld(xyz); + if (Number.isNaN(offsetIndex)) { // VTK Error Macro will have been tripped already, no need to do it again, return offsetIndex; } - return publicAPI - .getPointData() - .getScalars() - .getComponent(offsetIndex, comp); + return publicAPI.getPointData().getScalars().getComponent(offsetIndex, comp); }; -} - -// ---------------------------------------------------------------------------- +} // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- -const DEFAULT_VALUES = { - direction: null, // a mat3 - indexToWorld: null, // a mat4 - worldToIndex: null, // a mat4 + +var DEFAULT_VALUES = { + direction: null, + // a mat3 + indexToWorld: null, + // a mat4 + worldToIndex: null, + // a mat4 spacing: [1.0, 1.0, 1.0], origin: [0.0, 0.0, 0.0], extent: [0, -1, 0, -1, 0, -1], - dataDescription: StructuredType.EMPTY, -}; - -// ---------------------------------------------------------------------------- + dataDescription: StructuredType.EMPTY +}; // ---------------------------------------------------------------------------- -export function extend(publicAPI, model, initialValues = {}) { - Object.assign(model, DEFAULT_VALUES, initialValues); +function extend(publicAPI, model) { + var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance - // Inheritance vtkDataSet.extend(publicAPI, model, initialValues); if (!model.direction) { @@ -424,22 +454,21 @@ export function extend(publicAPI, model, initialValues = {}) { } model.indexToWorld = new Float64Array(16); - model.worldToIndex = new Float64Array(16); + model.worldToIndex = new Float64Array(16); // Set/Get methods - // Set/Get methods macro.get(publicAPI, model, ['indexToWorld', 'worldToIndex']); macro.setGetArray(publicAPI, model, ['origin', 'spacing'], 3); macro.setGetArray(publicAPI, model, ['direction'], 9); - macro.getArray(publicAPI, model, ['extent'], 6); + macro.getArray(publicAPI, model, ['extent'], 6); // Object specific methods - // Object specific methods vtkImageData(publicAPI, model); -} +} // ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- - -export const newInstance = macro.newInstance(extend, 'vtkImageData'); +var newInstance = macro.newInstance(extend, 'vtkImageData'); // ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- +var vtkImageData$1 = { + newInstance: newInstance, + extend: extend +}; -export default { newInstance, extend }; +export { vtkImageData$1 as default, extend, newInstance }; diff --git a/Sources/Common/DataModel/StructuredData/index.js b/Sources/Common/DataModel/StructuredData/index.js index 4212c3c8763..e4526a0f1f2 100644 --- a/Sources/Common/DataModel/StructuredData/index.js +++ b/Sources/Common/DataModel/StructuredData/index.js @@ -1,10 +1,15 @@ -import Constants from 'vtk.js/Sources/Common/DataModel/StructuredData/Constants'; +import _defineProperty from '@babel/runtime/helpers/defineProperty'; +import Constants from './StructuredData/Constants.js'; -const { StructuredType } = Constants; +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } -export function getDataDescriptionFromExtent(inExt) { - let dataDim = 0; - for (let i = 0; i < 3; ++i) { +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } +var StructuredType = Constants.StructuredType; + +function getDataDescriptionFromExtent(inExt) { + var dataDim = 0; + + for (var i = 0; i < 3; ++i) { if (inExt[i * 2] < inExt[i * 2 + 1]) { dataDim++; } @@ -26,6 +31,7 @@ export function getDataDescriptionFromExtent(inExt) { if (inExt[2] === inExt[3]) { return StructuredType.XZ_PLANE; } + return StructuredType.XY_PLANE; } @@ -44,4 +50,32 @@ export function getDataDescriptionFromExtent(inExt) { return StructuredType.SINGLE_POINT; } -export default { getDataDescriptionFromExtent, ...Constants }; + +function getDimensionsFromExtent(extent, dims) { + +} + + +function getLocalStructuredCoordinates(ijk, extent, lijk) { + +} + + +function computePointId(dim, ijk) { + return (ijk[2]*(dim[1] + ijk[1])*dim[0] + ijk[0]); +} + + +function computePointIdForExtent(extent, ijk) { + var ydim = (extent[3] - extent[2] + 1); + var xdim = (extent[1] - extent[0] + 1); + return ((ijk[2] - extent[4])*ydim + (ijk[1] - extent[2]))*xdim + (ijk[0] - extent[0]); +} + +var vtkStructuredData = _objectSpread({ + getDataDescriptionFromExtent: getDataDescriptionFromExtent, + computePointId: computePointId, + computePointIdForExtent: computePointIdForExtent, +}, Constants); + +export { vtkStructuredData as default, getDataDescriptionFromExtent }; diff --git a/Sources/Rendering/Core/CellPicker/index.js b/Sources/Rendering/Core/CellPicker/index.js index fb6a4b81658..32ee0b0a08f 100644 --- a/Sources/Rendering/Core/CellPicker/index.js +++ b/Sources/Rendering/Core/CellPicker/index.js @@ -1,40 +1,68 @@ -import macro from 'vtk.js/Sources/macros'; -import vtkCellTypes from 'vtk.js/Sources/Common/DataModel/CellTypes'; -import vtkLine from 'vtk.js/Sources/Common/DataModel/Line'; -import vtkPicker from 'vtk.js/Sources/Rendering/Core/Picker'; -import vtkPolyLine from 'vtk.js/Sources/Common/DataModel/PolyLine'; -import vtkTriangle from 'vtk.js/Sources/Common/DataModel/Triangle'; -import vtkQuad from 'vtk.js/Sources/Common/DataModel/Quad'; -import * as vtkMath from 'vtk.js/Sources/Common/Core/Math'; -import { CellType } from 'vtk.js/Sources/Common/DataModel/CellTypes/Constants'; +import _defineProperty from '@babel/runtime/helpers/defineProperty'; +import macro from '../../macros.js'; +import vtkCellTypes from '../../Common/DataModel/CellTypes.js'; +import vtkLine from '../../Common/DataModel/Line.js'; +import vtkPicker from './Picker.js'; +import vtkPolyLine from '../../Common/DataModel/PolyLine.js'; +import vtkTriangle from '../../Common/DataModel/Triangle.js'; +import vtkQuad from '../../Common/DataModel/Quad.js'; +import { L, l as normalize } from '../../Common/Core/Math/index.js'; +import { CellType } from '../../Common/DataModel/CellTypes/Constants.js'; import { vec3 } from 'gl-matrix'; +import vtkBox from '../../Common/DataModel/Box.js'; +import vtkMath from '../../Common/Core/Math.js'; +import vtkDataArray from '../../Common/Core/DataArray.js'; +import DataTypeByteSize from '../../Common/Core/DataArray/Constants.js'; +import vtkPiecewiseFunction from '@kitware/vtk.js/Common/DataModel/PiecewiseFunction.js'; -// ---------------------------------------------------------------------------- + +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } // Global methods // ---------------------------------------------------------------------------- +function interpolationFunctions(pcoords, sf) { + // Function for interpolation, in Native Vtk of VtkVoxel + var rm, sm, tm; + + var r = pcoords[0], s = pcoords[1], t = pcoords[2]; + + rm = 1. - r; + sm = 1. - s; + tm = 1. - t; + + sf[0] = rm * sm * tm; + sf[1] = r * sm * tm; + sf[2] = rm * s * tm; + sf[3] = r * s * tm; + sf[4] = rm * sm * t; + sf[5] = r * sm * t; + sf[6] = rm * s * t; + sf[7] = r * s * t; +} + function createCellMap() { - return { - [CellType.VTK_LINE]: vtkLine.newInstance(), - [CellType.VTK_POLY_LINE]: vtkPolyLine.newInstance(), - [CellType.VTK_TRIANGLE]: vtkTriangle.newInstance(), - [CellType.VTK_QUAD]: vtkQuad.newInstance(), - }; + var _ref; + + return _ref = {}, _defineProperty(_ref, CellType.VTK_LINE, vtkLine.newInstance()), _defineProperty(_ref, CellType.VTK_POLY_LINE, vtkPolyLine.newInstance()), _defineProperty(_ref, CellType.VTK_TRIANGLE, vtkTriangle.newInstance()), _defineProperty(_ref, CellType.VTK_QUAD, vtkQuad.newInstance()), _ref; } function clipLineWithPlane(mapper, matrix, p1, p2) { - const outObj = { planeId: -1, t1: 0.0, t2: 1.0, intersect: 0 }; - const nbClippingPlanes = mapper.getNumberOfClippingPlanes(); - const plane = []; - for (let i = 0; i < nbClippingPlanes; i++) { - mapper.getClippingPlaneInDataCoords(matrix, i, plane); + var outObj = { + planeId: -1, + t1: 0.0, + t2: 1.0, + intersect: 0 + }; + var nbClippingPlanes = mapper.getNumberOfClippingPlanes(); + var plane = []; - const d1 = - plane[0] * p1[0] + plane[1] * p1[1] + plane[2] * p1[2] + plane[3]; - const d2 = - plane[0] * p2[0] + plane[1] * p2[1] + plane[2] * p2[2] + plane[3]; + for (var i = 0; i < nbClippingPlanes; i++) { + mapper.getClippingPlaneInDataCoords(matrix, i, plane); + var d1 = plane[0] * p1[0] + plane[1] * p1[1] + plane[2] * p1[2] + plane[3]; + var d2 = plane[0] * p2[0] + plane[1] * p2[1] + plane[2] * p2[2] + plane[3]; // If both distances are negative, both points are outside - // If both distances are negative, both points are outside if (d1 < 0 && d2 < 0) { return 0; } @@ -42,15 +70,14 @@ function clipLineWithPlane(mapper, matrix, p1, p2) { if (d1 < 0 || d2 < 0) { // If only one of the distances is negative, the line crosses the plane // Compute fractional distance "t" of the crossing between p1 & p2 - let t = 0.0; + var t = 0.0; // The "if" here just avoids an expensive division when possible - // The "if" here just avoids an expensive division when possible if (d1 !== 0) { // We will never have d1==d2 since they have different signs t = d1 / (d1 - d2); - } + } // If point p1 was clipped, adjust t1 + - // If point p1 was clipped, adjust t1 if (d1 < 0) { if (t >= outObj.t1) { outObj.t1 = t; @@ -59,51 +86,61 @@ function clipLineWithPlane(mapper, matrix, p1, p2) { } else if (t <= outObj.t2) { // else point p2 was clipped, so adjust t2 outObj.t2 = t; - } - // If this happens, there's no line left + } // If this happens, there's no line left + + if (outObj.t1 > outObj.t2) { outObj.intersect = 0; return outObj; } } } + outObj.intersect = 1; return outObj; -} - -// ---------------------------------------------------------------------------- +} // ---------------------------------------------------------------------------- // Static API // ---------------------------------------------------------------------------- -export const STATIC = { - clipLineWithPlane, -}; -// ---------------------------------------------------------------------------- +var STATIC = { + clipLineWithPlane: clipLineWithPlane +}; // ---------------------------------------------------------------------------- // vtkCellPicker methods // ---------------------------------------------------------------------------- +var Tolerance = 1e-6; +var VolumeOpacityIsovalue = 0.05; +var UseVolumeGradientOpacity = 0; +var PickClippingPlanes = 0; +var PickTextureData = 0; + function vtkCellPicker(publicAPI, model) { // Set our className model.classHierarchy.push('vtkCellPicker'); - const superClass = { ...publicAPI }; + + var superClass = _objectSpread({}, publicAPI); + var volume = undefined; + model.volumeFromPicker + var values = new Float32Array(); + model.gradients = vtkDataArray.newInstance({ empty: true, name: 'gradients', values, numberOfComponents: 3, numberOfTuples: 8}); + + function setVolumeForPicker(volumeFromPicker) { + volume = volumeFromPicker; + } function resetCellPickerInfo() { model.cellId = -1; - model.pCoords[0] = 0.0; model.pCoords[1] = 0.0; model.pCoords[2] = 0.0; - model.cellIJK[0] = 0.0; model.cellIJK[1] = 0.0; model.cellIJK[2] = 0.0; - model.mapperNormal[0] = 0.0; model.mapperNormal[1] = 0.0; model.mapperNormal[2] = 1.0; - model.pickNormal[0] = 0.0; model.pickNormal[1] = 0.0; model.pickNormal[2] = 1.0; @@ -115,46 +152,52 @@ function vtkCellPicker(publicAPI, model) { resetCellPickerInfo(); } - publicAPI.initialize = () => { + publicAPI.initialize = function () { resetPickInfo(); superClass.initialize(); }; - publicAPI.computeSurfaceNormal = (data, cell, weights, normal) => { - const normals = data.getPointData().getNormals(); - // TODO add getCellDimension on vtkCell - const cellDimension = 0; + publicAPI.computeSurfaceNormal = function (data, cell, weights, normal) { + var normals = data.getPointData().getNormals(); // TODO add getCellDimension on vtkCell + if (normals) { normal[0] = 0.0; normal[1] = 0.0; normal[2] = 0.0; - const pointNormal = []; - for (let i = 0; i < 3; i++) { + var pointNormal = []; + + for (var i = 0; i < 3; i++) { normals.getTuple(cell.getPointsIds()[i], pointNormal); normal[0] += pointNormal[0] * weights[i]; normal[1] += pointNormal[1] * weights[i]; normal[2] += pointNormal[2] * weights[i]; } - vtkMath.normalize(normal); - } else if (cellDimension === 2) { - // TODO + + normalize(normal); } else { return 0; } + return 1; }; - publicAPI.pick = (selection, renderer) => { + publicAPI.pick = function (selection, renderer, volume=undefined) { publicAPI.initialize(); - const pickResult = superClass.pick(selection, renderer); + + if (volume) { + setVolumeForPicker(volume); + } + + var pickResult = superClass.pick(selection, renderer); + if (pickResult) { - const camera = renderer.getActiveCamera(); - const cameraPos = []; + var camera = renderer.getActiveCamera(); + var cameraPos = []; camera.getPosition(cameraPos); if (camera.getParallelProjection()) { // For parallel projection, use -ve direction of projection - const cameraFocus = []; + var cameraFocus = []; camera.getFocalPoint(cameraFocus); model.pickNormal[0] = cameraPos[0] - cameraFocus[0]; model.pickNormal[1] = cameraPos[1] - cameraFocus[1]; @@ -165,32 +208,27 @@ function vtkCellPicker(publicAPI, model) { model.pickNormal[1] = cameraPos[1] - model.pickPosition[1]; model.pickNormal[2] = cameraPos[2] - model.pickPosition[2]; } - vtkMath.normalize(model.pickNormal); + + normalize(model.pickNormal); } + return pickResult; }; - publicAPI.intersectWithLine = (p1, p2, tol, mapper) => { - let tMin = Number.MAX_VALUE; - const t1 = 0.0; - const t2 = 1.0; - - const vtkCellPickerPlaneTol = 1e-14; - - const clipLine = clipLineWithPlane( - mapper, - model.transformMatrix, - p1, - p2, - t1, - t2 - ); + publicAPI.intersectWithLine = function (p1, p2, tol, mapper) { + var tMin = Number.MAX_VALUE; + var t1 = 0.0; + var t2 = 1.0; + var vtkCellPickerPlaneTol = 1e-14; + var clipLine = clipLineWithPlane(mapper, model.transformMatrix, p1, p2); + if (mapper && !clipLine.intersect) { return Number.MAX_VALUE; } if (mapper.isA('vtkImageMapper') || mapper.isA('vtkImageArrayMapper')) { - const pickData = mapper.intersectWithLineForCellPicking(p1, p2); + var pickData = mapper.intersectWithLineForCellPicking(p1, p2); + if (pickData) { tMin = pickData.t; model.cellIJK = pickData.ijk; @@ -198,153 +236,480 @@ function vtkCellPicker(publicAPI, model) { } } else if (mapper.isA('vtkMapper')) { tMin = publicAPI.intersectActorWithLine(p1, p2, t1, t2, tol, mapper); + } else if (mapper.isA('vtkVolumeMapper')) { + tMin = publicAPI.intersectVolumeWithLine(p1, p2, t1, t2, tol, mapper); } if (tMin < model.globalTMin) { model.globalTMin = tMin; - if ( - Math.abs(tMin - t1) < vtkCellPickerPlaneTol && - clipLine.clippingPlaneId >= 0 - ) { + + if (Math.abs(tMin - t1) < vtkCellPickerPlaneTol && clipLine.clippingPlaneId >= 0) { model.mapperPosition[0] = p1[0] * (1 - t1) + p2[0] * t1; model.mapperPosition[1] = p1[1] * (1 - t1) + p2[1] * t1; model.mapperPosition[2] = p1[2] * (1 - t1) + p2[2] * t1; - const plane = []; - mapper.getClippingPlaneInDataCoords( - model.transformMatrix, - clipLine.clippingPlaneId, - plane - ); - vtkMath.normalize(plane); - // Want normal outward from the planes, not inward + var plane = []; + mapper.getClippingPlaneInDataCoords(model.transformMatrix, clipLine.clippingPlaneId, plane); + normalize(plane); // Want normal outward from the planes, not inward + model.mapperNormal[0] = -plane[0]; model.mapperNormal[1] = -plane[1]; model.mapperNormal[2] = -plane[2]; } - vec3.transformMat4( - model.pickPosition, - model.mapperPosition, - model.transformMatrix - ); - // Transform vector - const mat = model.transformMatrix; - model.mapperNormal[0] = - mat[0] * model.pickNormal[0] + - mat[4] * model.pickNormal[1] + - mat[8] * model.pickNormal[2]; - model.mapperNormal[1] = - mat[1] * model.pickNormal[0] + - mat[5] * model.pickNormal[1] + - mat[9] * model.pickNormal[2]; - model.mapperNormal[2] = - mat[2] * model.pickNormal[0] + - mat[6] * model.pickNormal[1] + - mat[10] * model.pickNormal[2]; + + vec3.transformMat4(model.pickPosition, model.mapperPosition, model.transformMatrix); // Transform vector + + var mat = model.transformMatrix; + model.mapperNormal[0] = mat[0] * model.pickNormal[0] + mat[4] * model.pickNormal[1] + mat[8] * model.pickNormal[2]; + model.mapperNormal[1] = mat[1] * model.pickNormal[0] + mat[5] * model.pickNormal[1] + mat[9] * model.pickNormal[2]; + model.mapperNormal[2] = mat[2] * model.pickNormal[0] + mat[6] * model.pickNormal[1] + mat[10] * model.pickNormal[2]; } + return tMin; }; - publicAPI.intersectActorWithLine = (p1, p2, t1, t2, tol, mapper) => { - let tMin = Number.MAX_VALUE; - const minXYZ = [0, 0, 0]; - let pDistMin = Number.MAX_VALUE; - const minPCoords = [0, 0, 0]; - let minCellId = null; - let minCell = null; - let minCellType = null; - let subId = null; - const x = []; - const data = mapper.getInputData(); - const isPolyData = 1; - - // Make a new p1 and p2 using the clipped t1 and t2 - const q1 = [0, 0, 0]; - const q2 = [0, 0, 0]; + publicAPI.ClipLineWithExtent = function (extent, x1, x2, t1, t2, planeId) { + var bounds = new Array(6); + bounds[0] = extent[0]; + bounds[1] = extent[1]; + bounds[2] = extent[2]; + bounds[3] = extent[3]; + bounds[4] = extent[4]; + bounds[5] = extent[5]; + + var p2; + + return vtkBox.IntersectWithLine(bounds, x1, x2, t1, t2, undefined, undefined, planeId, p2); + } + + publicAPI.computeVolumeOpacity = function(xi, pcoords, data, scalars, scalarOpacity, gradientOpacity) { + var opacity = 1.0; + var weights = new Array(8); + interpolationFunctions(pcoords, weights); + var extent = new Array(6); + extent = data.getExtent(); + var scalarType = data.getScalarType(); + var xInc = 1; + var yInc = extent[1] - extent[0] + 1; + var zInc = yInc * (extent[3] - extent[2] + 1); + + if (xi[0] == extent[1]) { + xInc = 0; + } + + if (xi[1] == extent[3]) { + yInc = 0; + } + + if (xi[2] == extent[5]) { + zInc = 0; + } + + console.log("computeVolumeOpacity Data = ", data); + console.log("computeVolumeOpacity scalars = ", scalars) + var ptId = data.computePointId(xi); + + var val = 0.0 + + console.log("computeVolumeOpacity ptId = ", ptId); + + for (let j = 0; j < 8; j++) { + var ptInc = (j & 1) * xInc + ((j >> 1) & 1) * yInc + ((j >> 2) & 1) * zInc; + console.log("computeVolumeOpacity ptInc = ", ptInc); + val += weights[j] * scalars.getComponent(ptId + ptInc, 0); + } + + // Compute the ScalarOpacity + if (scalarOpacity) + { + opacity *= scalarOpacity.getValue(val); + } + else if (!Number.isInteger(scalarType)) + { + opacity *= val; + } + else + { + // Assume unsigned char + opacity *= val / 255.0; + } + + console.log("computeVolumeOpacity, data = ", data); + + } + + publicAPI.setImageDataPickInfo = function (x, extent) { + console.log("setImageDataPickInfo") + } + + publicAPI.intersectVolumeWithLine = function (p1, p2, t1, t2, tol, mapper) { + var data = mapper.getInputData() + + if (data === undefined) { + return 0 + } + + var spacing = data.getSpacing() + var origin = data.getOrigin() + var extent = data.getExtent() + + var x1 = [] + var x2 = [] + + for (let i = 0; i < 3; i++) { + let x1_data = (p1[i] - origin[i]) / spacing[i]; + let x2_data = (p2[i] - origin[i]) / spacing[i]; + x1.push(x1_data) + x2.push(x2_data) + } + + var planeId; + var s1, s2; + var resultData = publicAPI.ClipLineWithExtent(extent, x1, x2, s1, s2, planeId) + + if (!publicAPI.ClipLineWithExtent(extent, x1, x2, s1, s2, planeId)) + { + return Number.MAX_VALUE; + } + if (s1 >= t1) + { + t1 = s1; + } + if (s2 <= t2) + { + t2 = s2; + } + + // Sanity check + if (t2 < t1) + { + return Number.MAX_VALUE; + } + + // Get the threshold for the opacity + let opacityThreshold = VolumeOpacityIsovalue; + + // // Compute the length of the line intersecting the volume + let rayLength = Math.sqrt(vtkMath.distance2BetweenPoints(x1, x2)) * (t2 - t1); + console.log("rayLength = ", rayLength); + let property = undefined; + + if (volume.getProperty()) { + property = volume.getProperty() + } + + // This is the minimum increment that will be allowed + let tTol = tol / rayLength * (t2 - t1); + + // Find out whether there are multiple components in the volume + let numComponents = data.getNumberOfScalarComponents(); + let independentComponents = 0; + + if (property) + { + independentComponents = property.getIndependentComponents(); + } + + var numIndependentComponents = 1; + if (independentComponents) + { + numIndependentComponents = numComponents; + } + + var dataTypeFromConstants = DataTypeByteSize + var scalars = vtkDataArray.newInstance({ empty: true, + size: dataTypeFromConstants.DataTypeByteSize[data.getScalarType()]}) // TODO research + scalars.setNumberOfComponents(numComponents); + console.log("numComponents = ", numComponents); + + var scalarArraySize = numComponents * data.getNumberOfPoints(); + var scalarSize = dataTypeFromConstants.DataTypeByteSize[data.getScalarType()] // TODO Research + var tMin = Number.MAX_VALUE + + console.log("intersectVolumeWithLine, numIndependentComponents = ", numIndependentComponents); + + for (let component = 0; component < numIndependentComponents; component++) + { + + var scalarOpacity = property ? property.getScalarOpacity(component) : undefined; + var disableGradientOpacity = (property ? property.getDisableGradientOpacity(component): 1) + var gradientOpacity = null + + if (!disableGradientOpacity && UseVolumeGradientOpacity) { + gradientOpacity = property.getGradientOpacity(component); + } + + console.log("intersectVolumeWithLine, gradientOpacity = ", gradientOpacity); + console.log("intersectVolumeWithLine, scalarOpacity = ", scalarOpacity); + + let oComponent = component; + + if (!independentComponents) { + oComponent = numComponents - 1; + } + + var opacity = 0.0; + var lastOpacity = 0.0; + var lastT = t1; + var x = new Array(3); + var pcoords = new Array(3); + var xi = new Array(3); + + var t = t1; + + console.log("intersectVolumeWithLine: t = ", t); + console.log("intersectVolumeWithLine: t2 = ", t2); + console.log("intersectVolumeWithLine: data = ", data); + + + while (t <= t2) { + for (let j = 0; j < 3; j++) + { + // "t" is the fractional distance between endpoints x1 and x2 + x[j] = x1[j] * (1.0 - t) + x2[j] * t; + + // проверяем что эти координаты находятся внутри экстента + // Paranoia bounds check + if (x[j] < extent[2 * j]) + { + x[j] = extent[2 * j]; + } + else if (x[j] > extent[2 * j + 1]) + { + x[j] = extent[2 * j + 1]; + } + + xi[j] = vtkMath.floor(x[j]); + pcoords[j] = x[j] - xi[j]; + } + + opacity = publicAPI.computeVolumeOpacity(xi, pcoords, data, scalars, scalarOpacity, gradientOpacity); + + // If the ray has crossed the isosurface, then terminate the loop + if (opacity > opacityThreshold) + { + break; + } + + lastT = t; + console.log("intersectVolumeWithLine, lastT = ", lastT); + lastOpacity = opacity; + + // Compute the next "t" value that crosses a voxel boundary + t = 1.0; + for (let k = 0; k < 3; k++) + { + // Skip dimension "k" if it is perpendicular to ray + if (Math.abs(x2[k] - x1[k]) > tol * rayLength) + { + // Compute the previous coord along dimension "k" + let lastX = x1[k] * (1.0 - lastT) + x2[k] * lastT; + + // Increment to next slice boundary along dimension "k", + // including a tolerance value for stability in cases + // where lastX is just less than an integer value. + let nextX = 0; + if (x2[k] > x1[k]) + { + nextX = vtkMath.floor(lastX + tol) + 1; + } + else + { + nextX = vtkMath.ceil(lastX - tol) - 1; + } + + // Compute the "t" value for this slice boundary + let ttry = lastT + (nextX - lastX) / (x2[k] - x1[k]); + if (ttry > lastT + tTol && ttry < t) + { + t = ttry; + } + } + } + + // Break if far clipping plane has been reached + if (t >= 1.0) + { + t = 1.0; + break; + } + } + + console.log("IntersectLineWithVolume opacity = ", opacity); + console.log("IntersectLineWitgVolume opacityThreshold = ", opacityThreshold); + + if (opacity > opacityThreshold) + { + // Backtrack to the actual surface position unless this was first step + if (t > t1) + { + let f = (opacityThreshold - lastOpacity) / (opacity - lastOpacity); + t = lastT * (1.0 - f) + t * f; + for (let j = 0; j < 3; j++) + { + x[j] = x1[j] * (1.0 - t) + x2[j] * t; + if (x[j] < extent[2 * j]) + { + x[j] = extent[2 * j]; + } + else if (x[j] > extent[2 * j + 1]) + { + x[j] = extent[2 * j + 1]; + } + xi[j] = vtkMath.floor(x[j]); + pcoords[j] = x[j] - xi[j]; + } + } + + + // Check to see if this is the new global minimum + if (t < tMin && t < model.GlobalTMin) + { + console.log("ResetPickInfo worked!"); + publicAPI.ResetPickInfo(); + tMin = t; + + model.Mapper = mapper; + model.dataSet = data; + + publicAPI.setImageDataPickInfo(x, extent); + + model.mapperPosition[0] = x[0] * spacing[0] + origin[0]; + model.mapperPosition[1] = x[1] * spacing[1] + origin[1]; + model.mapperPosition[2] = x[2] * spacing[2] + origin[2]; + + // Default the normal to the view-plane normal. This default + // will be used if the gradient cannot be computed any other way. + model.mapperNormal[0] = p1[0] - p2[0]; + model.mapperNormal[1] = p1[1] - p2[1]; + model.mapperNormal[2] = p1[2] - p2[2]; + vtkMath.normalize(model.mapperNormal); + + // Check to see if this is the first step, which means that this + // is the boundary of the volume. If this is the case, use the + // normal of the boundary. + if (t == t1 && planeId >= 0 && xi[planeId / 2] == extent[planeId]) + { + model.mapperNormal[0] = 0.0; + model.mapperNormal[1] = 0.0; + model.mapperNormal[2] = 0.0; + model.mapperNormal[planeId / 2] = 2.0 * (planeId % 2) - 1.0; + if (spacing[planeId / 2] < 0) + { + model.mapperNormal[planeId / 2] = model.mapperNormal[planeId / 2]; + } + } + else + { + // research ??? voxel in vtk.js + // // Set the normal from the direction of the gradient + var ci = model.CellIJK; + + var weights = new Array(8); + interpolationFunctions(model.pCoords, weights); + + // data->GetVoxelGradient(ci[0], ci[1], ci[2], scalars, this->Gradients); + // double v[3]; + // v[0] = v[1] = v[2] = 0.0; + // for (int k = 0; k < 8; k++) + // { + // double* pg = this->Gradients->GetTuple(k); + // v[0] += pg[0] * weights[k]; + // v[1] += pg[1] * weights[k]; + // v[2] += pg[2] * weights[k]; + // } + + // double norm = vtkMath::Norm(v); + // if (norm > 0) + // { + // model.mapperNormal[0] = v[0] / norm; + // model.mapperNormal[1] = v[1] / norm; + // model.MapperNormal[2] = v[2] / norm; + // } + } + } // End of "if (opacity > opacityThreshold)" + } // End of "if (t < tMin && t < this->GlobalTMin)" + } // End of loop over volume components + + scalars.delete(); + console.log("tMin after rayCastLoop, tMin = ", tMin); + return tMin; + } + + publicAPI.intersectActorWithLine = function (p1, p2, t1, t2, tol, mapper) { + var tMin = Number.MAX_VALUE; + var minXYZ = [0, 0, 0]; + var pDistMin = Number.MAX_VALUE; + var minPCoords = [0, 0, 0]; + var minCellId = null; + var minCell = null; + var minCellType = null; + var subId = null; + var x = []; + var data = mapper.getInputData(); + + var q1 = [0, 0, 0]; + var q2 = [0, 0, 0]; q1[0] = p1[0]; q1[1] = p1[1]; q1[2] = p1[2]; q2[0] = p2[0]; q2[1] = p2[1]; q2[2] = p2[2]; + if (t1 !== 0.0 || t2 !== 1.0) { - for (let j = 0; j < 3; j++) { + for (var j = 0; j < 3; j++) { q1[j] = p1[j] * (1.0 - t1) + p2[j] * t1; q2[j] = p1[j] * (1.0 - t2) + p2[j] * t2; } } - const locator = null; - if (locator) { - // TODO when cell locator will be implemented - } else if (data.getCells) { + if (data.getCells) { if (!data.getCells()) { data.buildLinks(); } - const tempCellMap = createCellMap(); - const minCellMap = createCellMap(); - - const numberOfCells = data.getNumberOfCells(); - + var tempCellMap = createCellMap(); + var minCellMap = createCellMap(); + var numberOfCells = data.getNumberOfCells(); /* eslint-disable no-continue */ - for (let cellId = 0; cellId < numberOfCells; cellId++) { - const pCoords = [0, 0, 0]; - minCellType = data.getCellType(cellId); + for (var cellId = 0; cellId < numberOfCells; cellId++) { + var pCoords = [0, 0, 0]; + minCellType = data.getCellType(cellId); // Skip cells that are marked as empty - // Skip cells that are marked as empty if (minCellType === CellType.VTK_EMPTY_CELL) { continue; } - const cell = tempCellMap[minCellType]; + var cell = tempCellMap[minCellType]; if (cell == null) { continue; } minCell = minCellMap[minCellType]; - data.getCell(cellId, cell); + var cellPicked = void 0; - let cellPicked; - - if (isPolyData) { + { if (vtkCellTypes.hasSubCells(minCellType)) { - cellPicked = cell.intersectWithLine( - t1, - t2, - p1, - p2, - tol, - x, - pCoords - ); + cellPicked = cell.intersectWithLine(t1, t2, p1, p2, tol, x, pCoords); } else { cellPicked = cell.intersectWithLine(p1, p2, tol, x, pCoords); } - } else { - cellPicked = cell.intersectWithLine(q1, q2, tol, x, pCoords); - if (t1 !== 0.0 || t2 !== 1.0) { - cellPicked.t = t1 * (1.0 - cellPicked.t) + t2 * cellPicked.t; - } } - if ( - cellPicked.intersect === 1 && - cellPicked.t <= tMin + model.tolerance && - cellPicked.t >= t1 && - cellPicked.t <= t2 - ) { - const pDist = cell.getParametricDistance(pCoords); + if (cellPicked.intersect === 1 && cellPicked.t <= tMin + model.tolerance && cellPicked.t >= t1 && cellPicked.t <= t2) { + var pDist = cell.getParametricDistance(pCoords); - if (pDist < pDistMin || (pDist === pDistMin && cellPicked.t < tMin)) { + if (pDist < pDistMin || pDist === pDistMin && cellPicked.t < tMin) { tMin = cellPicked.t; pDistMin = pDist; subId = cellPicked.subId; minCellId = cellId; cell.deepCopy(minCell); - for (let k = 0; k < 3; k++) { + + for (var k = 0; k < 3; k++) { minXYZ[k] = x[k]; minPCoords[k] = pCoords[k]; } @@ -352,107 +717,91 @@ function vtkCellPicker(publicAPI, model) { } } /* eslint-enable no-continue */ + } if (minCellId >= 0 && tMin < model.globalTMin) { resetPickInfo(); - const nbPointsInCell = minCell.getNumberOfPoints(); - const weights = new Array(nbPointsInCell); - for (let i = 0; i < nbPointsInCell; i++) { + var nbPointsInCell = minCell.getNumberOfPoints(); + var weights = new Array(nbPointsInCell); + + for (var i = 0; i < nbPointsInCell; i++) { weights[i] = 0.0; } - const point = []; + + var point = []; if (vtkCellTypes.hasSubCells(minCellType)) { minCell.evaluateLocation(subId, minPCoords, point, weights); } else { minCell.evaluateLocation(minPCoords, point, weights); - } + } // Return the polydata to the user + - // Return the polydata to the user model.dataSet = data; model.cellId = minCellId; model.pCoords[0] = minPCoords[0]; model.pCoords[1] = minPCoords[1]; - model.pCoords[2] = minPCoords[2]; - - // Find the point with the maximum weight - let maxWeight = 0; - let iMaxWeight = -1; - for (let i = 0; i < nbPointsInCell; i++) { - if (weights[i] > maxWeight) { - iMaxWeight = i; - maxWeight = weights[i]; + model.pCoords[2] = minPCoords[2]; // Find the point with the maximum weight + + var maxWeight = 0; + var iMaxWeight = -1; + + for (var _i = 0; _i < nbPointsInCell; _i++) { + if (weights[_i] > maxWeight) { + iMaxWeight = _i; + maxWeight = weights[_i]; } - } + } // If maximum weight is found, use it to get the PointId + - // If maximum weight is found, use it to get the PointId if (iMaxWeight !== -1) { model.pointId = minCell.getPointsIds()[iMaxWeight]; - } + } // Set the mapper position + - // Set the mapper position model.mapperPosition[0] = minXYZ[0]; model.mapperPosition[1] = minXYZ[1]; - model.mapperPosition[2] = minXYZ[2]; - - // Compute the normal - if ( - !publicAPI.computeSurfaceNormal( - data, - minCell, - weights, - model.mapperNormal - ) - ) { + model.mapperPosition[2] = minXYZ[2]; // Compute the normal + + if (!publicAPI.computeSurfaceNormal(data, minCell, weights, model.mapperNormal)) { // By default, the normal points back along view ray model.mapperNormal[0] = p1[0] - p2[0]; model.mapperNormal[1] = p1[1] - p2[1]; model.mapperNormal[2] = p1[2] - p2[2]; - vtkMath.normalize(model.mapperNormal); + normalize(model.mapperNormal); } } return tMin; }; -} - -// ---------------------------------------------------------------------------- +} // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- -const DEFAULT_VALUES = { +var DEFAULT_VALUES = { cellId: -1, pCoords: [], cellIJK: [], pickNormal: [], - mapperNormal: [], -}; - -// ---------------------------------------------------------------------------- + mapperNormal: [] +}; // ---------------------------------------------------------------------------- +function extend(publicAPI, model) { + var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + Object.assign(model, DEFAULT_VALUES, initialValues); // Inheritance -export function extend(publicAPI, model, initialValues = {}) { - Object.assign(model, DEFAULT_VALUES, initialValues); - - // Inheritance vtkPicker.extend(publicAPI, model, initialValues); + macro.getArray(publicAPI, model, ['pickNormal', 'mapperNormal', 'pCoords', 'cellIJK']); + macro.get(publicAPI, model, ['cellId']); // Object methods - macro.getArray(publicAPI, model, [ - 'pickNormal', - 'mapperNormal', - 'pCoords', - 'cellIJK', - ]); - macro.get(publicAPI, model, ['cellId']); - - // Object methods vtkCellPicker(publicAPI, model); -} - -// ---------------------------------------------------------------------------- +} // ---------------------------------------------------------------------------- -export const newInstance = macro.newInstance(extend, 'vtkCellPicker'); +var newInstance = macro.newInstance(extend, 'vtkCellPicker'); // ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- +var vtkCellPicker$1 = _objectSpread({ + newInstance: newInstance, + extend: extend +}, STATIC); -export default { newInstance, extend, ...STATIC }; +export { STATIC, vtkCellPicker$1 as default, extend, newInstance }; diff --git a/Sources/Rendering/Core/VolumeProperty/index.js b/Sources/Rendering/Core/VolumeProperty/index.js index 92b1e7051f8..cb0cba1d006 100644 --- a/Sources/Rendering/Core/VolumeProperty/index.js +++ b/Sources/Rendering/Core/VolumeProperty/index.js @@ -1,13 +1,16 @@ -import macro from 'vtk.js/Sources/macros'; -import vtkColorTransferFunction from 'vtk.js/Sources/Rendering/Core/ColorTransferFunction'; -import vtkPiecewiseFunction from 'vtk.js/Sources/Common/DataModel/PiecewiseFunction'; -import Constants from 'vtk.js/Sources/Rendering/Core/VolumeProperty/Constants'; - -const { InterpolationType, OpacityMode } = Constants; -const { vtkErrorMacro } = macro; - -const VTK_MAX_VRCOMP = 4; - +import _defineProperty from '@babel/runtime/helpers/defineProperty'; +import macro from '../../macros.js'; +import vtkColorTransferFunction from './ColorTransferFunction.js'; +import vtkPiecewiseFunction from '../../Common/DataModel/PiecewiseFunction.js'; +import Constants from './VolumeProperty/Constants.js'; + +function ownKeys(object, enumerableOnly) { var keys = Object.keys(object); if (Object.getOwnPropertySymbols) { var symbols = Object.getOwnPropertySymbols(object); enumerableOnly && (symbols = symbols.filter(function (sym) { return Object.getOwnPropertyDescriptor(object, sym).enumerable; })), keys.push.apply(keys, symbols); } return keys; } + +function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = null != arguments[i] ? arguments[i] : {}; i % 2 ? ownKeys(Object(source), !0).forEach(function (key) { _defineProperty(target, key, source[key]); }) : Object.getOwnPropertyDescriptors ? Object.defineProperties(target, Object.getOwnPropertyDescriptors(source)) : ownKeys(Object(source)).forEach(function (key) { Object.defineProperty(target, key, Object.getOwnPropertyDescriptor(source, key)); }); } return target; } +var InterpolationType = Constants.InterpolationType, + OpacityMode = Constants.OpacityMode; +var vtkErrorMacro = macro.vtkErrorMacro; +var VTK_MAX_VRCOMP = 4; // ---------------------------------------------------------------------------- // vtkVolumeProperty methods // ---------------------------------------------------------------------------- @@ -16,12 +19,13 @@ function vtkVolumeProperty(publicAPI, model) { // Set our className model.classHierarchy.push('vtkVolumeProperty'); - publicAPI.getMTime = () => { - let mTime = model.mtime; - let time; + publicAPI.getMTime = function () { + var mTime = model.mtime; + var time; - for (let index = 0; index < VTK_MAX_VRCOMP; index++) { - // Color MTimes + for (var index = 0; index < VTK_MAX_VRCOMP; index++) { + + // Color MTimes if (model.componentData[index].colorChannels === 1) { if (model.componentData[index].grayTransferFunction) { // time that Gray transfer function was last modified @@ -34,11 +38,11 @@ function vtkVolumeProperty(publicAPI, model) { time = model.componentData[index].rGBTransferFunction.getMTime(); mTime = mTime > time ? mTime : time; } - } + } // Opacity MTimes + - // Opacity MTimes if (model.componentData[index].scalarOpacity) { - // time that Scalar opacity transfer function was last modified + // time that Scalar opаacity transfer function was last modified time = model.componentData[index].scalarOpacity.getMTime(); mTime = mTime > time ? mTime : time; } @@ -50,23 +54,99 @@ function vtkVolumeProperty(publicAPI, model) { mTime = mTime > time ? mTime : time; } } + + } return mTime; }; - publicAPI.getColorChannels = (index) => { + publicAPI.getDisableGradientOpacity = function (index) { + return model.componentData[index].DisableGradientOpacity; + } + + publicAPI.getGradientOpacity = function (index) { + if (model.componentData[index].disableGradientOpacity) { + if (!model.componentData[index].defaultGradientOpacity) { + publicAPI.createDefaultGradientOpacity(index); + } + return publicAPI.defaultGradientOpacity[index]; + } + return publicAPI.getStoredGradientOpacity(index); + } + + publicAPI.getStoredGradientOpacity = function (index) { + if (model.componentData[index]) { + model.componentData[index].gradientOpacity = vtkPiecewiseFunction.newInstance(); + model.componentData[index].gradientOpacity.addPoint(0, 1.0); + model.componentData[index].gradientOpacity.addPoint(255, 1.0); + } + + return model.componentData[index].gradientOpacity; + } + + publicAPI.setDisableGradientOpacity = function (index, value) { + if (model.componentData[index].disableGradientOpacity == value) { + return; + } + + model.componentData[index].disableGradientOpacity = value; + + if (value) { + publicAPI.createDefaultGradientOpacity(index); + } + + + /* + if (this->DisableGradientOpacity[index] == value) + { + return; + } + + this->DisableGradientOpacity[index] = value; + + // Make sure the default function is up-to-date (since the user + // could have modified the default function) + + if (value) + { + this->CreateDefaultGradientOpacity(index); + } + + // Since this Ivar basically "sets" the gradient opacity function to be + // either a default one or the user-specified one, update the MTime + // accordingly + + this->GradientOpacityMTime[index].Modified(); + + this->Modified(); + */ + } + + publicAPI.createDefaultGradientOpacity = function (index) { + if (!model.componentData[index].defaultGradientOpacity) { + model.componentData[index].defaultGradientOpacity = vtkPiecewiseFunction.newInstance(); + // research about register. + } + + model.componentData[index].defaultGradientOpacity.removeAllPoints(); + model.componentData[index].defaultGradientOpacity.addPoint(0, 1.0); + model.componentData[index].defaultGradientOpacity.addPoint(255, 1.0); + } + + publicAPI.getColorChannels = function (index) { if (index < 0 || index > 3) { vtkErrorMacro('Bad index - must be between 0 and 3'); return 0; } return model.componentData[index].colorChannels; - }; + }; // Set the color of a volume to a gray transfer function + + + publicAPI.setGrayTransferFunction = function (index, func) { + var modified = false; - // Set the color of a volume to a gray transfer function - publicAPI.setGrayTransferFunction = (index, func) => { - let modified = false; if (model.componentData[index].grayTransferFunction !== func) { model.componentData[index].grayTransferFunction = func; modified = true; @@ -80,28 +160,31 @@ function vtkVolumeProperty(publicAPI, model) { if (modified) { publicAPI.modified(); } + return modified; - }; + }; // Get the currently set gray transfer function. Create one if none set. + - // Get the currently set gray transfer function. Create one if none set. - publicAPI.getGrayTransferFunction = (index) => { + publicAPI.getGrayTransferFunction = function (index) { if (model.componentData[index].grayTransferFunction === null) { - model.componentData[index].grayTransferFunction = - vtkPiecewiseFunction.newInstance(); + model.componentData[index].grayTransferFunction = vtkPiecewiseFunction.newInstance(); model.componentData[index].grayTransferFunction.addPoint(0, 0.0); model.componentData[index].grayTransferFunction.addPoint(1024, 1.0); + if (model.componentData[index].colorChannels !== 1) { model.componentData[index].colorChannels = 1; } + publicAPI.modified(); } return model.componentData[index].grayTransferFunction; - }; + }; // Set the color of a volume to an RGB transfer function + + + publicAPI.setRGBTransferFunction = function (index, func) { + var modified = false; - // Set the color of a volume to an RGB transfer function - publicAPI.setRGBTransferFunction = (index, func) => { - let modified = false; if (model.componentData[index].rGBTransferFunction !== func) { model.componentData[index].rGBTransferFunction = func; modified = true; @@ -115,50 +198,42 @@ function vtkVolumeProperty(publicAPI, model) { if (modified) { publicAPI.modified(); } + return modified; - }; + }; // Get the currently set RGB transfer function. Create one if none set. - // Get the currently set RGB transfer function. Create one if none set. - publicAPI.getRGBTransferFunction = (index) => { + + publicAPI.getRGBTransferFunction = function (index) { if (model.componentData[index].rGBTransferFunction === null) { - model.componentData[index].rGBTransferFunction = - vtkColorTransferFunction.newInstance(); - model.componentData[index].rGBTransferFunction.addRGBPoint( - 0, - 0.0, - 0.0, - 0.0 - ); - model.componentData[index].rGBTransferFunction.addRGBPoint( - 1024, - 1.0, - 1.0, - 1.0 - ); + model.componentData[index].rGBTransferFunction = vtkColorTransferFunction.newInstance(); + model.componentData[index].rGBTransferFunction.addRGBPoint(0, 0.0, 0.0, 0.0); + model.componentData[index].rGBTransferFunction.addRGBPoint(1024, 1.0, 1.0, 1.0); + if (model.componentData[index].colorChannels !== 3) { model.componentData[index].colorChannels = 3; } + publicAPI.modified(); } return model.componentData[index].rGBTransferFunction; - }; + }; // Set the scalar opacity of a volume to a transfer function + - // Set the scalar opacity of a volume to a transfer function - publicAPI.setScalarOpacity = (index, func) => { + publicAPI.setScalarOpacity = function (index, func) { if (model.componentData[index].scalarOpacity !== func) { model.componentData[index].scalarOpacity = func; publicAPI.modified(); return true; } + return false; - }; + }; // Get the scalar opacity transfer function. Create one if none set. + - // Get the scalar opacity transfer function. Create one if none set. - publicAPI.getScalarOpacity = (index) => { + publicAPI.getScalarOpacity = function (index) { if (model.componentData[index].scalarOpacity === null) { - model.componentData[index].scalarOpacity = - vtkPiecewiseFunction.newInstance(); + model.componentData[index].scalarOpacity = vtkPiecewiseFunction.newInstance(); model.componentData[index].scalarOpacity.addPoint(0, 1.0); model.componentData[index].scalarOpacity.addPoint(1024, 1.0); publicAPI.modified(); @@ -167,22 +242,24 @@ function vtkVolumeProperty(publicAPI, model) { return model.componentData[index].scalarOpacity; }; - publicAPI.setComponentWeight = (index, value) => { + publicAPI.setComponentWeight = function (index, value) { if (index < 0 || index >= VTK_MAX_VRCOMP) { vtkErrorMacro('Invalid index'); return false; } - const val = Math.min(1, Math.max(0, value)); + var val = Math.min(1, Math.max(0, value)); + if (model.componentData[index].componentWeight !== val) { model.componentData[index].componentWeight = val; publicAPI.modified(); return true; } + return false; }; - publicAPI.getComponentWeight = (index) => { + publicAPI.getComponentWeight = function (index) { if (index < 0 || index >= VTK_MAX_VRCOMP) { vtkErrorMacro('Invalid index'); return 0.0; @@ -191,59 +268,50 @@ function vtkVolumeProperty(publicAPI, model) { return model.componentData[index].componentWeight; }; - publicAPI.setInterpolationTypeToNearest = () => - publicAPI.setInterpolationType(InterpolationType.NEAREST); - - publicAPI.setInterpolationTypeToLinear = () => - publicAPI.setInterpolationType(InterpolationType.LINEAR); - - publicAPI.setInterpolationTypeToFastLinear = () => - publicAPI.setInterpolationType(InterpolationType.FAST_LINEAR); - - publicAPI.getInterpolationTypeAsString = () => - macro.enumToString(InterpolationType, model.interpolationType); - - const sets = [ - 'useGradientOpacity', - 'scalarOpacityUnitDistance', - 'gradientOpacityMinimumValue', - 'gradientOpacityMinimumOpacity', - 'gradientOpacityMaximumValue', - 'gradientOpacityMaximumOpacity', - 'opacityMode', - ]; - sets.forEach((val) => { - const cap = macro.capitalize(val); - publicAPI[`set${cap}`] = (index, value) => { - if (model.componentData[index][`${val}`] !== value) { - model.componentData[index][`${val}`] = value; + publicAPI.setInterpolationTypeToNearest = function () { + return publicAPI.setInterpolationType(InterpolationType.NEAREST); + }; + + publicAPI.setInterpolationTypeToLinear = function () { + return publicAPI.setInterpolationType(InterpolationType.LINEAR); + }; + + publicAPI.setInterpolationTypeToFastLinear = function () { + return publicAPI.setInterpolationType(InterpolationType.FAST_LINEAR); + }; + + publicAPI.getInterpolationTypeAsString = function () { + return macro.enumToString(InterpolationType, model.interpolationType); + }; + + var sets = ['useGradientOpacity', 'scalarOpacityUnitDistance', 'gradientOpacityMinimumValue', 'gradientOpacityMinimumOpacity', 'gradientOpacityMaximumValue', 'gradientOpacityMaximumOpacity', 'opacityMode']; + sets.forEach(function (val) { + var cap = macro.capitalize(val); + + publicAPI["set".concat(cap)] = function (index, value) { + if (model.componentData[index]["".concat(val)] !== value) { + model.componentData[index]["".concat(val)] = value; publicAPI.modified(); return true; } + return false; }; }); + var gets = ['useGradientOpacity', 'scalarOpacityUnitDistance', 'gradientOpacityMinimumValue', 'gradientOpacityMinimumOpacity', 'gradientOpacityMaximumValue', 'gradientOpacityMaximumOpacity', 'opacityMode']; + gets.forEach(function (val) { + var cap = macro.capitalize(val); - const gets = [ - 'useGradientOpacity', - 'scalarOpacityUnitDistance', - 'gradientOpacityMinimumValue', - 'gradientOpacityMinimumOpacity', - 'gradientOpacityMaximumValue', - 'gradientOpacityMaximumOpacity', - 'opacityMode', - ]; - gets.forEach((val) => { - const cap = macro.capitalize(val); - publicAPI[`get${cap}`] = (index) => model.componentData[index][`${val}`]; + publicAPI["get".concat(cap)] = function (index) { + return model.componentData[index]["".concat(val)]; + }; }); -} - -// ---------------------------------------------------------------------------- +} // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- -const DEFAULT_VALUES = { + +var DEFAULT_VALUES = { independentComponents: true, interpolationType: InterpolationType.FAST_LINEAR, shade: false, @@ -253,60 +321,49 @@ const DEFAULT_VALUES = { specularPower: 10.0, useLabelOutline: false, labelOutlineThickness: 1, - labelOutlineOpacity: 1.0, -}; + labelOutlineOpacity: 1.0 +}; // ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- - -export function extend(publicAPI, model, initialValues = {}) { - Object.assign(model, DEFAULT_VALUES, initialValues); +function extend(publicAPI, model) { + var initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; + Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API - // Build VTK API macro.obj(publicAPI, model); if (!model.componentData) { model.componentData = []; - for (let i = 0; i < VTK_MAX_VRCOMP; ++i) { + + for (var i = 0; i < VTK_MAX_VRCOMP; ++i) { model.componentData.push({ colorChannels: 1, grayTransferFunction: null, - rGBTransferFunction: null, + rGBTransferFunction: null, scalarOpacity: null, scalarOpacityUnitDistance: 1.0, opacityMode: OpacityMode.FRACTIONAL, - gradientOpacityMinimumValue: 0, gradientOpacityMinimumOpacity: 0.0, gradientOpacityMaximumValue: 1.0, gradientOpacityMaximumOpacity: 1.0, useGradientOpacity: false, - componentWeight: 1.0, + disableGradientOpacity: 0, + gradientOpacity: null, + defaultGradientOpacity: null, }); } } - macro.setGet(publicAPI, model, [ - 'independentComponents', - 'interpolationType', - 'shade', - 'ambient', - 'diffuse', - 'specular', - 'specularPower', - 'useLabelOutline', - 'labelOutlineThickness', - 'labelOutlineOpacity', - ]); - - // Object methods - vtkVolumeProperty(publicAPI, model); -} + macro.setGet(publicAPI, model, ['independentComponents', 'interpolationType', 'shade', 'ambient', 'diffuse', 'specular', 'specularPower', 'useLabelOutline', 'labelOutlineThickness', 'labelOutlineOpacity']); // Object methods -// ---------------------------------------------------------------------------- + vtkVolumeProperty(publicAPI, model); +} // ---------------------------------------------------------------------------- -export const newInstance = macro.newInstance(extend, 'vtkVolumeProperty'); +var newInstance = macro.newInstance(extend, 'vtkVolumeProperty'); // ---------------------------------------------------------------------------- -// ---------------------------------------------------------------------------- +var vtkVolumeProperty$1 = _objectSpread({ + newInstance: newInstance, + extend: extend +}, Constants); -export default { newInstance, extend, ...Constants }; +export { vtkVolumeProperty$1 as default, extend, newInstance }; From ab29c4eb107c6855caecebfb0ddc7912d731c64a Mon Sep 17 00:00:00 2001 From: "danil.mazurkin" Date: Mon, 7 Aug 2023 18:35:42 +1000 Subject: [PATCH 2/2] Add new function to ImageData --- Sources/Common/DataModel/ImageData/index.js | 98 ++++++++++++++++++++- 1 file changed, 97 insertions(+), 1 deletion(-) diff --git a/Sources/Common/DataModel/ImageData/index.js b/Sources/Common/DataModel/ImageData/index.js index 993e6261e2f..018dda2f078 100644 --- a/Sources/Common/DataModel/ImageData/index.js +++ b/Sources/Common/DataModel/ImageData/index.js @@ -270,7 +270,103 @@ function vtkImageData(publicAPI, model) { }; publicAPI.getPointGradient = function(i, j, k, s, g) { - console.log("soon..") + var ar = model.spacing; + var sp, sm; + var extent = model.extent; + + var dims = publicAPI.getDimensions(); + var ijsize = dims[0] * dims[1]; + + // Adjust i,j,k to the start of the extent + i -= extent[0]; + j -= extent[2]; + k -= extent[4]; + + // Check for out-of-bounds + if (i < 0 || i >= dims[0] || j < 0 || j >= dims[1] || k < 0 || k >= dims[2]) + { + g[0] = g[1] = g[2] = 0.0; + return; + } + + // i-axis + if (dims[0] == 1) + { + g[0] = 0.0; + } + else if (i == 0) + { + sp = s.getComponent(i + 1 + j * dims[0] + k * ijsize, 0); + sm = s.getComponent(i + j * dims[0] + k * ijsize, 0); + g[0] = (sm - sp) / ar[0]; + } + else if (i == (dims[0] - 1)) + { + sp = s.getComponent(i + j * dims[0] + k * ijsize, 0); + sm = s.getComponent(i - 1 + j * dims[0] + k * ijsize, 0); + g[0] = (sm - sp) / ar[0]; + } + else + { + sp = s.getComponent(i + 1 + j * dims[0] + k * ijsize, 0); + sm = s.getComponent(i - 1 + j * dims[0] + k * ijsize, 0); + g[0] = 0.5 * (sm - sp) / ar[0]; + } + + // j-axis + if (dims[1] == 1) + { + g[1] = 0.0; + } + else if (j == 0) + { + sp = s.getComponent(i + (j + 1) * dims[0] + k * ijsize, 0); + sm = s.getComponent(i + j * dims[0] + k * ijsize, 0); + g[1] = (sm - sp) / ar[1]; + } + else if (j == (dims[1] - 1)) + { + sp = s.getComponent(i + j * dims[0] + k * ijsize, 0); + sm = s.getComponent(i + (j - 1) * dims[0] + k * ijsize, 0); + g[1] = (sm - sp) / ar[1]; + } + else + { + sp = s.getComponent(i + (j + 1) * dims[0] + k * ijsize, 0); + sm = s.getComponent(i + (j - 1) * dims[0] + k * ijsize, 0); + g[1] = 0.5 * (sm - sp) / ar[1]; + } + + // k-axis + if (dims[2] == 1) + { + g[2] = 0.0; + } + else if (k == 0) + { + sp = s.getComponent(i + j * dims[0] + (k + 1) * ijsize, 0); + sm = s.getComponent(i + j * dims[0] + k * ijsize, 0); + g[2] = (sm - sp) / ar[2]; + } + else if (k == (dims[2] - 1)) + { + sp = s.getComponent(i + j * dims[0] + k * ijsize, 0); + sm = s.getComponent(i + j * dims[0] + (k - 1) * ijsize, 0); + g[2] = (sm - sp) / ar[2]; + } + else + { + sp = s.getComponent(i + j * dims[0] + (k + 1) * ijsize, 0); + sm = s.getComponent(i + j * dims[0] + (k - 1) * ijsize, 0); + g[2] = 0.5 * (sm - sp) / ar[2]; + } + + // Apply direction transform to get in xyz coordinate system + // Note: we already applied the spacing when handling the ijk + // axis above, and do not need to translate by the origin + // since this is a gradient computation + /// ??? + // this->DirectionMatrix->MultiplyPoint(g, g); } publicAPI.getVoxelGradient = function (i, j, k, s, g) {