Skip to content

Commit 36385e0

Browse files
committed
refactor(bounds): fix getBounds to return a copy of model.bounds
A getter should return a copy and not a reference. getBoundsByReference can return the actual model.bounds array. BREAKING CHANGE: Mappers should overwrite computeBounds instead of getBounds
1 parent bea78f5 commit 36385e0

File tree

19 files changed

+200
-152
lines changed

19 files changed

+200
-152
lines changed

Sources/Common/DataModel/BoundingBox/index.d.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { mat4 } from 'gl-matrix';
2-
import { Bounds, Vector2, Vector3 } from '../../../types';
2+
import { Bounds, TypedArray, Vector2, Vector3 } from '../../../types';
33
import vtkPoints from '../../Core/Points';
44
import { Nullable } from '../../../types';
55

@@ -394,11 +394,16 @@ declare class BoundingBox {
394394
/**
395395
* Adds points to a bounding box.
396396
* @param {Bounds} bounds
397-
* @param {number} x
397+
* @param {number|Number[]|TypedArray} xOrPoint
398398
* @param {number} y
399399
* @param {number} z
400400
*/
401-
addPoint(bounds: Bounds, x: number, y: number, z: number): Bounds;
401+
addPoint(
402+
bounds: Bounds,
403+
xOrPoint: number | number[] | TypedArray,
404+
y?: number,
405+
z?: number
406+
): Bounds;
402407

403408
/**
404409
* Adds points to a bounding box.

Sources/Common/DataModel/BoundingBox/index.js

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -49,14 +49,23 @@ export function reset(bounds) {
4949
return setBounds(bounds, INIT_BOUNDS);
5050
}
5151

52-
export function addPoint(bounds, x, y, z) {
52+
export function addPoint(bounds, xOrPoint, y, z) {
5353
const [xMin, xMax, yMin, yMax, zMin, zMax] = bounds;
54-
bounds[0] = xMin < x ? xMin : x;
55-
bounds[1] = xMax > x ? xMax : x;
56-
bounds[2] = yMin < y ? yMin : y;
57-
bounds[3] = yMax > y ? yMax : y;
58-
bounds[4] = zMin < z ? zMin : z;
59-
bounds[5] = zMax > z ? zMax : z;
54+
if (arguments.length === 4) {
55+
bounds[0] = xMin < xOrPoint ? xMin : xOrPoint;
56+
bounds[1] = xMax > xOrPoint ? xMax : xOrPoint;
57+
bounds[2] = yMin < y ? yMin : y;
58+
bounds[3] = yMax > y ? yMax : y;
59+
bounds[4] = zMin < z ? zMin : z;
60+
bounds[5] = zMax > z ? zMax : z;
61+
} else {
62+
bounds[0] = xMin < xOrPoint[0] ? xMin : xOrPoint[0];
63+
bounds[1] = xMax > xOrPoint[0] ? xMax : xOrPoint[0];
64+
bounds[2] = yMin < xOrPoint[1] ? yMin : xOrPoint[1];
65+
bounds[3] = yMax > xOrPoint[1] ? yMax : xOrPoint[1];
66+
bounds[4] = zMin < xOrPoint[2] ? zMin : xOrPoint[2];
67+
bounds[5] = zMax > xOrPoint[2] ? zMax : xOrPoint[2];
68+
}
6069
return bounds;
6170
}
6271

Sources/Common/DataModel/Box/index.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ function vtkBox(publicAPI, model) {
120120
vtkBoundingBox.setBounds(model.bbox, boundsArray);
121121
};
122122

123-
publicAPI.getBounds = () => model.bbox;
123+
publicAPI.getBounds = () => [...model.bbox];
124124

125125
publicAPI.evaluateFunction = (x, y, z) => {
126126
const point = Array.isArray(x) ? x : [x, y, z];

Sources/Proxy/Core/ViewProxy/index.js

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -353,10 +353,11 @@ function vtkViewProxy(publicAPI, model) {
353353

354354
// --------------------------------------------------------------------------
355355

356-
publicAPI.setBackground = macro.chain(
357-
model.renderer.setBackground,
358-
updateAnnotationColor
359-
);
356+
publicAPI.setBackground = (...args) => {
357+
const res = model.renderer.setBackground(...args);
358+
updateAnnotationColor();
359+
return res;
360+
};
360361

361362
// --------------------------------------------------------------------------
362363

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,11 +15,30 @@ export interface IAbstractMapper3DInitialValues
1515
export interface vtkAbstractMapper3D extends vtkAbstractMapper {
1616
/**
1717
* Get the bounds for this mapper as [xmin, xmax, ymin, ymax,zmin, zmax].
18-
* @default 0
19-
* @return {Bounds} The bounds for the mapper.
18+
* Bounds are (re)computed if needed.
19+
* @return {Bounds} A copy of the bounds for the mapper.
20+
* @see getBoundsByReference
21+
* @see computeBounds
2022
*/
2123
getBounds(): Bounds;
2224

25+
/**
26+
* Get the bounds for this mapper as [xmin, xmax, ymin, ymax,zmin, zmax].
27+
* Bounds are (re)computed if needed.
28+
* @return {Bounds} The bounds array of the mapper.
29+
* @see getBounds
30+
* @see computeBounds
31+
*/
32+
getBoundsByReference(): Bounds;
33+
34+
/**
35+
* Compute the bounds for this mapper.
36+
* Must be implemented by sub-classes. Called by getBounds methods.
37+
* @see getBoundsByReference
38+
* @see getBounds
39+
*/
40+
computeBounds(): void;
41+
2342
/**
2443
* Get the center of this mapper’s data.
2544
* @return {Vector3} The center of the mapper's data.

Sources/Rendering/Core/AbstractMapper3D/index.js

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,38 @@
11
import macro from 'vtk.js/Sources/macros';
22
import vtkAbstractMapper from 'vtk.js/Sources/Rendering/Core/AbstractMapper';
33
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';
4-
import { createUninitializedBounds } from 'vtk.js/Sources/Common/Core/Math';
54

65
// ----------------------------------------------------------------------------
76
// vtkAbstractMapper methods
87
// ----------------------------------------------------------------------------
98

109
function vtkAbstractMapper3D(publicAPI, model) {
10+
publicAPI.computeBounds = () => {
11+
macro.vtkErrorMacro(`vtkAbstractMapper3D.computeBounds - NOT IMPLEMENTED`);
12+
};
13+
14+
const superGetBounds = publicAPI.getBounds;
1115
publicAPI.getBounds = () => {
12-
macro.vtkErrorMacro(`vtkAbstractMapper3D.getBounds - NOT IMPLEMENTED`);
13-
return createUninitializedBounds();
16+
publicAPI.computeBounds();
17+
return superGetBounds();
18+
};
19+
20+
const superGetBoundsByReference = publicAPI.getBoundsByReference;
21+
publicAPI.getBoundsByReference = () => {
22+
publicAPI.computeBounds();
23+
return superGetBoundsByReference();
1424
};
1525

1626
publicAPI.getCenter = () => {
17-
const bounds = publicAPI.getBounds();
27+
const bounds = publicAPI.getBoundsByReference();
1828
model.center = vtkBoundingBox.isValid(bounds)
1929
? vtkBoundingBox.getCenter(bounds)
2030
: null;
2131
return model.center?.slice();
2232
};
2333

2434
publicAPI.getLength = () => {
25-
const bounds = publicAPI.getBounds();
35+
const bounds = publicAPI.getBoundsByReference();
2636
return vtkBoundingBox.getDiagonalLength(bounds);
2737
};
2838
}
@@ -46,6 +56,7 @@ export function extend(publicAPI, model, initialValues = {}) {
4656
vtkAbstractMapper.extend(publicAPI, model, initialValues);
4757

4858
macro.setGet(publicAPI, model, ['viewSpecificProperties']);
59+
macro.getArray(publicAPI, model, ['bounds'], 6);
4960

5061
vtkAbstractMapper3D(publicAPI, model);
5162
}

Sources/Rendering/Core/CubeAxesActor/index.js

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -788,7 +788,7 @@ function vtkCubeAxesActor(publicAPI, model) {
788788
// as it relies on the pixel size of the window. Every time the camera
789789
// changes the bounds change. This method simplifies by just expanding
790790
// the grid bounds by a user specified factor.
791-
publicAPI.getBounds = () => {
791+
publicAPI.computeBounds = () => {
792792
publicAPI.update();
793793
vtkBoundingBox.setBounds(model.bounds, model.gridActor.getBounds());
794794
vtkBoundingBox.scaleAboutCenter(
@@ -797,15 +797,15 @@ function vtkCubeAxesActor(publicAPI, model) {
797797
model.boundsScaleFactor,
798798
model.boundsScaleFactor
799799
);
800-
return model.bounds;
801800
};
802801

803802
// Make sure the grid share the actor property
804-
const _setProp = macro.chain(
805-
publicAPI.setProperty,
806-
model.gridActor.setProperty
807-
);
808-
publicAPI.setProperty = (p) => _setProp(p)[0];
803+
const superSetProp = publicAPI.setProperty;
804+
publicAPI.setProperty = (p) => {
805+
const res = superSetProp(p);
806+
model.gridActor.setProperty(p);
807+
return res;
808+
};
809809
}
810810

811811
// ----------------------------------------------------------------------------

Sources/Rendering/Core/Glyph3DMapper/index.js

Lines changed: 7 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -66,22 +66,16 @@ function vtkGlyph3DMapper(publicAPI, model) {
6666
return idata.getPointData().getArray(model.scaleArray);
6767
};
6868

69-
publicAPI.getBounds = () => {
70-
const idata = publicAPI.getInputData(0);
71-
const gdata = publicAPI.getInputData(1);
72-
if (!idata || !gdata) {
73-
return vtkMath.createUninitializedBounds();
74-
}
75-
76-
// first we build the arrays used for the glyphing
77-
publicAPI.buildArrays();
78-
return model.bounds;
79-
};
69+
publicAPI.computeBounds = () => publicAPI.buildArrays();
8070

8171
publicAPI.buildArrays = () => {
8272
// if the mtgime requires it, rebuild
8373
const idata = publicAPI.getInputData(0);
8474
const gdata = publicAPI.getInputData(1);
75+
if (!idata || !gdata) {
76+
vtkBoundingBox.reset(model.bounds);
77+
return;
78+
}
8579
if (
8680
model.buildTime.getMTime() < gdata.getMTime() ||
8781
model.buildTime.getMTime() < idata.getMTime() ||
@@ -114,12 +108,7 @@ function vtkGlyph3DMapper(publicAPI, model) {
114108
// overall bounds while building the arrays
115109
const corners = [];
116110
vtkBoundingBox.getCorners(gbounds, corners);
117-
model.bounds[0] = vtkBoundingBox.INIT_BOUNDS[0];
118-
model.bounds[1] = vtkBoundingBox.INIT_BOUNDS[1];
119-
model.bounds[2] = vtkBoundingBox.INIT_BOUNDS[2];
120-
model.bounds[3] = vtkBoundingBox.INIT_BOUNDS[3];
121-
model.bounds[4] = vtkBoundingBox.INIT_BOUNDS[4];
122-
model.bounds[5] = vtkBoundingBox.INIT_BOUNDS[5];
111+
vtkBoundingBox.reset(model.bounds);
123112

124113
const tcorner = new Float64Array(3);
125114

@@ -225,24 +214,7 @@ function vtkGlyph3DMapper(publicAPI, model) {
225214
// update bounds
226215
for (let p = 0; p < 8; ++p) {
227216
vec3.transformMat4(tcorner, corners[p], z);
228-
if (tcorner[0] < model.bounds[0]) {
229-
model.bounds[0] = tcorner[0];
230-
}
231-
if (tcorner[1] < model.bounds[2]) {
232-
model.bounds[2] = tcorner[1];
233-
}
234-
if (tcorner[2] < model.bounds[4]) {
235-
model.bounds[4] = tcorner[2];
236-
}
237-
if (tcorner[0] > model.bounds[1]) {
238-
model.bounds[1] = tcorner[0];
239-
}
240-
if (tcorner[1] > model.bounds[3]) {
241-
model.bounds[3] = tcorner[1];
242-
}
243-
if (tcorner[2] > model.bounds[5]) {
244-
model.bounds[5] = tcorner[2];
245-
}
217+
vtkBoundingBox.addPoint(model.bounds, tcorner);
246218
}
247219

248220
const n = new Float32Array(nbuff, i * 36, 9);
@@ -333,9 +305,6 @@ export function extend(publicAPI, model, initialValues = {}) {
333305
model.buildTime = {};
334306
macro.obj(model.buildTime, { mtime: 0 });
335307

336-
model.boundsTime = {};
337-
macro.obj(model.boundsTime, { mtime: 0 });
338-
339308
macro.setGet(publicAPI, model, [
340309
'orient',
341310
'orientationMode',

Sources/Rendering/Core/HardwareSelector/test/testHardwareSelectorGlyph.js

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,16 @@ test('Test HardwareSelectorGlyph', (tapeContext) => {
108108
sel.setFieldAssociation(FieldAssociations.FIELD_ASSOCIATION_POINTS);
109109

110110
return sel.selectAsync(renderer, 200, 200, 250, 300).then((res) => {
111-
const allGood = res.length === 7 && res[0].getProperties().prop === actor;
112-
113-
tapeContext.ok(res.length === 7, 'Seven glyphs selected');
111+
tapeContext.equal(res.length, 7, 'Seven glyphs selected');
114112
tapeContext.ok(
115113
res[0].getProperties().compositeID === 71,
116114
'glyph 71 was the first selected'
117115
);
118-
tapeContext.ok(allGood, 'Correct prop was selected');
116+
tapeContext.equal(
117+
res[0].getProperties().prop,
118+
actor,
119+
'Correct prop was selected'
120+
);
119121

120122
gc.releaseResources();
121123
});

Sources/Rendering/Core/ImageArrayMapper/index.js

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
import macro from 'vtk.js/Sources/macros';
22
import vtkAbstractImageMapper from 'vtk.js/Sources/Rendering/Core/AbstractImageMapper';
3+
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';
34
import vtkImageMapper from 'vtk.js/Sources/Rendering/Core/ImageMapper';
45
import * as vtkMath from 'vtk.js/Sources/Common/Core/Math';
56
import * as pickingHelper from 'vtk.js/Sources/Rendering/Core/AbstractImageMapper/helper';
@@ -80,13 +81,16 @@ function vtkImageArrayMapper(publicAPI, model) {
8081
return null;
8182
};
8283

83-
publicAPI.getBounds = () => {
84+
// reimplemented from AbstractMapper3D
85+
publicAPI.computeBounds = () => {
8486
const image = publicAPI.getCurrentImage();
8587
if (!image) {
86-
return vtkMath.createUninitializedBounds();
88+
vtkBoundingBox.reset(model.bounds);
89+
return;
8790
}
8891
if (!model.useCustomExtents) {
89-
return image.getBounds();
92+
vtkBoundingBox.setBounds(model.bounds, image.getBounds());
93+
return;
9094
}
9195

9296
const ex = model.customDisplayExtent.slice();
@@ -95,7 +99,7 @@ function vtkImageArrayMapper(publicAPI, model) {
9599
const nSlice = publicAPI.getSubSlice();
96100
ex[4] = nSlice;
97101
ex[5] = nSlice;
98-
return image.extentToBounds(ex);
102+
vtkBoundingBox.setBounds(model.bounds, image.extentToBounds(ex));
99103
};
100104

101105
publicAPI.getBoundsForSlice = (

0 commit comments

Comments
 (0)