Skip to content

Commit 8901d13

Browse files
committed
fix(Rendering): tighter glyph bounds
Now computes a more accurate and tight bounding box for the glyph.
1 parent f58cf3a commit 8901d13

File tree

4 files changed

+76
-79
lines changed

4 files changed

+76
-79
lines changed

Sources/Common/DataModel/BoundingBox/index.js

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import macro from 'vtk.js/Sources/macro';
22
import vtkPlane from 'vtk.js/Sources/Common/DataModel/Plane';
33

4-
export const INIT_BOUNDS = [
4+
const INIT_BOUNDS = [
55
Number.MAX_VALUE, -Number.MAX_VALUE, // X
66
Number.MAX_VALUE, -Number.MAX_VALUE, // Y
77
Number.MAX_VALUE, -Number.MAX_VALUE, // Z
@@ -74,6 +74,18 @@ function oppositeSign(a, b) {
7474
return (a <= 0 && b >= 0) || (a >= 0 && b <= 0);
7575
}
7676

77+
function getCorners(bounds, corners) {
78+
let count = 0;
79+
for (let ix = 0; ix < 2; ix++) {
80+
for (let iy = 2; iy < 4; iy++) {
81+
for (let iz = 4; iz < 6; iz++) {
82+
corners[count] = [bounds[ix], bounds[iy], bounds[iz]];
83+
count++;
84+
}
85+
}
86+
}
87+
}
88+
7789
// ----------------------------------------------------------------------------
7890
// Static API
7991
// ----------------------------------------------------------------------------
@@ -88,6 +100,8 @@ export const STATIC = {
88100
getXRange,
89101
getYRange,
90102
getZRange,
103+
getCorners,
104+
INIT_BOUNDS,
91105
};
92106

93107
// ----------------------------------------------------------------------------
@@ -360,6 +374,11 @@ function vtkBoundingBox(publicAPI, model) {
360374
});
361375
};
362376

