Skip to content

Commit 24a81a9

Browse files
authored
Merge pull request #3240 from Kitware/update-beta
Update beta
2 parents 7b411e8 + bf98788 commit 24a81a9

File tree

40 files changed

+1045
-148
lines changed

40 files changed

+1045
-148
lines changed

Sources/Common/Core/DataArray/index.d.ts

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,23 @@ export interface vtkDataArray extends vtkObject {
8383
*/
8484
setRange(rangeValue: vtkRange, componentIndex: number): Range;
8585

86+
/**
87+
* Returns an array of the ranges for each component of the DataArray.
88+
* Defaults to computing all the ranges if they aren't already computed.
89+
*
90+
* If the number of components is greater than 1, the last element in the
91+
* ranges array is the min,max magnitude of the dataset. This is the same as
92+
* calling `getRange(-1)`.
93+
*
94+
* Passing `getRanges(false)` will return a clone of the ranges that have
95+
* already been computed. This is useful when you want to avoid recomputing
96+
* the ranges, which can be expensive.
97+
*
98+
* @param {boolean} [computeRanges] (default: true)
99+
* @returns {vtkRange[]}
100+
*/
101+
getRanges(computeRanges: boolean): vtkRange[];
102+
86103
/**
87104
* Set the given tuple at the given index.
88105
* @param {Number} idx

Sources/Common/Core/DataArray/index.js

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,35 @@ function vtkDataArray(publicAPI, model) {
281281
return model.rangeTuple;
282282
};
283283

284+
publicAPI.getRanges = (computeRanges = true) => {
285+
if (!computeRanges) {
286+
return structuredClone(model.ranges);
287+
}
288+
/** @type {import('../../../interfaces').vtkRange[]} */
289+
const ranges = [];
290+
for (let i = 0; i < model.numberOfComponents; i++) {
291+
const [min, max] = publicAPI.getRange(i);
292+
/** @type {import('../../../interfaces').vtkRange} */
293+
const range = {
294+
min,
295+
max,
296+
};
297+
ranges.push(range);
298+
}
299+
// where the number of components is greater than 1, the last element in
300+
// the range array is the min,max magnitude of the entire dataset.
301+
if (model.numberOfComponents > 1) {
302+
const [min, max] = publicAPI.getRange(-1);
303+
/** @type {import('../../../interfaces').vtkRange} */
304+
const range = {
305+
min,
306+
max,
307+
};
308+
ranges.push(range);
309+
}
310+
return ranges;
311+
};
312+
284313
publicAPI.setTuple = (idx, tuple) => {
285314
const offset = idx * model.numberOfComponents;
286315
for (let i = 0; i < model.numberOfComponents; i++) {
@@ -447,12 +476,18 @@ function vtkDataArray(publicAPI, model) {
447476
return sortedObj;
448477
};
449478

479+
/**
480+
* @param {import("./index").vtkDataArray} other
481+
*/
450482
publicAPI.deepCopy = (other) => {
451483
// Retain current dataType and array reference before shallowCopy call.
452484
const currentType = publicAPI.getDataType();
453485
const currentArray = model.values;
454486
publicAPI.shallowCopy(other);
455487

488+
// set the ranges
489+
model.ranges = structuredClone(other.getRanges());
490+
456491
// Avoid array reallocation if size already sufficient
457492
// and dataTypes match.
458493
if (

Sources/Common/Core/DataArray/test/testDataArray.js

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,36 @@ test('Test vtkDataArray getRange function with NaN values.', (t) => {
131131
t.end();
132132
});
133133

134+
test('Test vtkDataArray getRanges function with single-channel data.', (t) => {
135+
// create a data array with a single channel.
136+
const newArray = new Uint16Array(256 * 3);
137+
138+
// fill the new array with the pattern 0,1,2,3,4,5, ..., 767.
139+
for (let i = 0; i < 256 * 3; ++i) {
140+
newArray[i] = i;
141+
}
142+
143+
const da = vtkDataArray.newInstance({
144+
numberOfComponents: 1,
145+
values: newArray,
146+
});
147+
148+
t.ok(
149+
da.getRanges().length === 1,
150+
'getRanges should return an array of 1 vtkRange objects'
151+
);
152+
t.ok(
153+
da.getRanges()[0].min === 0,
154+
'the first component returned by getRanges minimum value should be 0'
155+
);
156+
t.ok(
157+
da.getRanges()[0].max === 767,
158+
'the first component returned by getRanges maximum value should be 767'
159+
);
160+
161+
t.end();
162+
});
163+
134164
test('Test vtkDataArray getTuple', (t) => {
135165
const da = vtkDataArray.newInstance({
136166
numberOfComponents: 3,
@@ -202,6 +232,98 @@ test('Test vtkDataArray getRange function with multi-channel data.', (t) => {
202232
t.end();
203233
});
204234

235+
test('Test vtkDataArray getRanges function with multi-channel data.', (t) => {
236+
// create a data array with 3 channel data.
237+
const numberOfPixels = 10;
238+
const numberOfComponents = 4;
239+
const newArray = new Uint16Array(numberOfPixels * numberOfComponents);
240+
241+
// fill the new array with the pattern 1,2,3, 1,2,3
242+
// such that each channel has 1,1,1 2,2,2 3,3,3 respectively.
243+
for (let i = 0; i < numberOfPixels; ++i) {
244+
newArray[i * numberOfComponents] = i;
245+
newArray[i * numberOfComponents + 1] = i * 2;
246+
newArray[i * numberOfComponents + 2] = i * 3;
247+
newArray[i * numberOfComponents + 3] = i * 4;
248+
}
249+
250+
const da = vtkDataArray.newInstance({
251+
numberOfComponents,
252+
values: newArray,
253+
});
254+
255+
const ranges = da.getRanges();
256+
257+
t.ok(
258+
ranges.length === numberOfComponents + 1,
259+
'getRanges should return an array of 5 vtkRange objects'
260+
);
261+
t.ok(ranges[0].min === 0, 'component:0 minimum value should be 0');
262+
t.ok(ranges[0].max === 9, 'component:0 maximum value should be 9');
263+
t.ok(ranges[1].min === 0, 'component:1 minimum value should be 0');
264+
t.ok(ranges[1].max === 18, 'component:1 maximum value should be 18');
265+
t.ok(ranges[2].min === 0, 'component:2 minimum value should be 0');
266+
t.ok(ranges[2].max === 27, 'component:2 maximum value should be 27 ');
267+
t.ok(
268+
ranges[2].min === 0,
269+
'component:-1 vector magnitude minimum should be 0'
270+
);
271+
t.ok(
272+
ranges[3].max === 36,
273+
'component:-1 vector magnitude maximum should be 36'
274+
);
275+
276+
t.end();
277+
});
278+
279+
test('Test vtkDataArray getRanges(false) (`computeRanges=false`) function with multi-channel data', (t) => {
280+
// create a data array with 3 channel data.
281+
const numberOfPixels = 10;
282+
const numberOfComponents = 4;
283+
const newArray = new Uint16Array(numberOfPixels * numberOfComponents);
284+
285+
// fill the new array with the pattern 1,2,3, 1,2,3
286+
// such that each channel has 1,1,1 2,2,2 3,3,3 respectively.
287+
for (let i = 0; i < numberOfPixels; ++i) {
288+
newArray[i * numberOfComponents] = i;
289+
newArray[i * numberOfComponents + 1] = i * 2;
290+
newArray[i * numberOfComponents + 2] = i * 3;
291+
newArray[i * numberOfComponents + 3] = i * 4;
292+
}
293+
294+
const da = vtkDataArray.newInstance({
295+
numberOfComponents,
296+
values: newArray,
297+
});
298+
299+
// set `computeRanges` to false. This will prevent the ranges from being
300+
// computed and will return only the ranges previously computer (if any).
301+
const ranges = da.getRanges(false);
302+
303+
t.ok(ranges === undefined, `getRanges should return undefined`);
304+
305+
// now fetch the range for component 0.
306+
da.getRange(0);
307+
308+
// now fetch the ranges again with `computeRanges` set to false.
309+
const updatedRanges = da.getRanges(false);
310+
311+
// `updatedRanges` should now be only the range for component 0. because if
312+
// was computed in `da.getRange(0)`
313+
t.ok(
314+
updatedRanges.length === numberOfComponents + 1,
315+
'getRanges should return an array of 5 vtkRange objects'
316+
);
317+
t.ok(updatedRanges[0].min === 0, 'component:0 minimum value should be 0');
318+
t.ok(updatedRanges[0].max === 9, 'component:0 maximum value should be 9');
319+
t.ok(updatedRanges[1] === null, 'component:1 should be null');
320+
t.ok(updatedRanges[2] === null, 'component:2 should be null');
321+
t.ok(updatedRanges[3] === null, 'component:3 should be null');
322+
t.ok(updatedRanges[4] === null, 'component:-1 should be null');
323+
324+
t.end();
325+
});
326+
205327
test('Test vtkDataArray insertNextTuple', (t) => {
206328
const dataArray = vtkDataArray.newInstance({
207329
dataType: VtkDataTypes.UNSIGNED_CHAR,

Sources/Rendering/Core/AbstractImageMapper/index.d.ts

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,87 @@ export interface vtkAbstractImageMapper extends vtkAbstractMapper3D {
122122
* @param customDisplayExtent
123123
*/
124124
setCustomDisplayExtentFrom(customDisplayExtent: number[]): boolean;
125+
126+
/**
127+
* Set the opacity texture width.
128+
*
129+
* The default width (1024) should be fine in most instances.
130+
* Only set this property if your opacity function range width is
131+
* larger than 1024.
132+
*
133+
* A reasonable max texture size would be either 2048 or 4096, as those
134+
* widths are supported by the vast majority of devices. Any width larger
135+
* than that will have issues with device support.
136+
*
137+
* Specifying a width that is less than or equal to 0 will use the largest
138+
* possible texture width on the device. Use this with caution! The max texture
139+
* width of one device may not be the same for another device.
140+
*
141+
* You can find more information about supported texture widths at the following link:
142+
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
143+
*
144+
* @param {Number} width the texture width (defaults to 1024)
145+
*/
146+
setOpacityTextureWidth(width: number): boolean;
147+
148+
/**
149+
* Get the opacity texture width.
150+
*/
151+
getOpacityTextureWidth(): number;
152+
153+
/**
154+
* Set the color texture width.
155+
*
156+
* The default width (1024) should be fine in most instances.
157+
* Only set this property if your color transfer function range width is
158+
* larger than 1024.
159+
*
160+
* A reasonable max texture size would be either 2048 or 4096, as those
161+
* widths are supported by the vast majority of devices. Any width larger
162+
* than that will have issues with device support.
163+
*
164+
* Specifying a width that is less than or equal to 0 will use the largest
165+
* possible texture width on the device. Use this with caution! The max texture
166+
* width of one device may not be the same for another device.
167+
*
168+
* You can find more information about supported texture widths at the following link:
169+
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
170+
*
171+
* @param {Number} width the texture width (defaults to 1024)
172+
*/
173+
setColorTextureWidth(width: number): boolean;
174+
175+
/**
176+
* Get the color texture width.
177+
*/
178+
getColorTextureWidth(): number;
179+
180+
/**
181+
* Set the label outline texture width.
182+
*
183+
* The default width (1024) should be fine in most instances.
184+
* Only set this property if you have more than 1024 labels
185+
* that you want to render with thickness.
186+
*
187+
* A reasonable max texture size would be either 2048 or 4096, as those
188+
* widths are supported by the vast majority of devices. Any width larger
189+
* than that will have issues with device support.
190+
*
191+
* Specifying a width that is less than or equal to 0 will use the largest
192+
* possible texture width on the device. Use this with caution! The max texture
193+
* width of one device may not be the same for another device.
194+
*
195+
* You can find more information about supported texture widths at the following link:
196+
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
197+
*
198+
* @param {Number} width the texture width (defaults to 1024)
199+
*/
200+
setLabelOutlineTextureWidth(width: number): boolean;
201+
202+
/**
203+
* Get the label outline texture width.
204+
*/
205+
getLabelOutlineTextureWidth(): number;
125206
}
126207

127208
/**

Sources/Rendering/Core/AbstractImageMapper/index.js

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@ const DEFAULT_VALUES = {
3030
customDisplayExtent: [0, 0, 0, 0, 0, 0],
3131
useCustomExtents: false,
3232
backgroundColor: [0, 0, 0, 1],
33+
colorTextureWidth: 1024,
34+
opacityTextureWidth: 1024,
35+
labelOutlineTextureWidth: 1024,
3336
};
3437

3538
// ----------------------------------------------------------------------------
@@ -40,7 +43,13 @@ export function extend(publicAPI, model, initialValues = {}) {
4043
// Build VTK API
4144
vtkAbstractMapper3D.extend(publicAPI, model, initialValues);
4245

43-
macro.setGet(publicAPI, model, ['slice', 'useCustomExtents']);
46+
macro.setGet(publicAPI, model, [
47+
'slice',
48+
'useCustomExtents',
49+
'colorTextureWidth',
50+
'opacityTextureWidth',
51+
'labelOutlineTextureWidth',
52+
]);
4453
macro.setGetArray(publicAPI, model, ['customDisplayExtent'], 6);
4554
macro.setGetArray(publicAPI, model, ['backgroundColor'], 4);
4655

Sources/Rendering/Core/AbstractPicker/index.d.ts

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { vtkObject } from '../../../interfaces';
22
import { Vector3 } from '../../../types';
3-
import vtkActor from '../Actor';
3+
import vtkProp3D from '../Prop3D';
44
import vtkRenderer from '../Renderer';
55

66
/**
@@ -10,8 +10,8 @@ export interface IAbstractPickerInitialValues {
1010
renderer?: vtkRenderer;
1111
selectionPoint?: Vector3;
1212
pickPosition?: Vector3;
13-
pickFromList?: number;
14-
pickList?: vtkActor[];
13+
pickFromList?: boolean;
14+
pickList?: vtkProp3D[];
1515
}
1616

1717
/**
@@ -20,15 +20,15 @@ export interface IAbstractPickerInitialValues {
2020
export interface vtkAbstractPicker extends vtkObject {
2121
/**
2222
*
23-
* @param {vtkActor} actor
23+
* @param {vtkProp3D} prop
2424
*/
25-
addPickList(actor: vtkActor): void;
25+
addPickList(prop: vtkProp3D): void;
2626

2727
/**
2828
*
29-
* @param {vtkActor} actor
29+
* @param {vtkProp3D} prop
3030
*/
31-
deletePickList(actor: vtkActor): void;
31+
deletePickList(prop: vtkProp3D): void;
3232

3333
/**
3434
*
@@ -38,7 +38,7 @@ export interface vtkAbstractPicker extends vtkObject {
3838
/**
3939
*
4040
*/
41-
getPickList(): boolean;
41+
getPickList(): vtkProp3D[];
4242

4343
/**
4444
* Get the picked position
@@ -82,17 +82,17 @@ export interface vtkAbstractPicker extends vtkObject {
8282

8383
/**
8484
*
85-
* @param {Number} pickFromList
86-
* @default 0
85+
* @param {Boolean} pickFromList
86+
* @default false
8787
*/
88-
setPickFromList(pickFromList: number): boolean;
88+
setPickFromList(pickFromList: boolean): boolean;
8989

9090
/**
9191
*
92-
* @param {vtkActor[]} pickList
92+
* @param {vtkProp3D[]} pickList
9393
* @default []
9494
*/
95-
setPickList(pickList: vtkActor[]): boolean;
95+
setPickList(pickList: vtkProp3D[]): boolean;
9696
}
9797

9898
/**

0 commit comments

Comments
 (0)