Skip to content

Commit

Permalink
fix(Rendering): tighter glyph bounds
Browse files Browse the repository at this point in the history
Now computes a more accurate and tight bounding
box for the glyph.
  • Loading branch information
Ken Martin committed Dec 1, 2017
1 parent f58cf3a commit 8901d13
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 79 deletions.
22 changes: 21 additions & 1 deletion Sources/Common/DataModel/BoundingBox/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import macro from 'vtk.js/Sources/macro';
import vtkPlane from 'vtk.js/Sources/Common/DataModel/Plane';

export const INIT_BOUNDS = [
const INIT_BOUNDS = [
Number.MAX_VALUE, -Number.MAX_VALUE, // X
Number.MAX_VALUE, -Number.MAX_VALUE, // Y
Number.MAX_VALUE, -Number.MAX_VALUE, // Z
Expand Down Expand Up @@ -74,6 +74,18 @@ function oppositeSign(a, b) {
return (a <= 0 && b >= 0) || (a >= 0 && b <= 0);
}

function getCorners(bounds, corners) {
let count = 0;
for (let ix = 0; ix < 2; ix++) {
for (let iy = 2; iy < 4; iy++) {
for (let iz = 4; iz < 6; iz++) {
corners[count] = [bounds[ix], bounds[iy], bounds[iz]];
count++;
}
}
}
}

// ----------------------------------------------------------------------------
// Static API
// ----------------------------------------------------------------------------
Expand All @@ -88,6 +100,8 @@ export const STATIC = {
getXRange,
getYRange,
getZRange,
getCorners,
INIT_BOUNDS,
};

// ----------------------------------------------------------------------------
Expand Down Expand Up @@ -360,6 +374,11 @@ function vtkBoundingBox(publicAPI, model) {
});
};

publicAPI.getCorners = () => {
getCorners(model.bounds, model.corners);
return model.corners;
};

