forked from enviPath/enviPy
302 lines
9.1 KiB
JavaScript
302 lines
9.1 KiB
JavaScript
/****************************************************************************
|
|
* Copyright 2017 EPAM Systems
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
***************************************************************************/
|
|
|
|
var Set = require('../../util/set');
|
|
var Vec2 = require('../../util/vec2');
|
|
|
|
var Struct = require('./../struct/index');
|
|
var utils = require('./utils');
|
|
|
|
function readKeyValuePairs(str, /* bool */ valueString) {
|
|
/* reader */
|
|
var ret = {};
|
|
var partition = utils.partitionLineFixed(str, 3, true);
|
|
var count = utils.parseDecimalInt(partition[0]);
|
|
for (var i = 0; i < count; ++i) {
|
|
/* eslint-disable no-mixed-operators*/
|
|
ret[utils.parseDecimalInt(partition[2 * i + 1]) - 1] =
|
|
valueString ? partition[2 * i + 2].trim() :
|
|
utils.parseDecimalInt(partition[2 * i + 2]);
|
|
/* eslint-enable no-mixed-operators*/
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
function readKeyMultiValuePairs(str, /* bool */ valueString) {
|
|
/* reader */
|
|
var ret = [];
|
|
var partition = utils.partitionLineFixed(str, 3, true);
|
|
var count = utils.parseDecimalInt(partition[0]);
|
|
for (var i = 0; i < count; ++i) {
|
|
ret.push([
|
|
/* eslint-disable no-mixed-operators*/
|
|
utils.parseDecimalInt(partition[2 * i + 1]) - 1,
|
|
valueString ? partition[2 * i + 2].trim() : utils.parseDecimalInt(partition[2 * i + 2])
|
|
/* eslint-enable no-mixed-operators*/
|
|
]);
|
|
}
|
|
return ret;
|
|
}
|
|
|
|
function postLoadMul(sgroup, mol, atomMap) { // eslint-disable-line max-statements
|
|
sgroup.data.mul = sgroup.data.subscript - 0;
|
|
var atomReductionMap = {};
|
|
|
|
sgroup.atoms = Struct.SGroup.filterAtoms(sgroup.atoms, atomMap);
|
|
sgroup.patoms = Struct.SGroup.filterAtoms(sgroup.patoms, atomMap);
|
|
|
|
// mark repetitions for removal
|
|
for (var k = 1; k < sgroup.data.mul; ++k) {
|
|
for (var m = 0; m < sgroup.patoms.length; ++m) {
|
|
var raid = sgroup.atoms[k * sgroup.patoms.length + m]; // eslint-disable-line no-mixed-operators
|
|
if (raid < 0)
|
|
continue; // eslint-disable-line no-continue
|
|
if (sgroup.patoms[m] < 0)
|
|
throw new Error('parent atom missing');
|
|
atomReductionMap[raid] = sgroup.patoms[m]; // "merge" atom in parent
|
|
}
|
|
}
|
|
sgroup.patoms = Struct.SGroup.removeNegative(sgroup.patoms);
|
|
|
|
var patomsMap = identityMap(sgroup.patoms);
|
|
|
|
var bondsToRemove = [];
|
|
mol.bonds.each(function (bid, bond) {
|
|
var beginIn = bond.begin in atomReductionMap;
|
|
var endIn = bond.end in atomReductionMap;
|
|
// if both adjacent atoms of a bond are to be merged, remove it
|
|
/* eslint-disable no-mixed-operators*/
|
|
if (beginIn && endIn ||
|
|
beginIn && bond.end in patomsMap ||
|
|
endIn && bond.begin in patomsMap)
|
|
bondsToRemove.push(bid);
|
|
/* eslint-enable no-mixed-operators*/
|
|
// if just one atom is merged, modify the bond accordingly
|
|
else if (beginIn)
|
|
bond.begin = atomReductionMap[bond.begin];
|
|
else if (endIn)
|
|
bond.end = atomReductionMap[bond.end];
|
|
}, sgroup);
|
|
|
|
// apply removal lists
|
|
for (var b = 0; b < bondsToRemove.length; ++b)
|
|
mol.bonds.remove(bondsToRemove[b]);
|
|
for (var a in atomReductionMap) {
|
|
mol.atoms.remove(a);
|
|
atomMap[a] = -1;
|
|
}
|
|
sgroup.atoms = sgroup.patoms;
|
|
sgroup.patoms = null;
|
|
}
|
|
|
|
function postLoadSru(sgroup) {
|
|
sgroup.data.connectivity = (sgroup.data.connectivity || 'EU').trim().toLowerCase();
|
|
}
|
|
|
|
function postLoadSup(sgroup) {
|
|
sgroup.data.name = (sgroup.data.subscript || '').trim();
|
|
sgroup.data.subscript = '';
|
|
}
|
|
|
|
function postLoadGen(sgroup, mol, atomMap) { // eslint-disable-line no-unused-vars
|
|
}
|
|
|
|
function postLoadDat(sgroup, mol) {
|
|
if (!sgroup.data.absolute)
|
|
sgroup.pp = sgroup.pp.add(Struct.SGroup.getMassCentre(mol, sgroup.atoms));
|
|
}
|
|
|
|
function loadSGroup(mol, sg, atomMap) {
|
|
var postLoadMap = {
|
|
MUL: postLoadMul,
|
|
SRU: postLoadSru,
|
|
SUP: postLoadSup,
|
|
DAT: postLoadDat,
|
|
GEN: postLoadGen
|
|
};
|
|
|
|
// add the group to the molecule
|
|
sg.id = mol.sgroups.add(sg);
|
|
|
|
// apply type-specific post-processing
|
|
postLoadMap[sg.type](sg, mol, atomMap);
|
|
// mark atoms in the group as belonging to it
|
|
for (var s = 0; s < sg.atoms.length; ++s) {
|
|
if (mol.atoms.has(sg.atoms[s]))
|
|
Set.add(mol.atoms.get(sg.atoms[s]).sgs, sg.id);
|
|
}
|
|
|
|
if (sg.type == 'DAT')
|
|
mol.sGroupForest.insert(sg.id, -1, []);
|
|
else
|
|
mol.sGroupForest.insert(sg.id);
|
|
|
|
return sg.id;
|
|
}
|
|
|
|
function initSGroup(sGroups, propData) {
|
|
/* reader */
|
|
var kv = readKeyValuePairs(propData, true);
|
|
for (var key in kv) {
|
|
var type = kv[key];
|
|
if (!(type in Struct.SGroup.TYPES))
|
|
throw new Error('Unsupported S-group type');
|
|
var sg = new Struct.SGroup(type);
|
|
sg.number = key;
|
|
sGroups[key] = sg;
|
|
}
|
|
}
|
|
|
|
function applySGroupProp(sGroups, propName, propData, numeric, core) { // eslint-disable-line max-params
|
|
var kv = readKeyValuePairs(propData, !(numeric));
|
|
for (var key in kv)
|
|
// "core" properties are stored directly in an sgroup, not in sgroup.data
|
|
(core ? sGroups[key] : sGroups[key].data)[propName] = kv[key];
|
|
}
|
|
|
|
function applySGroupArrayProp(sGroups, propName, propData, shift) {
|
|
/* reader */
|
|
var sid = utils.parseDecimalInt(propData.slice(1, 4)) - 1;
|
|
var num = utils.parseDecimalInt(propData.slice(4, 8));
|
|
var part = toIntArray(utils.partitionLineFixed(propData.slice(8), 3, true));
|
|
|
|
if (part.length != num)
|
|
throw new Error('File format invalid');
|
|
if (shift) {
|
|
part = part.map(function (v) {
|
|
return v + shift;
|
|
});
|
|
}
|
|
sGroups[sid][propName] = sGroups[sid][propName].concat(part);
|
|
}
|
|
|
|
function applyDataSGroupName(sg, name) {
|
|
/* reader */
|
|
sg.data.fieldName = name;
|
|
}
|
|
|
|
function applyDataSGroupQuery(sg, query) {
|
|
/* reader */
|
|
sg.data.query = query;
|
|
}
|
|
|
|
function applyDataSGroupQueryOp(sg, queryOp) {
|
|
/* reader */
|
|
sg.data.queryOp = queryOp;
|
|
}
|
|
|
|
function applyDataSGroupDesc(sGroups, propData) {
|
|
/* reader */
|
|
var split = utils.partitionLine(propData, [4, 31, 2, 20, 2, 3], false);
|
|
var id = utils.parseDecimalInt(split[0]) - 1;
|
|
var fieldName = split[1].trim();
|
|
var fieldType = split[2].trim();
|
|
var units = split[3].trim();
|
|
var query = split[4].trim();
|
|
var queryOp = split[5].trim();
|
|
var sGroup = sGroups[id];
|
|
sGroup.data.fieldType = fieldType;
|
|
sGroup.data.fieldName = fieldName;
|
|
sGroup.data.units = units;
|
|
sGroup.data.query = query;
|
|
sGroup.data.queryOp = queryOp;
|
|
}
|
|
|
|
function applyDataSGroupInfo(sg, propData) { // eslint-disable-line max-statements
|
|
/* reader */
|
|
var split = utils.partitionLine(propData, [10/* x.x*/, 10/* y.y*/, 4/* eee*/, 1/* f*/, 1/* g*/, 1/* h*/, 3/* i */, 3/* jjj*/, 3/* kkk*/, 3/* ll*/, 2/* m*/, 3/* n*/, 2/* oo*/], false);
|
|
|
|
var x = parseFloat(split[0]);
|
|
var y = parseFloat(split[1]);
|
|
var attached = split[3].trim() == 'A';
|
|
var absolute = split[4].trim() == 'A';
|
|
var showUnits = split[5].trim() == 'U';
|
|
var nCharsToDisplay = split[7].trim();
|
|
nCharsToDisplay = nCharsToDisplay == 'ALL' ? -1 : utils.parseDecimalInt(nCharsToDisplay);
|
|
var tagChar = split[10].trim();
|
|
var daspPos = utils.parseDecimalInt(split[11].trim());
|
|
|
|
sg.pp = new Vec2(x, -y);
|
|
sg.data.attached = attached;
|
|
sg.data.absolute = absolute;
|
|
sg.data.showUnits = showUnits;
|
|
sg.data.nCharsToDisplay = nCharsToDisplay;
|
|
sg.data.tagChar = tagChar;
|
|
sg.data.daspPos = daspPos;
|
|
}
|
|
|
|
function applyDataSGroupInfoLine(sGroups, propData) {
|
|
/* reader */
|
|
var id = utils.parseDecimalInt(propData.substr(0, 4)) - 1;
|
|
var sg = sGroups[id];
|
|
applyDataSGroupInfo(sg, propData.substr(5));
|
|
}
|
|
|
|
function applyDataSGroupData(sg, data, finalize) {
|
|
/* reader */
|
|
sg.data.fieldValue = (sg.data.fieldValue || '') + data;
|
|
if (finalize) {
|
|
sg.data.fieldValue = trimRight(sg.data.fieldValue);
|
|
if (sg.data.fieldValue.startsWith('"') && sg.data.fieldValue.endsWith('"'))
|
|
sg.data.fieldValue = sg.data.fieldValue.substr(1, sg.data.fieldValue.length - 2);
|
|
}
|
|
}
|
|
|
|
function applyDataSGroupDataLine(sGroups, propData, finalize) {
|
|
/* reader */
|
|
var id = utils.parseDecimalInt(propData.substr(0, 5)) - 1;
|
|
var data = propData.substr(5);
|
|
var sg = sGroups[id];
|
|
applyDataSGroupData(sg, data, finalize);
|
|
}
|
|
|
|
// Utilities functions
|
|
function toIntArray(strArray) {
|
|
/* reader */
|
|
var ret = [];
|
|
for (var j = 0; j < strArray.length; ++j)
|
|
ret[j] = utils.parseDecimalInt(strArray[j]);
|
|
return ret;
|
|
}
|
|
|
|
function trimRight(str) {
|
|
return str.replace(/\s+$/, '');
|
|
}
|
|
|
|
function identityMap(array) {
|
|
var map = {};
|
|
for (var i = 0; i < array.length; ++i)
|
|
map[array[i]] = array[i];
|
|
return map;
|
|
}
|
|
|
|
module.exports = {
|
|
readKeyValuePairs: readKeyValuePairs,
|
|
readKeyMultiValuePairs: readKeyMultiValuePairs,
|
|
loadSGroup: loadSGroup,
|
|
initSGroup: initSGroup,
|
|
applySGroupProp: applySGroupProp,
|
|
applySGroupArrayProp: applySGroupArrayProp,
|
|
applyDataSGroupName: applyDataSGroupName,
|
|
applyDataSGroupQuery: applyDataSGroupQuery,
|
|
applyDataSGroupQueryOp: applyDataSGroupQueryOp,
|
|
applyDataSGroupDesc: applyDataSGroupDesc,
|
|
applyDataSGroupInfo: applyDataSGroupInfo,
|
|
applyDataSGroupData: applyDataSGroupData,
|
|
applyDataSGroupInfoLine: applyDataSGroupInfoLine,
|
|
applyDataSGroupDataLine: applyDataSGroupDataLine
|
|
};
|