mirror of
https://github.com/rdkit/rdkit.git
synced 2026-06-03 21:44:30 +08:00
We leave the names of the bit connected with Mol files as SGroups, since that is appropriate there, but the more generic pieces are renamed
666 lines
20 KiB
C++
666 lines
20 KiB
C++
//
|
|
// Copyright (C) 2002-2018 Greg Landrum and T5 Informatics GmbH
|
|
//
|
|
// @@ All Rights Reserved @@
|
|
// This file is part of the RDKit.
|
|
// The contents are covered by the terms of the BSD license
|
|
// which is included in the file license.txt, found at the root
|
|
// of the RDKit source tree.
|
|
//
|
|
|
|
#include <boost/algorithm/string/join.hpp>
|
|
|
|
#include "FileParsers.h"
|
|
#include "MolSGroupWriting.h"
|
|
|
|
namespace RDKit {
|
|
namespace SGroupWriting {
|
|
|
|
/* ------------------ V2000 Utils ------------------ */
|
|
|
|
std::string BuildV2000STYLines(const ROMol &mol) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
unsigned int count = 0;
|
|
|
|
const auto &sgroups = getSubstanceGroups(mol);
|
|
for (auto sg = sgroups.begin(); sg != sgroups.end(); ++sg) {
|
|
temp << FormatV2000IntField(1 + (sg - sgroups.begin()))
|
|
<< FormatV2000StringField(sg->getProp<std::string>("TYPE"), 3, true,
|
|
true);
|
|
if (++count == 8) {
|
|
ret << "M STY" << FormatV2000NumEntriesField(8) << temp.str()
|
|
<< std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M STY" << FormatV2000NumEntriesField(count) << temp.str()
|
|
<< std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000StringPropLines(const unsigned int entriesPerLine,
|
|
const ROMol &mol,
|
|
const std::string &propName,
|
|
const std::string &propCode,
|
|
const unsigned int fieldWitdh) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
unsigned int count = 0;
|
|
const auto &sgroups = getSubstanceGroups(mol);
|
|
for (auto sg = sgroups.begin(); sg != sgroups.end(); ++sg) {
|
|
std::string propValue;
|
|
// Write field only if defined
|
|
if (sg->getPropIfPresent(propName, propValue)) {
|
|
temp << FormatV2000IntField(1 + (sg - sgroups.begin()))
|
|
<< FormatV2000StringField(propValue, fieldWitdh, true, true);
|
|
if (++count == entriesPerLine) {
|
|
ret << "M " << propCode << FormatV2000NumEntriesField(entriesPerLine)
|
|
<< temp.str() << std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M " << propCode << FormatV2000NumEntriesField(count) << temp.str()
|
|
<< std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SLBLines(const ROMol &mol) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
unsigned int count = 0;
|
|
const auto &sgroups = getSubstanceGroups(mol);
|
|
for (auto sg = sgroups.begin(); sg != sgroups.end(); ++sg) {
|
|
unsigned int id;
|
|
// Write value if assigned, else 0
|
|
if (sg->getPropIfPresent("ID", id)) {
|
|
temp << FormatV2000IntField(1 + (sg - sgroups.begin()))
|
|
<< FormatV2000IntField(id);
|
|
if (++count == 8) {
|
|
ret << "M SLB" << FormatV2000NumEntriesField(8) << temp.str()
|
|
<< std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M SLB" << FormatV2000NumEntriesField(count) << temp.str()
|
|
<< std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SDSLines(const ROMol &mol) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
unsigned int count = 0;
|
|
const auto &sgroups = getSubstanceGroups(mol);
|
|
for (auto sg = sgroups.begin(); sg != sgroups.end(); ++sg) {
|
|
// Write field only if defined
|
|
std::string eState;
|
|
if (sg->getPropIfPresent("ESTATE", eState) && eState == "E") {
|
|
temp << FormatV2000IntField(1 + (sg - sgroups.begin()));
|
|
if (++count == 15) {
|
|
ret << "M SDS EXP" << FormatV2000NumEntriesField(15) << temp.str()
|
|
<< std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M SDS EXP" << FormatV2000NumEntriesField(count) << temp.str()
|
|
<< std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SPLLines(const ROMol &mol) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
unsigned int count = 0;
|
|
const auto &sgroups = getSubstanceGroups(mol);
|
|
for (auto sg = sgroups.begin(); sg != sgroups.end(); ++sg) {
|
|
// Write field only if a parent is defined
|
|
unsigned int parentIdx = -1;
|
|
if (sg->getPropIfPresent("PARENT", parentIdx)) {
|
|
temp << FormatV2000IntField(1 + (sg - sgroups.begin()))
|
|
<< FormatV2000IntField(1 + parentIdx);
|
|
if (++count == 8) {
|
|
ret << "M SPL" << FormatV2000NumEntriesField(8) << temp.str()
|
|
<< std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M SPL" << FormatV2000NumEntriesField(count) << temp.str()
|
|
<< std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SNCLines(const ROMol &mol) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
unsigned int count = 0;
|
|
const auto &sgroups = getSubstanceGroups(mol);
|
|
for (auto sg = sgroups.begin(); sg != sgroups.end(); ++sg) {
|
|
unsigned int compno;
|
|
// Write field only if compno is set
|
|
if (sg->getPropIfPresent("COMPNO", compno)) {
|
|
temp << FormatV2000IntField(1 + (sg - sgroups.begin()))
|
|
<< FormatV2000IntField(compno);
|
|
if (++count == 8) {
|
|
ret << "M SNC" << FormatV2000NumEntriesField(8) << temp.str()
|
|
<< std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M SNC" << FormatV2000NumEntriesField(count) << temp.str()
|
|
<< std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SBTLines(const ROMol &mol) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
unsigned int count = 0;
|
|
const auto &sgroups = getSubstanceGroups(mol);
|
|
for (auto sg = sgroups.begin(); sg != sgroups.end(); ++sg) {
|
|
std::string bracketType;
|
|
if (sg->getPropIfPresent("BRKTYP", bracketType)) {
|
|
unsigned int idx = 1 + (sg - sgroups.begin());
|
|
if (bracketType == "BRACKET") {
|
|
temp << FormatV2000IntField(idx) << FormatV2000IntField(0);
|
|
} else if (bracketType == "PAREN") {
|
|
temp << FormatV2000IntField(idx) << FormatV2000IntField(1);
|
|
} else {
|
|
std::ostringstream errout;
|
|
errout << "Invalid BRKTYP value '" << bracketType << "' for SGroup "
|
|
<< idx;
|
|
throw SubstanceGroupException(errout.str());
|
|
}
|
|
if (++count == 8) {
|
|
ret << "M SBT" << FormatV2000NumEntriesField(8) << temp.str()
|
|
<< std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M SBT" << FormatV2000NumEntriesField(count) << temp.str()
|
|
<< std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
template <class T>
|
|
std::string BuildV2000IdxVectorDataLines(const unsigned int entriesPerLine,
|
|
const unsigned int sGroupId,
|
|
const std::string &code,
|
|
const T &idxVector) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
unsigned int count = 0;
|
|
for (const auto &idx : idxVector) {
|
|
temp << FormatV2000IntField(1 + idx);
|
|
if (++count == entriesPerLine) {
|
|
ret << "M " << code << FormatV2000IntField(sGroupId)
|
|
<< FormatV2000NumEntriesField(entriesPerLine) << temp.str()
|
|
<< std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M " << code << FormatV2000IntField(sGroupId)
|
|
<< FormatV2000NumEntriesField(count) << temp.str() << std::endl;
|
|
}
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SMTLine(const int idx, const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
std::string smtValue;
|
|
if ((sgroup.getProp<std::string>("TYPE") == "MUL" &&
|
|
sgroup.getPropIfPresent("MULT", smtValue)) ||
|
|
sgroup.getPropIfPresent("LABEL", smtValue)) {
|
|
ret << "M SMT" << FormatV2000IntField(idx)
|
|
<< FormatV2000StringField(smtValue, 69, false, true) << std::endl;
|
|
}
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SDILine(const int idx, const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
const std::vector<SubstanceGroup::Bracket> brackets = sgroup.getBrackets();
|
|
|
|
for (const auto &bracket : brackets) {
|
|
ret << "M SDI" << FormatV2000IntField(idx)
|
|
<< FormatV2000NumEntriesField(4);
|
|
|
|
for (unsigned int iPoint = 0; iPoint < 2; ++iPoint) {
|
|
ret << FormatV2000DoubleField(bracket.at(iPoint).x);
|
|
ret << FormatV2000DoubleField(bracket.at(iPoint).y);
|
|
}
|
|
ret << std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SBVLine(const int idx, const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
for (const auto &cstate : sgroup.getCStates()) {
|
|
ret << "M SBV" << FormatV2000IntField(idx)
|
|
<< FormatV2000IntField(cstate.bondIdx + 1);
|
|
if (sgroup.getProp<std::string>("TYPE") == "SUP") {
|
|
ret << FormatV2000DoubleField(cstate.vector.x);
|
|
ret << FormatV2000DoubleField(cstate.vector.y);
|
|
}
|
|
ret << std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SDTLine(const int idx, const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
std::string sdtValue;
|
|
if (sgroup.getPropIfPresent("FIELDNAME", sdtValue)) {
|
|
ret << "M SDT" << FormatV2000IntField(idx);
|
|
ret << FormatV2000StringField(sdtValue, 30, true, true);
|
|
|
|
if (sgroup.getPropIfPresent("FIELDTYPE", sdtValue)) {
|
|
ret << FormatV2000StringField(sdtValue, 2, true, false);
|
|
} else {
|
|
ret << " T";
|
|
}
|
|
|
|
if (sgroup.getPropIfPresent("FIELDINFO", sdtValue)) {
|
|
ret << FormatV2000StringField(sdtValue, 20, true, false);
|
|
}
|
|
|
|
if (sgroup.getPropIfPresent("QUERYTYPE", sdtValue)) {
|
|
ret << FormatV2000StringField(sdtValue, 2, true, false);
|
|
}
|
|
if (sgroup.getPropIfPresent("QUERYOP", sdtValue)) {
|
|
ret << FormatV2000StringField(sdtValue, 15, true, false);
|
|
}
|
|
|
|
ret << std::endl;
|
|
}
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SDDLine(const int idx, const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
std::string sddValue;
|
|
if (sgroup.getPropIfPresent("FIELDDISP", sddValue)) {
|
|
ret << "M SDD" << FormatV2000IntField(idx);
|
|
ret << FormatV2000StringField(sddValue, 69, false, true);
|
|
ret << std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SCDSEDLines(const int idx, const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
STR_VECT dataFields;
|
|
if (sgroup.getPropIfPresent("DATAFIELDS", dataFields)) {
|
|
for (const auto &data : dataFields) {
|
|
unsigned int length = data.size();
|
|
if (length > 200) {
|
|
std::ostringstream errout;
|
|
errout << "Data field '" << data << "' in SGroup " << idx
|
|
<< " is longer than limit of 200 characters.";
|
|
throw SubstanceGroupException(errout.str());
|
|
}
|
|
unsigned int start = 0;
|
|
unsigned int end = 69;
|
|
for (; length > end; start += 69, end += 69) {
|
|
std::string dataChunk = data.substr(start, end);
|
|
ret << "M SCD" << FormatV2000IntField(idx)
|
|
<< FormatV2000StringField(dataChunk, 69, true, true) << std::endl;
|
|
}
|
|
std::string dataChunk = data.substr(start, end);
|
|
ret << "M SED" << FormatV2000IntField(idx)
|
|
<< FormatV2000StringField(dataChunk, 69, false, true) << std::endl;
|
|
}
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SAPLines(const int idx, const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
std::ostringstream temp;
|
|
|
|
const std::vector<SubstanceGroup::AttachPoint> saps =
|
|
sgroup.getAttachPoints();
|
|
|
|
unsigned int count = 0;
|
|
unsigned int entriesPerLine = 6;
|
|
for (const auto &sap : saps) {
|
|
temp << FormatV2000IntField(1 + sap.aIdx);
|
|
|
|
// lvIdx == -1 will turn into 0, which is right (see spec)
|
|
temp << FormatV2000IntField(1 + sap.lvIdx);
|
|
|
|
temp << FormatV2000StringField(sap.id, 2, false, true);
|
|
if (++count == entriesPerLine) {
|
|
ret << "M SAP" << FormatV2000IntField(idx)
|
|
<< FormatV2000IntField(entriesPerLine) << temp.str() << std::endl;
|
|
temp.str("");
|
|
count = 0;
|
|
}
|
|
}
|
|
if (count) {
|
|
ret << "M SAP" << FormatV2000IntField(idx)
|
|
<< FormatV2000NumEntriesField(count) << temp.str() << std::endl;
|
|
}
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV2000SCLLine(const int idx, const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
std::string sclValue;
|
|
if (sgroup.getPropIfPresent("CLASS", sclValue)) {
|
|
ret << "M SCL" << FormatV2000IntField(idx);
|
|
ret << FormatV2000StringField(sclValue, 69, false, true);
|
|
ret << std::endl;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
const std::string GetMolFileSGroupInfo(const RWMol &mol) {
|
|
std::ostringstream ret;
|
|
|
|
// multiple group per line properties
|
|
ret << BuildV2000STYLines(mol);
|
|
ret << BuildV2000SLBLines(mol);
|
|
ret << BuildV2000StringPropLines(8, mol, "SUBTYPE", "SST", 3);
|
|
ret << BuildV2000StringPropLines(8, mol, "CONNECT", "SCN", 3);
|
|
ret << BuildV2000SDSLines(mol);
|
|
ret << BuildV2000SPLLines(mol);
|
|
ret << BuildV2000SNCLines(mol);
|
|
ret << BuildV2000SBTLines(mol);
|
|
|
|
// single group per line properties
|
|
unsigned int idx = 0;
|
|
for (const auto &sgroup : getSubstanceGroups(mol)) {
|
|
++idx;
|
|
ret << BuildV2000IdxVectorDataLines(15, idx, "SAL", sgroup.getAtoms());
|
|
|
|
// SPA line must always come somewhere after the SAL line.
|
|
ret << BuildV2000IdxVectorDataLines(15, idx, "SPA",
|
|
sgroup.getParentAtoms());
|
|
|
|
ret << BuildV2000IdxVectorDataLines(15, idx, "SBL", sgroup.getBonds());
|
|
// Write CRS line -- CRS still not supported
|
|
ret << BuildV2000SDILine(idx, sgroup);
|
|
|
|
ret << BuildV2000SMTLine(idx, sgroup);
|
|
ret << BuildV2000SBVLine(idx, sgroup);
|
|
|
|
ret << BuildV2000SDTLine(idx, sgroup);
|
|
ret << BuildV2000SDDLine(idx, sgroup);
|
|
// SCD/SED must come after SDT
|
|
ret << BuildV2000SCDSEDLines(idx, sgroup);
|
|
|
|
ret << BuildV2000SAPLines(idx, sgroup);
|
|
ret << BuildV2000SCLLine(idx, sgroup);
|
|
}
|
|
return ret.str();
|
|
}
|
|
|
|
/* ------------------ V3000 Utils ------------------ */
|
|
|
|
template <class T>
|
|
std::string BuildV3000IdxVectorDataBlock(const std::string &key,
|
|
const std::vector<T> &dataVector) {
|
|
return BuildV3000IdxVectorDataBlock(key, dataVector.begin(),
|
|
dataVector.end());
|
|
}
|
|
|
|
template <class Iterator>
|
|
std::string BuildV3000IdxVectorDataBlock(const std::string &key,
|
|
const Iterator &dataVectorBegin,
|
|
const Iterator &dataVectorEnd) {
|
|
std::ostringstream ret;
|
|
size_t size = dataVectorEnd - dataVectorBegin;
|
|
if (size) {
|
|
ret << ' ' << key << "=(" << size;
|
|
for (auto itr = dataVectorBegin; itr < dataVectorEnd; ++itr) {
|
|
ret << ' ' << 1 + *itr;
|
|
}
|
|
ret << ')';
|
|
}
|
|
return ret.str();
|
|
}
|
|
|
|
std::string BuildV3000BondsBlock(const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
auto isXBond = [&sgroup](unsigned int bondIdx) {
|
|
return SubstanceGroup::BondType::XBOND == sgroup.getBondType(bondIdx);
|
|
};
|
|
|
|
auto bonds = sgroup.getBonds();
|
|
auto first_cbond = std::stable_partition(bonds.begin(), bonds.end(), isXBond);
|
|
|
|
ret << BuildV3000IdxVectorDataBlock("XBONDS", bonds.begin(), first_cbond);
|
|
ret << BuildV3000IdxVectorDataBlock("CBONDS", first_cbond, bonds.end());
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string FormatV3000StringPropertyBlock(const std::string &prop,
|
|
const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
std::string propValue;
|
|
if (sgroup.getPropIfPresent(prop, propValue)) {
|
|
ret << ' ' << prop << '=';
|
|
bool hasSpaces =
|
|
(propValue.end() != find(propValue.begin(), propValue.end(), ' '));
|
|
|
|
if (hasSpaces || propValue.empty()) {
|
|
ret << "\"";
|
|
}
|
|
|
|
ret << propValue;
|
|
|
|
if (hasSpaces || propValue.empty()) {
|
|
ret << "\"";
|
|
}
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string FormatV3000ParentBlock(const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
unsigned int parentIdx = -1;
|
|
if (sgroup.getPropIfPresent("PARENT", parentIdx)) {
|
|
ret << " PARENT=" << (1 + parentIdx);
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string FormatV3000CompNoBlock(const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
unsigned int compno;
|
|
|
|
if (sgroup.getPropIfPresent("COMPNO", compno)) {
|
|
ret << " COMPNO=" << compno;
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string FormatV3000BracketBlock(
|
|
const std::vector<SubstanceGroup::Bracket> brackets) {
|
|
std::ostringstream ret;
|
|
|
|
for (const auto &bracket : brackets) {
|
|
ret << " BRKXYZ=(9";
|
|
for (unsigned int iPoint = 0; iPoint < 2; ++iPoint) {
|
|
ret << ' ' << FormatV3000DoubleField(bracket.at(iPoint).x);
|
|
ret << ' ' << FormatV3000DoubleField(bracket.at(iPoint).y);
|
|
ret << " 0"; // z coordinate is 0 by format specification
|
|
}
|
|
ret << " 0 0 0"; // 3rd point is 0 by format specification
|
|
ret << ")";
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string FormatV3000FieldDataBlock(const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
STR_VECT dataFields;
|
|
if (sgroup.getPropIfPresent("DATAFIELDS", dataFields)) {
|
|
for (const auto &data : dataFields) {
|
|
ret << " FIELDDATA=\"" << data << "\"";
|
|
}
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string FormatV3000CStateBlock(const SubstanceGroup &sgroup) {
|
|
std::ostringstream ret;
|
|
|
|
for (const auto &cstate : sgroup.getCStates()) {
|
|
unsigned int xbondIdx = 1 + cstate.bondIdx;
|
|
ret << " CSTATE=(";
|
|
if (sgroup.getProp<std::string>("TYPE") == "SUP") {
|
|
ret << "4 " << xbondIdx;
|
|
ret << ' ' << FormatV3000DoubleField(cstate.vector.x);
|
|
ret << ' ' << FormatV3000DoubleField(cstate.vector.y);
|
|
ret << " 0";
|
|
} else {
|
|
ret << "1 " << xbondIdx;
|
|
}
|
|
ret << ")";
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
std::string FormatV3000AttachPointBlock(
|
|
const std::vector<SubstanceGroup::AttachPoint> &saps) {
|
|
std::ostringstream ret;
|
|
|
|
for (const auto &sap : saps) {
|
|
ret << " SAP=(3 " << (1 + sap.aIdx);
|
|
|
|
if (sap.lvIdx != -1 && sap.aIdx == static_cast<unsigned int>(sap.lvIdx)) {
|
|
ret << " aidx";
|
|
} else {
|
|
// lvIdx == -1 will turn into 0, which is right (see spec)
|
|
ret << ' ' << (1 + sap.lvIdx);
|
|
}
|
|
|
|
ret << ' ' << sap.id << ")";
|
|
}
|
|
|
|
return ret.str();
|
|
}
|
|
|
|
//! Write a SGroup line. The order of the labels is defined in the spec.
|
|
const std::string GetV3000MolFileSGroupLines(const unsigned int idx,
|
|
const SubstanceGroup &sgroup) {
|
|
std::ostringstream os;
|
|
|
|
unsigned int id = 0;
|
|
sgroup.getPropIfPresent("ID", id);
|
|
|
|
os << idx << ' ' << sgroup.getProp<std::string>("TYPE") << ' ' << id;
|
|
|
|
os << BuildV3000IdxVectorDataBlock("ATOMS", sgroup.getAtoms());
|
|
os << BuildV3000BondsBlock(sgroup);
|
|
os << BuildV3000IdxVectorDataBlock("PATOMS", sgroup.getParentAtoms());
|
|
os << FormatV3000StringPropertyBlock("SUBTYPE", sgroup);
|
|
os << FormatV3000StringPropertyBlock("MULT", sgroup);
|
|
os << FormatV3000StringPropertyBlock("CONNECT", sgroup);
|
|
os << FormatV3000ParentBlock(sgroup);
|
|
os << FormatV3000CompNoBlock(sgroup);
|
|
// XBHEAD -> part of V2000 CRS, not supported yet
|
|
// XBCORR -> part of V2000 CRS, not supported yet
|
|
os << FormatV3000StringPropertyBlock("LABEL", sgroup);
|
|
os << FormatV3000BracketBlock(sgroup.getBrackets());
|
|
os << FormatV3000StringPropertyBlock("ESTATE", sgroup);
|
|
os << FormatV3000CStateBlock(sgroup);
|
|
os << FormatV3000StringPropertyBlock("FIELDNAME", sgroup);
|
|
os << FormatV3000StringPropertyBlock("FIELDINFO", sgroup);
|
|
os << FormatV3000StringPropertyBlock("FIELDDISP", sgroup);
|
|
os << FormatV3000StringPropertyBlock("QUERYTYPE", sgroup);
|
|
os << FormatV3000StringPropertyBlock("QUERYOP", sgroup);
|
|
os << FormatV3000FieldDataBlock(sgroup);
|
|
os << FormatV3000StringPropertyBlock("CLASS", sgroup);
|
|
os << FormatV3000AttachPointBlock(sgroup.getAttachPoints());
|
|
os << FormatV3000StringPropertyBlock("BRKTYP", sgroup);
|
|
os << FormatV3000StringPropertyBlock("SEQID", sgroup);
|
|
|
|
std::string sGroupBlock = os.str();
|
|
unsigned int length = sGroupBlock.size();
|
|
os.str("");
|
|
|
|
unsigned int start = 0;
|
|
while (length - start > 73) {
|
|
os << "M V30 " << sGroupBlock.substr(start, 72) << '-' << std::endl;
|
|
start += 72;
|
|
}
|
|
os << "M V30 " << sGroupBlock.substr(start, 73) << std::endl;
|
|
|
|
return os.str();
|
|
}
|
|
|
|
} // namespace SGroupWriting
|
|
} // namespace RDKit
|