publicAPI.scale = (sx, sy, sz) => {
if (publicAPI.isValid()) {
const newBounds = [].concat(model.bounds);
Expand Down Expand Up @@ -401,6 +420,7 @@ function vtkBoundingBox(publicAPI, model) {
const DEFAULT_VALUES = {
type: 'vtkBoundingBox',
bounds: [].concat(INIT_BOUNDS),
corners: [],
};

// ----------------------------------------------------------------------------
Expand Down
119 changes: 48 additions & 71 deletions Sources/Rendering/Core/Glyph3DMapper/index.js
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { mat3, mat4 } from 'gl-matrix';
import { mat3, mat4, vec3 } from 'gl-matrix';

import Constants from 'vtk.js/Sources/Rendering/Core/Glyph3DMapper/Constants';
import macro from 'vtk.js/Sources/macro';
import vtkMapper from 'vtk.js/Sources/Rendering/Core/Mapper';
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';

const { OrientationModes, ScaleModes } = Constants;
const { vtkErrorMacro } = macro;
Expand Down Expand Up @@ -69,83 +70,18 @@ function vtkGlyph3DMapper(publicAPI, model) {
if (!idata || !gdata) {
return vtkMath.createUninitializedBounds();
}
const ibounds = idata.getBounds();
const gbounds = gdata.getBounds();

const sArray = publicAPI.getScaleArrayData();

// either have to compute the full dataset result
// or use a heuristic. The basic gist is for the
// idata points, place a scaled and oriented glyph
// at that location and then compute the bounds.
// we instead take the input bounds, and add to them
// the maximum scaled glyph bounds for any orientation
// To get any orientation we treat the glyph as a
// sphere about the origin making it rotationally
// invarient
let radius = Math.abs(gbounds[0]);
for (let i = 1; i < 6; ++i) {
if (Math.abs(gbounds[i]) > radius) {
radius = gbounds[i];
}
}

// compute the max absolute scale
let scale = 1.0;
if (model.scaling) {
scale = model.scaleFactor;
}
if (sArray && model.scaleMode !== ScaleModes.SCALE_BY_CONSTANT) {
const numC = sArray.getNumberOfComponents();
if (model.scaleMode === ScaleModes.SCALE_BY_COMPONENTS) {
let maxScale = 0.0;
for (let i = 0; i < numC; ++i) {
const srange = sArray.getRange(i);
if (-srange[0] > maxScale) {
maxScale = -srange[0];
}
if (srange[1] > maxScale) {
maxScale = srange[1];
}
}
scale *= maxScale;
} else {
const maxScale = [];
for (let i = 0; i < numC; ++i) {
const srange = sArray.getRange(i);
maxScale[i] = -srange[0];
if (srange[1] > maxScale[i]) {
maxScale[i] = srange[1];
}
}
scale *= vtkMath.norm(maxScale, numC);
}
}

// if orienting then use the radius
if (model.orienting) {
model.bounds[0] = ibounds[0] - (radius * scale);
model.bounds[1] = ibounds[1] + (radius * scale);
model.bounds[2] = ibounds[2] - (radius * scale);
model.bounds[3] = ibounds[3] + (radius * scale);
model.bounds[4] = ibounds[4] - (radius * scale);
model.bounds[5] = ibounds[5] + (radius * scale);
} else { // other wise use the actual glyph
model.bounds[0] = ibounds[0] + (gbounds[0] * scale);
model.bounds[1] = ibounds[1] + (gbounds[1] * scale);
model.bounds[2] = ibounds[2] + (gbounds[2] * scale);
model.bounds[3] = ibounds[3] + (gbounds[3] * scale);
model.bounds[4] = ibounds[4] + (gbounds[4] * scale);
model.bounds[5] = ibounds[5] + (gbounds[5] * scale);
}

// first we build the arrays used for the glyphing
publicAPI.buildArrays();
return model.bounds;
};

publicAPI.buildArrays = () => {
// if the mtgime requires it, rebuild
const idata = publicAPI.getInputData(0);
if (model.buildTime.getMTime() < idata.getMTime() ||
const gdata = publicAPI.getInputData(1);
if (model.buildTime.getMTime() < gdata.getMTime() ||
model.buildTime.getMTime() < idata.getMTime() ||
model.buildTime.getMTime() < publicAPI.getMTime()) {
const pts = idata.getPoints().getData();
let sArray = publicAPI.getScaleArrayData();
Expand All @@ -163,6 +99,21 @@ function vtkGlyph3DMapper(publicAPI, model) {
sArray = null;
}

// get the glyph bounds
const gbounds = gdata.getBounds();
// convert them to 8 points so we can compute the
// overall bounds while building the arrays
const corners = [];
vtkBoundingBox.getCorners(gbounds, corners);
model.bounds[0] = vtkBoundingBox.INIT_BOUNDS[0];
model.bounds[1] = vtkBoundingBox.INIT_BOUNDS[1];
model.bounds[2] = vtkBoundingBox.INIT_BOUNDS[2];
model.bounds[3] = vtkBoundingBox.INIT_BOUNDS[3];
model.bounds[4] = vtkBoundingBox.INIT_BOUNDS[4];
model.bounds[5] = vtkBoundingBox.INIT_BOUNDS[5];

const tcorner = vec3.create();

const oArray = publicAPI.getOrientationArrayData();

const identity = mat4.create();
Expand Down Expand Up @@ -251,6 +202,29 @@ function vtkGlyph3DMapper(publicAPI, model) {
mat4.scale(z, z, scale);
}

// update bounds
for (let p = 0; p < 8; ++p) {
vec3.transformMat4(tcorner, corners[p], z);
if (tcorner[0] < model.bounds[0]) {
model.bounds[0] = tcorner[0];
}
if (tcorner[1] < model.bounds[2]) {
model.bounds[2] = tcorner[1];
}
if (tcorner[2] < model.bounds[4]) {
model.bounds[4] = tcorner[2];
}
if (tcorner[0] > model.bounds[1]) {
model.bounds[1] = tcorner[0];
}
if (tcorner[1] > model.bounds[3]) {
model.bounds[3] = tcorner[1];
}
if (tcorner[2] > model.bounds[5]) {
model.bounds[5] = tcorner[2];
}
}

const n = new Float32Array(nbuff, i * 36, 9);
mat3.fromMat4(n, z);
mat3.invert(n, n);
Expand Down Expand Up @@ -311,6 +285,9 @@ export function extend(publicAPI, model, initialValues = {}) {
model.buildTime = {};
macro.obj(model.buildTime, { mtime: 0 });

model.boundsTime = {};
macro.obj(model.boundsTime, { mtime: 0 });

macro.setGet(publicAPI, model, [
'orient',
'orientationArray',
Expand Down
Binary file modified Sources/Rendering/Core/Glyph3DMapper/test/testGlyph3DMapper.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
14 changes: 7 additions & 7 deletions Sources/Rendering/Core/Renderer/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import vtkCamera from 'vtk.js/Sources/Rendering/Core/Camera';
import vtkLight from 'vtk.js/Sources/Rendering/Core/Light';
import vtkMath from 'vtk.js/Sources/Common/Core/Math';
import vtkViewport from 'vtk.js/Sources/Rendering/Core/Viewport';
import { INIT_BOUNDS } from 'vtk.js/Sources/Common/DataModel/BoundingBox';
import vtkBoundingBox from 'vtk.js/Sources/Common/DataModel/BoundingBox';

const { vtkDebugMacro, vtkErrorMacro, vtkWarningMacro } = macro;

Expand Down Expand Up @@ -270,12 +270,12 @@ function vtkRenderer(publicAPI, model) {
};

publicAPI.computeVisiblePropBounds = () => {
model.allBounds[0] = INIT_BOUNDS[0];
model.allBounds[1] = INIT_BOUNDS[1];
model.allBounds[2] = INIT_BOUNDS[2];
model.allBounds[3] = INIT_BOUNDS[3];
model.allBounds[4] = INIT_BOUNDS[4];
model.allBounds[5] = INIT_BOUNDS[5];
model.allBounds[0] = vtkBoundingBox.INIT_BOUNDS[0];
model.allBounds[1] = vtkBoundingBox.INIT_BOUNDS[1];
model.allBounds[2] = vtkBoundingBox.INIT_BOUNDS[2];
model.allBounds[3] = vtkBoundingBox.INIT_BOUNDS[3];
model.allBounds[4] = vtkBoundingBox.INIT_BOUNDS[4];
model.allBounds[5] = vtkBoundingBox.INIT_BOUNDS[5];
let nothingVisible = true;

publicAPI.invokeEvent(COMPUTE_VISIBLE_PROP_BOUNDS_EVENT);
Expand Down

0 comments on commit 8901d13

Please sign in to comment.