UNPKG

3dmol

Version:

JavaScript/TypeScript molecular visualization library

183 lines (162 loc) 5.99 kB
import { ParserOptionsSpec } from "./ParserOptionsSpec"; var parseV2000 = function (lines: any, options: ParserOptionsSpec) { var atoms: any & Record<string, any> = [[]]; var noH = false; if (typeof options.keepH !== "undefined") noH = !options.keepH; while (lines.length > 0) { if (lines.length < 4) break; var atomCount = parseInt(lines[3].substring(0, 3)); if (isNaN(atomCount) || atomCount <= 0) break; var bondCount = parseInt(lines[3].substring(3, 6)); var offset = 4; if (lines.length < 4 + atomCount + bondCount) break; // Serial is atom's index in file; index is atoms index in 'atoms' var serialToIndex: number[] = []; var start = atoms[atoms.length - 1].length; var end = start + atomCount; var i: number, line: string; for (i = start; i < end; i++, offset++) { line = lines[offset]; var atom: Record<string, any> = {}; var elem = line.substring(31, 34).replace(/ /g, ""); atom.atom = atom.elem = elem[0].toUpperCase() + elem.substring(1).toLowerCase(); if (atom.elem !== "H" || !noH) { atom.serial = i; serialToIndex[i] = atoms[atoms.length - 1].length; atom.x = parseFloat(line.substring(0, 10)); atom.y = parseFloat(line.substring(10, 20)); atom.z = parseFloat(line.substring(20, 30)); atom.hetflag = true; atom.bonds = []; atom.bondOrder = []; atom.properties = {}; atom.index = atoms[atoms.length - 1].length; atoms[atoms.length - 1].push(atom); } } for (i = 0; i < bondCount; i++, offset++) { line = lines[offset]; var from = serialToIndex[parseInt(line.substring(0, 3)) - 1 + start]; var to = serialToIndex[parseInt(line.substring(3, 6)) - 1 + start]; var order = parseFloat(line.substring(6)); if (typeof from != "undefined" && typeof to != "undefined") { atoms[atoms.length - 1][from].bonds.push(to); atoms[atoms.length - 1][from].bondOrder.push(order); atoms[atoms.length - 1][to].bonds.push(from); atoms[atoms.length - 1][to].bondOrder.push(order); } } if (options.multimodel) { if (!options.onemol) atoms.push([]); while (lines[offset] !== "$$$$" && offset < lines.length) offset++; lines.splice(0, ++offset); } else { break; } } return atoms; }; /** * @param {!Array.<string>} lines * @param {ParserOptionsSpec} options * @returns {!Array.<!Array<!Object>>} */ var parseV3000 = function (lines: any, options: ParserOptionsSpec) { var atoms: any[][] & Record<string, any> = [[]]; var noH = false; if (typeof options.keepH !== "undefined") noH = !options.keepH; while (lines.length > 0) { if (lines.length < 8) break; if (!lines[4].startsWith("M V30 BEGIN CTAB")) break; if (!lines[5].startsWith("M V30 COUNTS") || lines[5].length < 14) break; var counts = lines[5].substring(13).match(/\S+/g); if (counts.length < 2) break; var atomCount = parseInt(counts[0]); if (isNaN(atomCount) || atomCount <= 0) break; var bondCount = parseInt(counts[1]); var offset = 7; if (lines.length < 8 + atomCount + bondCount) //header, bgn+end CTAB, counts, END break; // serial is atom's index in file; index is atoms index in 'atoms' var serialToIndex: number[] = []; var start = atoms[atoms.length - 1].length; var end = start + atomCount; var i: number, line: string; for (i = start; i < end; i++, offset++) { line = lines[offset]; var atomParts = line.substring(6).match(/\S+/g); if (atomParts!.length > 4) { var atom: Record<string, any> = {}; var elem = atomParts![1].replace(/ /g, ""); atom.atom = atom.elem = elem[0].toUpperCase() + elem.substring(1).toLowerCase(); if (atom.elem !== "H" || !noH) { atom.serial = i; serialToIndex[i] = atoms[atoms.length - 1].length; atom.x = parseFloat(atomParts![2]); atom.y = parseFloat(atomParts![3]); atom.z = parseFloat(atomParts![4]); atom.hetflag = true; atom.bonds = []; atom.bondOrder = []; atom.properties = {}; atom.index = atoms[atoms.length - 1].length; atoms[atoms.length - 1].push(atom); } } } if (lines[offset] === "M V30 END ATOM") offset++; else break; if (bondCount !== 0 && lines[offset] === "M V30 BEGIN BOND") offset++; else break; for (i = 0; i < bondCount; i++, offset++) { line = lines[offset]; var bondParts = line.substring(6).match(/\S+/g); if (bondParts!.length > 3) { var from = serialToIndex[parseInt(bondParts![2]) - 1 + start]; var to = serialToIndex[parseInt(bondParts![3]) - 1 + start]; var order = parseFloat(bondParts![1]); if (typeof from != "undefined" && typeof to != "undefined") { atoms[atoms.length - 1][from].bonds.push(to); atoms[atoms.length - 1][from].bondOrder.push(order); atoms[atoms.length - 1][to].bonds.push(from); atoms[atoms.length - 1][to].bondOrder.push(order); } } } if (options.multimodel) { if (!options.onemol) { atoms.push([]); } while (lines[offset] !== "$$$$" && offset < lines.length) { offset++; } lines.splice(0, ++offset); } else { break; } } return atoms; }; /** * @param {string} * str * @param {ParserOptionsSpec} * options * @category Parsers */ export function SDF(str: string, options: ParserOptionsSpec) { var molformat = "V2000"; var lines = str.split(/\r?\n|\r/); if (lines.length > 3 && lines[3].length > 38) { molformat = lines[3].substring(34, 39); } if (molformat === "V2000") { return parseV2000(lines, options); } else if (molformat === "V3000") { return parseV3000(lines, options); } return [['']]; }