molstar
Version:
A comprehensive macromolecular library.
148 lines (147 loc) • 5.95 kB
JavaScript
/**
* Copyright (c) 2019 mol* contributors, licensed under MIT, See LICENSE file for more info.
*
* @author Alexander Rose <alexander.rose@weirdbyte.de>
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.dsn6HeaderSize = void 0;
exports.readDsn6Header = readDsn6Header;
exports.parseDsn6Values = parseDsn6Values;
exports.getDsn6Counts = getDsn6Counts;
exports.parseFile = parseFile;
exports.parse = parse;
const mol_task_1 = require("../../../mol-task");
const result_1 = require("../result");
const file_handle_1 = require("../../common/file-handle");
const simple_buffer_1 = require("../../../mol-io/common/simple-buffer");
exports.dsn6HeaderSize = 512;
function parseBrixHeader(str) {
return {
xStart: parseInt(str.substr(10, 5)),
yStart: parseInt(str.substr(15, 5)),
zStart: parseInt(str.substr(20, 5)),
xExtent: parseInt(str.substr(32, 5)),
yExtent: parseInt(str.substr(38, 5)),
zExtent: parseInt(str.substr(42, 5)),
xRate: parseInt(str.substr(52, 5)),
yRate: parseInt(str.substr(58, 5)),
zRate: parseInt(str.substr(62, 5)),
xlen: parseFloat(str.substr(73, 10)),
ylen: parseFloat(str.substr(83, 10)),
zlen: parseFloat(str.substr(93, 10)),
alpha: parseFloat(str.substr(103, 10)),
beta: parseFloat(str.substr(113, 10)),
gamma: parseFloat(str.substr(123, 10)),
divisor: parseFloat(str.substr(138, 12)),
summand: parseInt(str.substr(155, 8)),
sigma: parseFloat(str.substr(170, 12))
};
}
function parseDsn6Header(buffer, littleEndian) {
const readInt = littleEndian ? (o) => buffer.readInt16LE(o * 2) : (o) => buffer.readInt16BE(o * 2);
const factor = 1 / readInt(17);
return {
xStart: readInt(0),
yStart: readInt(1),
zStart: readInt(2),
xExtent: readInt(3),
yExtent: readInt(4),
zExtent: readInt(5),
xRate: readInt(6),
yRate: readInt(7),
zRate: readInt(8),
xlen: readInt(9) * factor,
ylen: readInt(10) * factor,
zlen: readInt(11) * factor,
alpha: readInt(12) * factor,
beta: readInt(13) * factor,
gamma: readInt(14) * factor,
divisor: readInt(15) / 100,
summand: readInt(16),
sigma: undefined
};
}
function getBlocks(header) {
const { xExtent, yExtent, zExtent } = header;
const xBlocks = Math.ceil(xExtent / 8);
const yBlocks = Math.ceil(yExtent / 8);
const zBlocks = Math.ceil(zExtent / 8);
return { xBlocks, yBlocks, zBlocks };
}
async function readDsn6Header(file) {
const { buffer } = await file.readBuffer(0, exports.dsn6HeaderSize);
const brixStr = String.fromCharCode.apply(null, buffer);
const isBrix = brixStr.startsWith(':-)');
const littleEndian = isBrix || buffer.readInt16LE(18 * 2) === 100;
const header = isBrix ? parseBrixHeader(brixStr) : parseDsn6Header(buffer, littleEndian);
return { header, littleEndian };
}
async function parseDsn6Values(header, source, target, littleEndian) {
if (!littleEndian) {
// even though the values are one byte they need to be swapped like they are 2
simple_buffer_1.SimpleBuffer.flipByteOrderInPlace2(source.buffer);
}
const { divisor, summand, xExtent, yExtent, zExtent } = header;
const { xBlocks, yBlocks, zBlocks } = getBlocks(header);
let offset = 0;
// loop over blocks
for (let zz = 0; zz < zBlocks; ++zz) {
for (let yy = 0; yy < yBlocks; ++yy) {
for (let xx = 0; xx < xBlocks; ++xx) {
// loop inside block
for (let k = 0; k < 8; ++k) {
const z = 8 * zz + k;
for (let j = 0; j < 8; ++j) {
const y = 8 * yy + j;
for (let i = 0; i < 8; ++i) {
const x = 8 * xx + i;
// check if remaining slice-part contains values
if (x < xExtent && y < yExtent && z < zExtent) {
const idx = ((((x * yExtent) + y) * zExtent) + z);
target[idx] = (source[offset] - summand) / divisor;
++offset;
}
else {
offset += 8 - i;
break;
}
}
}
}
}
}
}
}
function getDsn6Counts(header) {
const { xExtent, yExtent, zExtent } = header;
const { xBlocks, yBlocks, zBlocks } = getBlocks(header);
const valueCount = xExtent * yExtent * zExtent;
const count = xBlocks * 8 * yBlocks * 8 * zBlocks * 8;
const elementByteSize = 1;
const byteCount = count * elementByteSize;
return { count, byteCount, valueCount };
}
async function parseInternal(file, size, ctx) {
await ctx.update({ message: 'Parsing DSN6/BRIX file...' });
const { header, littleEndian } = await readDsn6Header(file);
const { buffer } = await file.readBuffer(exports.dsn6HeaderSize, size - exports.dsn6HeaderSize);
const { valueCount } = getDsn6Counts(header);
const values = new Float32Array(valueCount);
await parseDsn6Values(header, buffer, values, littleEndian);
const result = { header, values, name: file.name };
return result;
}
function parseFile(file, size) {
return mol_task_1.Task.create('Parse DSN6/BRIX', async (ctx) => {
try {
return result_1.ReaderResult.success(await parseInternal(file, size, ctx));
}
catch (e) {
return result_1.ReaderResult.error(e);
}
});
}
function parse(buffer, name) {
return parseFile(file_handle_1.FileHandle.fromBuffer(simple_buffer_1.SimpleBuffer.fromUint8Array(buffer), name), buffer.length);
}
;