UNPKG

molstar

Version:

A comprehensive macromolecular library.

253 lines 9.62 kB
"use strict"; /** * Copyright (c) 2019-2020 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.parsePly = void 0; var tslib_1 = require("tslib"); var result_1 = require("../result"); var mol_task_1 = require("../../../mol-task"); var schema_1 = require("./schema"); var tokenizer_1 = require("../common/text/tokenizer"); var db_1 = require("../../../mol-data/db"); var token_1 = require("../common/text/column/token"); function State(data, runtimeCtx) { var tokenizer = (0, tokenizer_1.Tokenizer)(data); return { data: data, tokenizer: tokenizer, runtimeCtx: runtimeCtx, comments: [], elementSpecs: [], elements: [] }; } function markHeader(tokenizer) { var endHeaderIndex = tokenizer.data.indexOf('end_header', tokenizer.position); if (endHeaderIndex === -1) throw new Error("no 'end_header' record found"); // TODO set `tokenizer.lineNumber` correctly tokenizer.tokenStart = tokenizer.position; tokenizer.tokenEnd = endHeaderIndex; tokenizer.position = endHeaderIndex; tokenizer_1.Tokenizer.eatLine(tokenizer); } function parseHeader(state) { var tokenizer = state.tokenizer, comments = state.comments, elementSpecs = state.elementSpecs; markHeader(tokenizer); var headerLines = tokenizer_1.Tokenizer.getTokenString(tokenizer).split(/\r?\n/); if (headerLines[0] !== 'ply') throw new Error("data not starting with 'ply'"); if (headerLines[1] !== 'format ascii 1.0') throw new Error("format not 'ascii 1.0'"); var currentName; var currentCount; var currentProperties; function addCurrentElementSchema() { if (currentName !== undefined && currentCount !== undefined && currentProperties !== undefined) { var isList = false; for (var i = 0, il = currentProperties.length; i < il; ++i) { var p = currentProperties[i]; if (p.kind === 'list') { isList = true; break; } } if (isList && currentProperties.length !== 1) { // TODO handle lists with appended properties // currently only the list part will be accessible } if (isList) { elementSpecs.push({ kind: 'list', name: currentName, count: currentCount, property: currentProperties[0] }); } else { elementSpecs.push({ kind: 'table', name: currentName, count: currentCount, properties: currentProperties }); } } } for (var i = 2, il = headerLines.length; i < il; ++i) { var l = headerLines[i]; var ls = l.split(' '); if (l.startsWith('comment')) { comments.push(l.substr(8)); } else if (l.startsWith('element')) { addCurrentElementSchema(); currentProperties = []; currentName = ls[1]; currentCount = parseInt(ls[2]); } else if (l.startsWith('property')) { if (currentProperties === undefined) throw new Error("properties outside of element"); if (ls[1] === 'list') { currentProperties.push({ kind: 'list', countType: (0, schema_1.PlyType)(ls[2]), dataType: (0, schema_1.PlyType)(ls[3]), name: ls[4] }); } else { currentProperties.push({ kind: 'column', type: (0, schema_1.PlyType)(ls[1]), name: ls[2] }); } } else if (l.startsWith('end_header')) { addCurrentElementSchema(); } else { console.warn('unknown header line'); } } } function parseElements(state) { var elementSpecs = state.elementSpecs; for (var i = 0, il = elementSpecs.length; i < il; ++i) { var spec = elementSpecs[i]; if (spec.kind === 'table') parseTableElement(state, spec); else if (spec.kind === 'list') parseListElement(state, spec); } } function getColumnSchema(type) { switch (type) { case 'char': case 'uchar': case 'int8': case 'uint8': case 'short': case 'ushort': case 'int16': case 'uint16': case 'int': case 'uint': case 'int32': case 'uint32': return db_1.Column.Schema.int; case 'float': case 'double': case 'float32': case 'float64': return db_1.Column.Schema.float; } } function parseTableElement(state, spec) { var elements = state.elements, tokenizer = state.tokenizer; var count = spec.count, properties = spec.properties; var propertyCount = properties.length; var propertyNames = []; var propertyTypes = []; var propertyTokens = []; var propertyColumns = new Map(); for (var i = 0, il = propertyCount; i < il; ++i) { var tokens = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2); propertyTokens.push(tokens); } for (var i = 0, il = count; i < il; ++i) { for (var j = 0, jl = propertyCount; j < jl; ++j) { tokenizer_1.Tokenizer.skipWhitespace(tokenizer); tokenizer_1.Tokenizer.markStart(tokenizer); tokenizer_1.Tokenizer.eatValue(tokenizer); tokenizer_1.TokenBuilder.addUnchecked(propertyTokens[j], tokenizer.tokenStart, tokenizer.tokenEnd); } } for (var i = 0, il = propertyCount; i < il; ++i) { var _a = properties[i], type = _a.type, name_1 = _a.name; var column = (0, token_1.TokenColumn)(propertyTokens[i], getColumnSchema(type)); propertyNames.push(name_1); propertyTypes.push(type); propertyColumns.set(name_1, column); } elements.push({ kind: 'table', rowCount: count, propertyNames: propertyNames, propertyTypes: propertyTypes, getProperty: function (name) { return propertyColumns.get(name); } }); } function parseListElement(state, spec) { var elements = state.elements, tokenizer = state.tokenizer; var count = spec.count, property = spec.property; // initial tokens size assumes triangle index data var tokens = tokenizer_1.TokenBuilder.create(tokenizer.data, count * 2 * 3); var offsets = new Uint32Array(count + 1); var entryCount = 0; for (var i = 0, il = count; i < il; ++i) { tokenizer_1.Tokenizer.skipWhitespace(tokenizer); tokenizer_1.Tokenizer.markStart(tokenizer); while (tokenizer_1.Tokenizer.skipWhitespace(tokenizer) !== 10) { ++entryCount; tokenizer_1.Tokenizer.markStart(tokenizer); tokenizer_1.Tokenizer.eatValue(tokenizer); tokenizer_1.TokenBuilder.addToken(tokens, tokenizer); } offsets[i + 1] = entryCount; } /** holds row value entries transiently */ var listValue = { entries: [], count: 0 }; var column = (0, token_1.TokenColumn)(tokens, getColumnSchema(property.dataType)); elements.push({ kind: 'list', rowCount: count, name: property.name, type: property.dataType, value: function (row) { var offset = offsets[row] + 1; var count = column.value(offset - 1); for (var i = offset, il = offset + count; i < il; ++i) { listValue.entries[i - offset] = column.value(i); } listValue.count = count; return listValue; } }); } function parseInternal(data, ctx) { return (0, tslib_1.__awaiter)(this, void 0, void 0, function () { var state, elements, elementSpecs, comments, elementNames, result; return (0, tslib_1.__generator)(this, function (_a) { state = State(data, ctx); ctx.update({ message: 'Parsing...', current: 0, max: data.length }); parseHeader(state); parseElements(state); elements = state.elements, elementSpecs = state.elementSpecs, comments = state.comments; elementNames = elementSpecs.map(function (s) { return s.name; }); result = (0, schema_1.PlyFile)(elements, elementNames, comments); return [2 /*return*/, result_1.ReaderResult.success(result)]; }); }); } function parsePly(data) { var _this = this; return mol_task_1.Task.create('Parse PLY', function (ctx) { return (0, tslib_1.__awaiter)(_this, void 0, void 0, function () { return (0, tslib_1.__generator)(this, function (_a) { switch (_a.label) { case 0: return [4 /*yield*/, parseInternal(data, ctx)]; case 1: return [2 /*return*/, _a.sent()]; } }); }); }); } exports.parsePly = parsePly; //# sourceMappingURL=parser.js.map