UNPKG

molstar

Version:

A comprehensive macromolecular library.

199 lines 8.32 kB
"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