UNPKG

molstar

Version:

A comprehensive macromolecular library.

107 lines (106 loc) 4.12 kB
/** * Copyright (c) 2018 mol* contributors, licensed under MIT, See LICENSE file for more info. * * Taken/adapted from DensityServer (https://github.com/dsehnal/DensityServer) * * @author David Sehnal <david.sehnal@gmail.com> */ import * as Coords from '../algebra/coordinate'; import * as Box from '../algebra/box'; // import { FastMap } from '../utils/collections' /** Find a list of unique blocks+offsets that overlap with the query region. */ export function findUniqueBlocks(data, sampling, queryBox) { var translations = data.header.spacegroup.isPeriodic // find all query box translations that overlap with the unit cell. ? findDataOverlapTranslationList(queryBox, sampling.dataDomain) // no translations : [Coords.fractional(0, 0, 0)]; var blocks = new Map(); for (var _i = 0, translations_1 = translations; _i < translations_1.length; _i++) { var t = translations_1[_i]; findUniqueBlocksOffset(data, sampling, queryBox, t, blocks); } var blockList = []; blocks.forEach(function (b) { this.push(b); }, blockList); // sort the data so that the first coodinate changes the fastest // this is because that's how the data is laid out in the underlaying // data format and reading the data 'in order' makes it faster. blockList.sort(function (a, b) { var x = a.coord, y = b.coord; for (var i = 2; i >= 0; i--) { if (x[i] !== y[i]) return x[i] - y[i]; } return 0; }); return blockList; } /** * Find the integer interval [x, y] so that for all k \in [x, y] * [a + k, b + k] intersects with (u, v) */ function overlapMultiplierRange(a, b, u, v) { var x = Math.ceil(u - b) | 0, y = Math.floor(v - a) | 0; if (Coords.round(b + x) <= Coords.round(u)) x++; if (Coords.round(a + y) >= Coords.round(v)) y--; if (x > y) return void 0; return [x, y]; } /** * Finds that list of "unit" offsets (in fractional space) so that * shift(box, offset) has non-empty interaction with the region * described in the give domain. */ function findDataOverlapTranslationList(box, domain) { var ranges = []; var translations = []; var origin = domain.origin, dimensions = domain.dimensions; for (var i = 0; i < 3; i++) { var range = overlapMultiplierRange(box.a[i], box.b[i], origin[i], origin[i] + dimensions[i]); if (!range) return translations; ranges[i] = range; } var u = ranges[0], v = ranges[1], w = ranges[2]; for (var k = w[0]; k <= w[1]; k++) { for (var j = v[0]; j <= v[1]; j++) { for (var i = u[0]; i <= u[1]; i++) { translations.push(Coords.fractional(i, j, k)); } } } return translations; } function addUniqueBlock(blocks, coord, offset) { var hash = Coords.linearGridIndex(coord); if (blocks.has(hash)) { var entry = blocks.get(hash); entry.offsets.push(offset); } else { blocks.set(hash, { coord: coord, offsets: [offset] }); } } function findUniqueBlocksOffset(data, sampling, queryBox, offset, blocks) { var shifted = Box.shift(queryBox, offset); var intersection = Box.intersect(shifted, data.dataBox); // Intersection can be empty in the case of "aperiodic spacegroups" if (!intersection) return; var blockDomain = sampling.blockDomain; // this gets the "3d range" of block indices that contain data that overlaps // with the query region. // // Clamping the data makes sure we avoid silly rounding errors (hopefully :)) var _a = Box.clampGridToSamples(Box.fractionalToGrid(intersection, blockDomain)), min = _a.a, max = _a.b; for (var i = min[0]; i < max[0]; i++) { for (var j = min[1]; j < max[1]; j++) { for (var k = min[2]; k < max[2]; k++) { addUniqueBlock(blocks, Coords.grid(blockDomain, i, j, k), offset); } } } }