molstar
Version:
A comprehensive macromolecular library.
199 lines • 8.32 kB
JavaScript
"use strict";
/**
* Copyright (c) 2018-2020 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author David Sehnal <david.sehnal@gmail.com>
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.GridLookup3D = void 0;
var common_1 = require("./common");
var box3d_1 = require("../primitives/box3d");
var linear_algebra_1 = require("../../linear-algebra");
var int_1 = require("../../../mol-data/int");
function GridLookup3D(data, boundary, cellSizeOrCount) {
return new GridLookup3DImpl(data, boundary, cellSizeOrCount);
}
exports.GridLookup3D = GridLookup3D;
var GridLookup3DImpl = /** @class */ (function () {
function GridLookup3DImpl(data, boundary, cellSizeOrCount) {
var structure = build(data, boundary, cellSizeOrCount);
this.ctx = createContext(structure);
this.boundary = { box: structure.boundingBox, sphere: structure.boundingSphere };
this.buckets = { offset: structure.bucketOffset, count: structure.bucketCounts, array: structure.bucketArray };
this.result = common_1.Result.create();
}
GridLookup3DImpl.prototype.find = function (x, y, z, radius, result) {
this.ctx.x = x;
this.ctx.y = y;
this.ctx.z = z;
this.ctx.radius = radius;
this.ctx.isCheck = false;
var ret = result !== null && result !== void 0 ? result : this.result;
query(this.ctx, ret);
return ret;
};
GridLookup3DImpl.prototype.check = function (x, y, z, radius) {
this.ctx.x = x;
this.ctx.y = y;
this.ctx.z = z;
this.ctx.radius = radius;
this.ctx.isCheck = true;
return query(this.ctx, this.result);
};
return GridLookup3DImpl;
}());
function _build(state) {
var expandedBox = state.expandedBox, _a = state.size, sX = _a[0], sY = _a[1], sZ = _a[2], _b = state.data, px = _b.x, py = _b.y, pz = _b.z, radius = _b.radius, indices = _b.indices, elementCount = state.elementCount, delta = state.delta;
var n = sX * sY * sZ;
var _c = expandedBox.min, minX = _c[0], minY = _c[1], minZ = _c[2];
var maxRadius = 0;
var bucketCount = 0;
var grid = new Uint32Array(n);
var bucketIndex = new Int32Array(elementCount);
for (var t = 0; t < elementCount; t++) {
var i = int_1.OrderedSet.getAt(indices, t);
var x = Math.floor((px[i] - minX) / delta[0]);
var y = Math.floor((py[i] - minY) / delta[1]);
var z = Math.floor((pz[i] - minZ) / delta[2]);
var idx = (((x * sY) + y) * sZ) + z;
if ((grid[idx] += 1) === 1) {
bucketCount += 1;
}
bucketIndex[t] = idx;
}
if (radius) {
for (var t = 0; t < elementCount; t++) {
var i = int_1.OrderedSet.getAt(indices, t);
if (radius[i] > maxRadius)
maxRadius = radius[i];
}
}
var bucketCounts = new Int32Array(bucketCount);
for (var i = 0, j = 0; i < n; i++) {
var c = grid[i];
if (c > 0) {
grid[i] = j + 1;
bucketCounts[j] = c;
j += 1;
}
}
var bucketOffset = new Uint32Array(bucketCount);
for (var i = 1; i < bucketCount; ++i) {
bucketOffset[i] += bucketOffset[i - 1] + bucketCounts[i - 1];
}
var bucketFill = new Int32Array(bucketCount);
var bucketArray = new Int32Array(elementCount);
for (var i = 0; i < elementCount; i++) {
var bucketIdx = grid[bucketIndex[i]];
if (bucketIdx > 0) {
var k = bucketIdx - 1;
bucketArray[bucketOffset[k] + bucketFill[k]] = i;
bucketFill[k] += 1;
}
}
return {
size: state.size,
bucketArray: bucketArray,
bucketCounts: bucketCounts,
bucketOffset: bucketOffset,
grid: grid,
delta: delta,
min: state.expandedBox.min,
data: state.data,
maxRadius: maxRadius,
expandedBox: state.expandedBox,
boundingBox: state.boundingBox,
boundingSphere: state.boundingSphere
};
}
function build(data, boundary, cellSizeOrCount) {
// need to expand the grid bounds to avoid rounding errors
var expandedBox = box3d_1.Box3D.expand((0, box3d_1.Box3D)(), boundary.box, linear_algebra_1.Vec3.create(0.5, 0.5, 0.5));
var indices = data.indices;
var S = box3d_1.Box3D.size(linear_algebra_1.Vec3.zero(), expandedBox);
var delta, size;
var elementCount = int_1.OrderedSet.size(indices);
var cellCount = typeof cellSizeOrCount === 'number' ? cellSizeOrCount : 32;
var cellSize = Array.isArray(cellSizeOrCount) && cellSizeOrCount;
if (cellSize) {
size = [Math.ceil(S[0] / cellSize[0]), Math.ceil(S[1] / cellSize[1]), Math.ceil(S[2] / cellSize[2])];
delta = cellSize;
}
else if (elementCount > 0) {
// size of the box
// required "grid volume" so that each cell contains on average 'cellCount' elements.
var V = Math.ceil(elementCount / cellCount);
var f = Math.pow(V / (S[0] * S[1] * S[2]), 1 / 3);
size = [Math.ceil(S[0] * f), Math.ceil(S[1] * f), Math.ceil(S[2] * f)];
delta = [S[0] / size[0], S[1] / size[1], S[2] / size[2]];
}
else {
delta = S;
size = [1, 1, 1];
}
var inputData = {
x: data.x,
y: data.y,
z: data.z,
indices: indices,
radius: data.radius
};
var state = {
size: size,
data: inputData,
expandedBox: expandedBox,
boundingBox: boundary.box,
boundingSphere: boundary.sphere,
elementCount: elementCount,
delta: delta
};
return _build(state);
}
function createContext(grid) {
return { grid: grid, x: 0.1, y: 0.1, z: 0.1, radius: 0.1, isCheck: false };
}
function query(ctx, result) {
var _a = ctx.grid, min = _a.min, _b = _a.size, sX = _b[0], sY = _b[1], sZ = _b[2], bucketOffset = _a.bucketOffset, bucketCounts = _a.bucketCounts, bucketArray = _a.bucketArray, grid = _a.grid, _c = _a.data, px = _c.x, py = _c.y, pz = _c.z, indices = _c.indices, radius = _c.radius, delta = _a.delta, maxRadius = _a.maxRadius;
var inputRadius = ctx.radius, isCheck = ctx.isCheck, x = ctx.x, y = ctx.y, z = ctx.z;
var r = inputRadius + maxRadius;
var rSq = r * r;
common_1.Result.reset(result);
var loX = Math.max(0, Math.floor((x - r - min[0]) / delta[0]));
var loY = Math.max(0, Math.floor((y - r - min[1]) / delta[1]));
var loZ = Math.max(0, Math.floor((z - r - min[2]) / delta[2]));
var hiX = Math.min(sX - 1, Math.floor((x + r - min[0]) / delta[0]));
var hiY = Math.min(sY - 1, Math.floor((y + r - min[1]) / delta[1]));
var hiZ = Math.min(sZ - 1, Math.floor((z + r - min[2]) / delta[2]));
if (loX > hiX || loY > hiY || loZ > hiZ)
return false;
for (var ix = loX; ix <= hiX; ix++) {
for (var iy = loY; iy <= hiY; iy++) {
for (var iz = loZ; iz <= hiZ; iz++) {
var bucketIdx = grid[(((ix * sY) + iy) * sZ) + iz];
if (bucketIdx === 0)
continue;
var k = bucketIdx - 1;
var offset = bucketOffset[k];
var count = bucketCounts[k];
var end = offset + count;
for (var i = offset; i < end; i++) {
var idx = int_1.OrderedSet.getAt(indices, bucketArray[i]);
var dx = px[idx] - x;
var dy = py[idx] - y;
var dz = pz[idx] - z;
var distSq = dx * dx + dy * dy + dz * dz;
if (distSq <= rSq) {
if (maxRadius > 0 && Math.sqrt(distSq) - radius[idx] > inputRadius)
continue;
if (isCheck)
return true;
common_1.Result.add(result, bucketArray[i], distSq);
}
}
}
}
}
return result.count > 0;
}
//# sourceMappingURL=grid.js.map