UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

854 lines (727 loc) 23.3 kB
import _defineProperty from '@babel/runtime/helpers/defineProperty'; import _classCallCheck from '@babel/runtime/helpers/classCallCheck'; import _createClass from '@babel/runtime/helpers/createClass'; import _toConsumableArray from '@babel/runtime/helpers/toConsumableArray'; import _slicedToArray from '@babel/runtime/helpers/slicedToArray'; import { d as dot } from '../Core/Math/index.js'; import { vec3 } from 'gl-matrix'; import vtkPlane from './Plane.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 INIT_BOUNDS = [Number.MAX_VALUE, -Number.MAX_VALUE, // X Number.MAX_VALUE, -Number.MAX_VALUE, // Y Number.MAX_VALUE, -Number.MAX_VALUE // Z ]; // ---------------------------------------------------------------------------- // Global methods // ---------------------------------------------------------------------------- function _equals(a, b) { return a[0] === b[0] && a[1] === b[1] && a[2] === b[2] && a[3] === b[3] && a[4] === b[4] && a[5] === b[5]; } function _isValid(bounds) { return (bounds === null || bounds === void 0 ? void 0 : bounds.length) >= 6 && bounds[0] <= bounds[1] && bounds[2] <= bounds[3] && bounds[4] <= bounds[5]; } function _setBounds(bounds, otherBounds) { bounds[0] = otherBounds[0]; bounds[1] = otherBounds[1]; bounds[2] = otherBounds[2]; bounds[3] = otherBounds[3]; bounds[4] = otherBounds[4]; bounds[5] = otherBounds[5]; return bounds; } function _reset(bounds) { return _setBounds(bounds, INIT_BOUNDS); } function _addPoint(bounds, x, y, z) { var _bounds = _slicedToArray(bounds, 6), xMin = _bounds[0], xMax = _bounds[1], yMin = _bounds[2], yMax = _bounds[3], zMin = _bounds[4], zMax = _bounds[5]; bounds[0] = xMin < x ? xMin : x; bounds[1] = xMax > x ? xMax : x; bounds[2] = yMin < y ? yMin : y; bounds[3] = yMax > y ? yMax : y; bounds[4] = zMin < z ? zMin : z; bounds[5] = zMax > z ? zMax : z; return bounds; } function _addPoints(bounds, points) { if (points.length === 0) { return bounds; } if (Array.isArray(points[0])) { for (var i = 0; i < points.length; ++i) { _addPoint.apply(void 0, [bounds].concat(_toConsumableArray(points[i]))); } } else { for (var _i = 0; _i < points.length; _i += 3) { _addPoint.apply(void 0, [bounds].concat(_toConsumableArray(points.slice(_i, _i + 3)))); } } return bounds; } function _addBounds(bounds, xMin, xMax, yMin, yMax, zMin, zMax) { var _bounds2 = _slicedToArray(bounds, 6), _xMin = _bounds2[0], _xMax = _bounds2[1], _yMin = _bounds2[2], _yMax = _bounds2[3], _zMin = _bounds2[4], _zMax = _bounds2[5]; if (zMax === undefined) { bounds[0] = Math.min(xMin[0], _xMin); bounds[1] = Math.max(xMin[1], _xMax); bounds[2] = Math.min(xMin[2], _yMin); bounds[3] = Math.max(xMin[3], _yMax); bounds[4] = Math.min(xMin[4], _zMin); bounds[5] = Math.max(xMin[5], _zMax); } else { bounds[0] = Math.min(xMin, _xMin); bounds[1] = Math.max(xMax, _xMax); bounds[2] = Math.min(yMin, _yMin); bounds[3] = Math.max(yMax, _yMax); bounds[4] = Math.min(zMin, _zMin); bounds[5] = Math.max(zMax, _zMax); } return bounds; } function _setMinPoint(bounds, x, y, z) { var _bounds3 = _slicedToArray(bounds, 6), xMin = _bounds3[0], xMax = _bounds3[1], yMin = _bounds3[2], yMax = _bounds3[3], zMin = _bounds3[4], zMax = _bounds3[5]; bounds[0] = x; bounds[1] = x > xMax ? x : xMax; bounds[2] = y; bounds[3] = y > yMax ? y : yMax; bounds[4] = z; bounds[5] = z > zMax ? z : zMax; return xMin !== x || yMin !== y || zMin !== z; } function _setMaxPoint(bounds, x, y, z) { var _bounds4 = _slicedToArray(bounds, 6), xMin = _bounds4[0], xMax = _bounds4[1], yMin = _bounds4[2], yMax = _bounds4[3], zMin = _bounds4[4], zMax = _bounds4[5]; bounds[0] = x < xMin ? x : xMin; bounds[1] = x; bounds[2] = y < yMin ? y : yMin; bounds[3] = y; bounds[4] = z < zMin ? z : zMin; bounds[5] = z; return xMax !== x || yMax !== y || zMax !== z; } function _inflate(bounds, delta) { bounds[0] -= delta; bounds[1] += delta; bounds[2] -= delta; bounds[3] += delta; bounds[4] -= delta; bounds[5] += delta; return bounds; } function _scale(bounds, sx, sy, sz) { if (!_isValid(bounds)) { return false; } if (sx >= 0.0) { bounds[0] *= sx; bounds[1] *= sx; } else { bounds[0] = sx * bounds[1]; bounds[1] = sx * bounds[0]; } if (sy >= 0.0) { bounds[2] *= sy; bounds[3] *= sy; } else { bounds[2] = sy * bounds[3]; bounds[3] = sy * bounds[2]; } if (sz >= 0.0) { bounds[4] *= sz; bounds[5] *= sz; } else { bounds[4] = sz * bounds[5]; bounds[5] = sz * bounds[4]; } return true; } function _getCenter(bounds) { return [0.5 * (bounds[0] + bounds[1]), 0.5 * (bounds[2] + bounds[3]), 0.5 * (bounds[4] + bounds[5])]; } function scaleAboutCenter(bounds, sx, sy, sz) { if (!_isValid(bounds)) { return false; } var center = _getCenter(bounds); bounds[0] -= center[0]; bounds[1] -= center[0]; bounds[2] -= center[1]; bounds[3] -= center[1]; bounds[4] -= center[2]; bounds[5] -= center[2]; _scale(bounds, sx, sy, sz); bounds[0] += center[0]; bounds[1] += center[0]; bounds[2] += center[1]; bounds[3] += center[1]; bounds[4] += center[2]; bounds[5] += center[2]; return true; } function _getLength(bounds, index) { return bounds[index * 2 + 1] - bounds[index * 2]; } function _getLengths(bounds) { return [_getLength(bounds, 0), _getLength(bounds, 1), _getLength(bounds, 2)]; } function _getXRange(bounds) { return bounds.slice(0, 2); } function _getYRange(bounds) { return bounds.slice(2, 4); } function _getZRange(bounds) { return bounds.slice(4, 6); } function _getMaxLength(bounds) { var l = _getLengths(bounds); if (l[0] > l[1]) { if (l[0] > l[2]) { return l[0]; } return l[2]; } if (l[1] > l[2]) { return l[1]; } return l[2]; } function _getDiagonalLength(bounds) { if (_isValid(bounds)) { var l = _getLengths(bounds); return Math.sqrt(l[0] * l[0] + l[1] * l[1] + l[2] * l[2]); } return null; } function _getMinPoint(bounds) { return [bounds[0], bounds[2], bounds[4]]; } function _getMaxPoint(bounds) { return [bounds[1], bounds[3], bounds[5]]; } function oppositeSign(a, b) { return a <= 0 && b >= 0 || a >= 0 && b <= 0; } function _getCorners(bounds, corners) { var count = 0; for (var ix = 0; ix < 2; ix++) { for (var iy = 2; iy < 4; iy++) { for (var iz = 4; iz < 6; iz++) { corners[count++] = [bounds[ix], bounds[iy], bounds[iz]]; } } } return corners; } // Computes the two corners with minimal and miximal coordinates function _computeCornerPoints(bounds, point1, point2) { point1[0] = bounds[0]; point1[1] = bounds[2]; point1[2] = bounds[4]; point2[0] = bounds[1]; point2[1] = bounds[3]; point2[2] = bounds[5]; return point1; } function _transformBounds(bounds, transform) { var out = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : []; var corners = _getCorners(bounds, []); for (var i = 0; i < corners.length; ++i) { vec3.transformMat4(corners[i], corners[i], transform); } _reset(out); return _addPoints(out, corners); } function _computeScale(bounds) { var scale3 = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; scale3[0] = 0.5 * (bounds[1] - bounds[0]); scale3[1] = 0.5 * (bounds[3] - bounds[2]); scale3[2] = 0.5 * (bounds[5] - bounds[4]); return scale3; } function _computeLocalBounds(points, u, v, w) { var bounds = [].concat(INIT_BOUNDS); var pointsData = points.getData(); for (var i = 0; i < pointsData.length; i += 3) { var point = [pointsData[i], pointsData[i + 1], pointsData[i + 2]]; var du = dot(point, u); bounds[0] = Math.min(du, bounds[0]); bounds[1] = Math.max(du, bounds[1]); var dv = dot(point, v); bounds[2] = Math.min(dv, bounds[2]); bounds[3] = Math.max(dv, bounds[3]); var dw = dot(point, w); bounds[4] = Math.min(dw, bounds[4]); bounds[5] = Math.max(dw, bounds[5]); } return bounds; } // The method returns a non-zero value if the bounding box is hit. function _intersectBox(bounds, origin, dir, coord, tolerance) { var inside = true; var quadrant = []; var whichPlane = 0; var maxT = []; var candidatePlane = [0.0, 0.0, 0.0]; var RIGHT = 0; var LEFT = 1; var MIDDLE = 2; // First find closest planes for (var i = 0; i < 3; i++) { if (origin[i] < bounds[2 * i]) { quadrant[i] = LEFT; candidatePlane[i] = bounds[2 * i]; inside = false; } else if (origin[i] > bounds[2 * i + 1]) { quadrant[i] = RIGHT; candidatePlane[i] = bounds[2 * i + 1]; inside = false; } else { quadrant[i] = MIDDLE; } } // Check whether origin of ray is inside bbox if (inside) { coord[0] = origin[0]; coord[1] = origin[1]; coord[2] = origin[2]; tolerance[0] = 0; return 1; } // Calculate parametric distance to plane for (var _i2 = 0; _i2 < 3; _i2++) { if (quadrant[_i2] !== MIDDLE && dir[_i2] !== 0.0) { maxT[_i2] = (candidatePlane[_i2] - origin[_i2]) / dir[_i2]; } else { maxT[_i2] = -1.0; } } // Find the largest parametric value of intersection for (var _i3 = 0; _i3 < 3; _i3++) { if (maxT[whichPlane] < maxT[_i3]) { whichPlane = _i3; } } // Check for valie intersection along line if (maxT[whichPlane] > 1.0 || maxT[whichPlane] < 0.0) { return 0; } tolerance[0] = maxT[whichPlane]; // Intersection point along line is okay. Check bbox. for (var _i4 = 0; _i4 < 3; _i4++) { if (whichPlane !== _i4) { coord[_i4] = origin[_i4] + maxT[whichPlane] * dir[_i4]; if (coord[_i4] < bounds[2 * _i4] || coord[_i4] > bounds[2 * _i4 + 1]) { return 0; } } else { coord[_i4] = candidatePlane[_i4]; } } return 1; } // Plane intersection with box function _intersectPlane(bounds, origin, normal) { var p = []; var d = 0; var sign = 1; var firstOne = 1; // Evaluate the eight points. If there is a sign change, there is an intersection for (var z = 4; z <= 5; ++z) { p[2] = bounds[z]; for (var y = 2; y <= 3; ++y) { p[1] = bounds[y]; for (var x = 0; x <= 1; ++x) { p[0] = bounds[x]; d = vtkPlane.evaluate(normal, origin, p); if (firstOne) { sign = d >= 0 ? 1 : -1; firstOne = 0; } if (d === 0.0 || sign > 0 && d < 0.0 || sign < 0 && d > 0.0) { return 1; } } } } return 0; // no intersection } function _intersect(bounds, bBounds) { if (!(_isValid(bounds) && _isValid(bBounds))) { return false; } var newBounds = [0, 0, 0, 0, 0, 0]; var intersection; for (var i = 0; i < 3; i++) { intersection = false; if (bBounds[i * 2] >= bounds[i * 2] && bBounds[i * 2] <= bounds[i * 2 + 1]) { intersection = true; newBounds[i * 2] = bBounds[i * 2]; } else if (bounds[i * 2] >= bBounds[i * 2] && bounds[i * 2] <= bBounds[i * 2 + 1]) { intersection = true; newBounds[i * 2] = bounds[i * 2]; } if (bBounds[i * 2 + 1] >= bounds[i * 2] && bBounds[i * 2 + 1] <= bounds[i * 2 + 1]) { intersection = true; newBounds[i * 2 + 1] = bBounds[2 * i + 1]; } else if (bounds[i * 2 + 1] >= bBounds[i * 2] && bounds[i * 2 + 1] <= bBounds[i * 2 + 1]) { intersection = true; newBounds[i * 2 + 1] = bounds[i * 2 + 1]; } if (!intersection) { return false; } } // OK they did intersect - set the box to be the result bounds[0] = newBounds[0]; bounds[1] = newBounds[1]; bounds[2] = newBounds[2]; bounds[3] = newBounds[3]; bounds[4] = newBounds[4]; bounds[5] = newBounds[5]; return true; } function _intersects(bounds, bBounds) { if (!(_isValid(bounds) && _isValid(bBounds))) { return false; } /* eslint-disable no-continue */ for (var i = 0; i < 3; i++) { if (bBounds[i * 2] >= bounds[i * 2] && bBounds[i * 2] <= bounds[i * 2 + 1]) { continue; } else if (bounds[i * 2] >= bBounds[i * 2] && bounds[i * 2] <= bBounds[i * 2 + 1]) { continue; } if (bBounds[i * 2 + 1] >= bounds[i * 2] && bBounds[i * 2 + 1] <= bounds[i * 2 + 1]) { continue; } else if (bounds[i * 2 + 1] >= bBounds[i * 2] && bounds[i * 2 + 1] <= bBounds[i * 2 + 1]) { continue; } return false; } /* eslint-enable no-continue */ return true; } function _containsPoint(bounds, x, y, z) { if (x < bounds[0] || x > bounds[1]) { return false; } if (y < bounds[2] || y > bounds[3]) { return false; } if (z < bounds[4] || z > bounds[5]) { return false; } return true; } function contains(bounds, otherBounds) { // if either box is not valid or they don't intersect if (!_intersects(bounds, otherBounds)) { return false; } if (!_containsPoint.apply(void 0, [bounds].concat(_toConsumableArray(_getMinPoint(otherBounds))))) { return false; } if (!_containsPoint.apply(void 0, [bounds].concat(_toConsumableArray(_getMaxPoint(otherBounds))))) { return false; } return true; } /** * Returns true if plane intersects bounding box. * If so, the box is cut by the plane * @param {array} origin * @param {array} normal */ function _cutWithPlane(bounds, origin, normal) { // Index[0..2] represents the order of traversing the corners of a cube // in (x,y,z), (y,x,z) and (z,x,y) ordering, respectively var index = [[0, 1, 2, 3, 4, 5, 6, 7], [0, 1, 4, 5, 2, 3, 6, 7], [0, 2, 4, 6, 1, 3, 5, 7]]; // stores the signed distance to a plane var d = [0, 0, 0, 0, 0, 0, 0, 0]; var idx = 0; for (var ix = 0; ix < 2; ix++) { for (var iy = 2; iy < 4; iy++) { for (var iz = 4; iz < 6; iz++) { var x = [bounds[ix], bounds[iy], bounds[iz]]; d[idx++] = vtkPlane.evaluate(normal, origin, x); } } } var dir = 2; while (dir--) { // in each direction, we test if the vertices of two orthogonal faces // are on either side of the plane if (oppositeSign(d[index[dir][0]], d[index[dir][4]]) && oppositeSign(d[index[dir][1]], d[index[dir][5]]) && oppositeSign(d[index[dir][2]], d[index[dir][6]]) && oppositeSign(d[index[dir][3]], d[index[dir][7]])) { break; } } if (dir < 0) { return false; } var sign = Math.sign(normal[dir]); var size = Math.abs((bounds[dir * 2 + 1] - bounds[dir * 2]) * normal[dir]); var t = sign > 0 ? 1 : 0; /* eslint-disable no-continue */ for (var i = 0; i < 4; i++) { if (size === 0) { continue; // shouldn't happen } var ti = Math.abs(d[index[dir][i]]) / size; if (sign > 0 && ti < t) { t = ti; } if (sign < 0 && ti > t) { t = ti; } } /* eslint-enable no-continue */ var bound = (1.0 - t) * bounds[dir * 2] + t * bounds[dir * 2 + 1]; if (sign > 0) { bounds[dir * 2] = bound; } else { bounds[dir * 2 + 1] = bound; } return true; } // ---------------------------------------------------------------------------- var BoundingBox = /*#__PURE__*/function () { function BoundingBox(refBounds) { _classCallCheck(this, BoundingBox); this.bounds = refBounds; if (!this.bounds) { this.bounds = new Float64Array(INIT_BOUNDS); } } _createClass(BoundingBox, [{ key: "getBounds", value: function getBounds() { return this.bounds; } }, { key: "equals", value: function equals(otherBounds) { return _equals(this.bounds, otherBounds); } }, { key: "isValid", value: function isValid() { return _isValid(this.bounds); } }, { key: "setBounds", value: function setBounds(otherBounds) { return _setBounds(this.bounds, otherBounds); } }, { key: "reset", value: function reset() { return _reset(this.bounds); } }, { key: "addPoint", value: function addPoint() { for (var _len = arguments.length, xyz = new Array(_len), _key = 0; _key < _len; _key++) { xyz[_key] = arguments[_key]; } return _addPoint.apply(void 0, [this.bounds].concat(xyz)); } }, { key: "addPoints", value: function addPoints(points) { return _addPoints(this.bounds, points); } }, { key: "addBounds", value: function addBounds(xMin, xMax, yMin, yMax, zMin, zMax) { return _addBounds(this.bounds, xMin, xMax, yMin, yMax, zMin, zMax); } }, { key: "setMinPoint", value: function setMinPoint(x, y, z) { return _setMinPoint(this.bounds, x, y, z); } }, { key: "setMaxPoint", value: function setMaxPoint(x, y, z) { return _setMaxPoint(this.bounds, x, y, z); } }, { key: "inflate", value: function inflate(delta) { return _inflate(this.bounds, delta); } }, { key: "scale", value: function scale(sx, sy, sz) { return _scale(this.bounds, sx, sy, sz); } }, { key: "getCenter", value: function getCenter() { return _getCenter(this.bounds); } }, { key: "getLength", value: function getLength(index) { return _getLength(this.bounds, index); } }, { key: "getLengths", value: function getLengths() { return _getLengths(this.bounds); } }, { key: "getMaxLength", value: function getMaxLength() { return _getMaxLength(this.bounds); } }, { key: "getDiagonalLength", value: function getDiagonalLength() { return _getDiagonalLength(this.bounds); } }, { key: "getMinPoint", value: function getMinPoint() { return _getMinPoint(this.bounds); } }, { key: "getMaxPoint", value: function getMaxPoint() { return _getMaxPoint(this.bounds); } }, { key: "getXRange", value: function getXRange() { return _getXRange(this.bounds); } }, { key: "getYRange", value: function getYRange() { return _getYRange(this.bounds); } }, { key: "getZRange", value: function getZRange() { return _getZRange(this.bounds); } }, { key: "getCorners", value: function getCorners(corners) { return _getCorners(this.bounds, corners); } }, { key: "computeCornerPoints", value: function computeCornerPoints(point1, point2) { return _computeCornerPoints(this.bounds, point1, point2); } }, { key: "computeLocalBounds", value: function computeLocalBounds(u, v, w) { return _computeLocalBounds(this.bounds, u, v, w); } }, { key: "transformBounds", value: function transformBounds(transform) { var out = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : []; return _transformBounds(this.bounds, transform, out); } }, { key: "computeScale3", value: function computeScale3(scale3) { return _computeScale(this.bounds, scale3); } }, { key: "cutWithPlane", value: function cutWithPlane(origin, normal) { return _cutWithPlane(this.bounds, origin, normal); } }, { key: "intersectBox", value: function intersectBox(origin, dir, coord, tolerance) { return _intersectBox(this.bounds, origin, dir, coord, tolerance); } }, { key: "intersectPlane", value: function intersectPlane(origin, normal) { return _intersectPlane(this.bounds, origin, normal); } }, { key: "intersect", value: function intersect(otherBounds) { return _intersect(this.bounds, otherBounds); } }, { key: "intersects", value: function intersects(otherBounds) { return _intersects(this.bounds, otherBounds); } }, { key: "containsPoint", value: function containsPoint(x, y, z) { return _containsPoint(this.bounds, x, y, z); } }, { key: "contains", value: function contains(otherBounds) { return _intersects(this.bounds, otherBounds); } }]); return BoundingBox; }(); function newInstance(initialValues) { var bounds = initialValues && initialValues.bounds; return new BoundingBox(bounds); } // ---------------------------------------------------------------------------- // Static API // ---------------------------------------------------------------------------- var STATIC = { equals: _equals, isValid: _isValid, setBounds: _setBounds, reset: _reset, addPoint: _addPoint, addPoints: _addPoints, addBounds: _addBounds, setMinPoint: _setMinPoint, setMaxPoint: _setMaxPoint, inflate: _inflate, scale: _scale, scaleAboutCenter: scaleAboutCenter, getCenter: _getCenter, getLength: _getLength, getLengths: _getLengths, getMaxLength: _getMaxLength, getDiagonalLength: _getDiagonalLength, getMinPoint: _getMinPoint, getMaxPoint: _getMaxPoint, getXRange: _getXRange, getYRange: _getYRange, getZRange: _getZRange, getCorners: _getCorners, computeCornerPoints: _computeCornerPoints, computeLocalBounds: _computeLocalBounds, transformBounds: _transformBounds, computeScale3: _computeScale, cutWithPlane: _cutWithPlane, intersectBox: _intersectBox, intersectPlane: _intersectPlane, intersect: _intersect, intersects: _intersects, containsPoint: _containsPoint, contains: contains, INIT_BOUNDS: INIT_BOUNDS }; var vtkBoundingBox = _objectSpread({ newInstance: newInstance }, STATIC); export { STATIC, _addBounds as addBounds, _addPoint as addPoint, _addPoints as addPoints, _computeCornerPoints as computeCornerPoints, _computeLocalBounds as computeLocalBounds, _computeScale as computeScale3, contains, _containsPoint as containsPoint, _cutWithPlane as cutWithPlane, vtkBoundingBox as default, _equals as equals, _getCenter as getCenter, _getCorners as getCorners, _getDiagonalLength as getDiagonalLength, _getLength as getLength, _getLengths as getLengths, _getMaxLength as getMaxLength, _getMaxPoint as getMaxPoint, _getMinPoint as getMinPoint, _getXRange as getXRange, _getYRange as getYRange, _getZRange as getZRange, _inflate as inflate, _intersect as intersect, _intersectBox as intersectBox, _intersectPlane as intersectPlane, _intersects as intersects, _isValid as isValid, _reset as reset, _scale as scale, scaleAboutCenter, _setBounds as setBounds, _setMaxPoint as setMaxPoint, _setMinPoint as setMinPoint, _transformBounds as transformBounds };