377+
publicAPI.getCorners = () => {
378+
getCorners(model.bounds, model.corners);
379+
return model.corners;
380+
};
381+
363382
publicAPI.scale = (sx, sy, sz) => {
364383
if (publicAPI.isValid()) {
365384
const newBounds = [].concat(model.bounds);
@@ -401,6 +420,7 @@ function vtkBoundingBox(publicAPI, model) {
401420
const DEFAULT_VALUES = {
402421
type: 'vtkBoundingBox',
403422
bounds: [].concat(INIT_BOUNDS),
423+
corners: [],
404424
};
405425

406426
// ----------------------------------------------------------------------------

Sources/Rendering/Core/Glyph3DMapper/index.js

+48-71
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1-
import { mat3, mat4 } from 'gl-matrix';
1+
import { mat3, mat4, vec3 } from 'gl-matrix';
22

33
import Constants from 'vtk.js/Sources/Rendering/Core/Glyph3DMapper/Constants';
44
import macro from 'vtk.js/Sources/macro';
55
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
66
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
7+
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';
78

89
const { OrientationModes, ScaleModes } = Constants;
910
const { vtkErrorMacro } = macro;
@@ -69,83 +70,18 @@ function vtkGlyph3DMapper(publicAPI, model) {
6970
if (!idata || !gdata) {
7071
return vtkMath.createUninitializedBounds();
7172
}
72-
const ibounds = idata.getBounds();
73-
const gbounds = gdata.getBounds();
74-
75-
const sArray = publicAPI.getScaleArrayData();
76-
77-
// either have to compute the full dataset result
78-
// or use a heuristic. The basic gist is for the
79-
// idata points, place a scaled and oriented glyph
80-
// at that location and then compute the bounds.
81-
// we instead take the input bounds, and add to them
82-
// the maximum scaled glyph bounds for any orientation
83-
// To get any orientation we treat the glyph as a
84-
// sphere about the origin making it rotationally
85-
// invarient
86-
let radius = Math.abs(gbounds[0]);
87-
for (let i = 1; i < 6; ++i) {
88-
if (Math.abs(gbounds[i]) > radius) {
89-
radius = gbounds[i];
90-
}
91-
}
92-
93-
// compute the max absolute scale
94-
let scale = 1.0;
95-
if (model.scaling) {
96-
scale = model.scaleFactor;
97-
}
98-
if (sArray && model.scaleMode !== ScaleModes.SCALE_BY_CONSTANT) {
99-
const numC = sArray.getNumberOfComponents();
100-
if (model.scaleMode === ScaleModes.SCALE_BY_COMPONENTS) {
101-
let maxScale = 0.0;
102-
for (let i = 0; i < numC; ++i) {
103-
const srange = sArray.getRange(i);
104-
if (-srange[0] > maxScale) {
105-
maxScale = -srange[0];
106-
}
107-
if (srange[1] > maxScale) {
108-
maxScale = srange[1];
109-
}
110-
}
111-
scale *= maxScale;
112-
} else {
113-
const maxScale = [];
114-
for (let i = 0; i < numC; ++i) {
115-
const srange = sArray.getRange(i);
116-
maxScale[i] = -srange[0];
117-
if (srange[1] > maxScale[i]) {
118-
maxScale[i] = srange[1];
119-
}
120-
}
121-
scale *= vtkMath.norm(maxScale, numC);
122-
}
123-
}
124-
125-
// if orienting then use the radius
126-
if (model.orienting) {
127-
model.bounds[0] = ibounds[0] - (radius * scale);
128-
model.bounds[1] = ibounds[1] + (radius * scale);
129-
model.bounds[2] = ibounds[2] - (radius * scale);
130-
model.bounds[3] = ibounds[3] + (radius * scale);
131-
model.bounds[4] = ibounds[4] - (radius * scale);
132-
model.bounds[5] = ibounds[5] + (radius * scale);
133-
} else { // other wise use the actual glyph
134-
model.bounds[0] = ibounds[0] + (gbounds[0] * scale);
135-
model.bounds[1] = ibounds[1] + (gbounds[1] * scale);
136-
model.bounds[2] = ibounds[2] + (gbounds[2] * scale);
137-
model.bounds[3] = ibounds[3] + (gbounds[3] * scale);
138-
model.bounds[4] = ibounds[4] + (gbounds[4] * scale);
139-
model.bounds[5] = ibounds[5] + (gbounds[5] * scale);
140-
}
14173

74+
// first we build the arrays used for the glyphing
75+
publicAPI.buildArrays();
14276
return model.bounds;
14377
};
14478

14579
publicAPI.buildArrays = () => {
14680
// if the mtgime requires it, rebuild
14781
const idata = publicAPI.getInputData(0);
148-
if (model.buildTime.getMTime() < idata.getMTime() ||
82+
const gdata = publicAPI.getInputData(1);
83+
if (model.buildTime.getMTime() < gdata.getMTime() ||
84+
model.buildTime.getMTime() < idata.getMTime() ||
14985
model.buildTime.getMTime() < publicAPI.getMTime()) {
15086
const pts = idata.getPoints().getData();
15187
let sArray = publicAPI.getScaleArrayData();
@@ -163,6 +99,21 @@ function vtkGlyph3DMapper(publicAPI, model) {
16399
sArray = null;
164100
}
165101

102+
// get the glyph bounds
103+
const gbounds = gdata.getBounds();
104+
// convert them to 8 points so we can compute the
105+
// overall bounds while building the arrays
106+
const corners = [];
107+
vtkBoundingBox.getCorners(gbounds, corners);
108+
model.bounds[0] = vtkBoundingBox.INIT_BOUNDS[0];
109+
model.bounds[1] = vtkBoundingBox.INIT_BOUNDS[1];
110+
model.bounds[2] = vtkBoundingBox.INIT_BOUNDS[2];
111+
model.bounds[3] = vtkBoundingBox.INIT_BOUNDS[3];
112+
model.bounds[4] = vtkBoundingBox.INIT_BOUNDS[4];
113+
model.bounds[5] = vtkBoundingBox.INIT_BOUNDS[5];
114+
115+
const tcorner = vec3.create();
116+
166117
const oArray = publicAPI.getOrientationArrayData();
167118

168119
const identity = mat4.create();
@@ -251,6 +202,29 @@ function vtkGlyph3DMapper(publicAPI, model) {
251202
mat4.scale(z, z, scale);
252203
}
253204

205+
// update bounds
206+
for (let p = 0; p < 8; ++p) {
207+
vec3.transformMat4(tcorner, corners[p], z);
208+
if (tcorner[0] < model.bounds[0]) {
209+
model.bounds[0] = tcorner[0];
210+
}
211+
if (tcorner[1] < model.bounds[2]) {
212+
model.bounds[2] = tcorner[1];
213+
}
214+
if (tcorner[2] < model.bounds[4]) {
215+
model.bounds[4] = tcorner[2];
216+
}
217+
if (tcorner[0] > model.bounds[1]) {
218+
model.bounds[1] = tcorner[0];
219+
}
220+
if (tcorner[1] > model.bounds[3]) {
221+
model.bounds[3] = tcorner[1];
222+
}
223+
if (tcorner[2] > model.bounds[5]) {
224+
model.bounds[5] = tcorner[2];
225+
}
226+
}
227+
254228
const n = new Float32Array(nbuff, i * 36, 9);
255229
mat3.fromMat4(n, z);
256230
mat3.invert(n, n);
@@ -311,6 +285,9 @@ export function extend(publicAPI, model, initialValues = {}) {
311285
model.buildTime = {};
312286
macro.obj(model.buildTime, { mtime: 0 });
313287

288+
model.boundsTime = {};
289+
macro.obj(model.boundsTime, { mtime: 0 });
290+
314291
macro.setGet(publicAPI, model, [
315292
'orient',
316293
'orientationArray',
Loading

Sources/Rendering/Core/Renderer/index.js

+7-7
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ import vtkCamera from 'vtk.js/Sources/Rendering/Core/Camera';
55
import vtkLight from 'vtk.js/Sources/Rendering/Core/Light';
66
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
77
import vtkViewport from 'vtk.js/Sources/Rendering/Core/Viewport';
8-
import { INIT_BOUNDS } from 'vtk.js/Sources/Common/DataModel/BoundingBox';
8+
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';
99

1010
const { vtkDebugMacro, vtkErrorMacro, vtkWarningMacro } = macro;
1111

@@ -270,12 +270,12 @@ function vtkRenderer(publicAPI, model) {
270270
};
271271

272272
publicAPI.computeVisiblePropBounds = () => {
273-
model.allBounds[0] = INIT_BOUNDS[0];
274-
model.allBounds[1] = INIT_BOUNDS[1];
275-
model.allBounds[2] = INIT_BOUNDS[2];
276-
model.allBounds[3] = INIT_BOUNDS[3];
277-
model.allBounds[4] = INIT_BOUNDS[4];
278-
model.allBounds[5] = INIT_BOUNDS[5];
273+
model.allBounds[0] = vtkBoundingBox.INIT_BOUNDS[0];
274+
model.allBounds[1] = vtkBoundingBox.INIT_BOUNDS[1];
275+
model.allBounds[2] = vtkBoundingBox.INIT_BOUNDS[2];
276+
model.allBounds[3] = vtkBoundingBox.INIT_BOUNDS[3];
277+
model.allBounds[4] = vtkBoundingBox.INIT_BOUNDS[4];
278+
model.allBounds[5] = vtkBoundingBox.INIT_BOUNDS[5];
279279
let nothingVisible = true;
280280

281281
publicAPI.invokeEvent(COMPUTE_VISIBLE_PROP_BOUNDS_EVENT);

0 commit comments

Comments
 (0)