in core/indigo-core/molecule/src/molecule_cdxml_saver.cpp [585:863]
void MoleculeCdxmlSaver::addNodeToFragment(BaseMolecule& mol, XMLElement* fragment, int atom_idx, const Vec2f& offset, Vec2f& min_coord, Vec2f& max_coord,
Vec2f& node_pos)
{
Vec3f pos3 = mol.getAtomXyz(atom_idx);
Vec2f pos(pos3.x, pos3.y);
bool have_z = BaseMolecule::hasZCoord(mol);
if (have_z)
{
pos3.x += offset.x;
pos3.y += offset.y;
pos3.scale(_scale);
}
pos.add(offset);
if (atom_idx == mol.vertexBegin())
min_coord = max_coord = pos;
else
{
min_coord.min(pos);
max_coord.max(pos);
}
pos.scale(_scale);
node_pos.set(pos.x, -pos.y);
int atom_number = mol.getAtomNumber(atom_idx);
int charge = mol.getAtomCharge(atom_idx);
int radical = 0;
int hcount = -1;
XMLElement* node = _doc->NewElement("n");
fragment->LinkEndChild(node);
node->SetAttribute("id", _atoms_ids[atom_idx]);
if (mol.isRSite(atom_idx))
{
node->SetAttribute("NodeType", "GenericNickname");
node->SetAttribute("GenericNickname", "A");
if ((charge != 0) && (charge != CHARGE_UNKNOWN))
node->SetAttribute("Charge", charge);
}
else if (mol.isPseudoAtom(atom_idx))
{
node->SetAttribute("NodeType", "GenericNickname");
node->SetAttribute("GenericNickname", mol.getPseudoAtom(atom_idx));
if ((charge != 0) && (charge != CHARGE_UNKNOWN))
node->SetAttribute("Charge", charge);
}
else if (atom_number > 0)
{
if (atom_number != ELEM_C)
node->SetAttribute("Element", atom_number);
if ((charge != 0) && (charge != CHARGE_UNKNOWN))
node->SetAttribute("Charge", charge);
if (mol.getAtomIsotope(atom_idx) > 0)
node->SetAttribute("Isotope", mol.getAtomIsotope(atom_idx));
radical = mol.getAtomRadical_NoThrow(atom_idx, 0);
if (radical > 0)
{
const char* radical_str = NULL;
if (radical == RADICAL_DOUBLET)
radical_str = "Doublet";
else if (radical == RADICAL_SINGLET)
radical_str = "Singlet";
else if (radical == RADICAL_TRIPLET)
radical_str = "Triplet";
else
throw Error("Radical type %d is not supported", radical);
node->SetAttribute("Radical", radical_str);
}
if ((atom_number != ELEM_C) && (atom_number != ELEM_H))
{
try
{
hcount = getHydrogenCount(mol, atom_idx, charge, radical);
}
catch (Exception&)
{
hcount = -1;
}
if (hcount >= 0)
node->SetAttribute("NumHydrogens", hcount);
}
if (_getAttachmentPoint(mol, atom_idx))
{
node->SetAttribute("NodeType", "ExternalConnectionPoint");
}
}
else if (atom_number < 0)
{
QS_DEF(Array<int>, list);
int query_atom_type;
if (mol.isQueryMolecule() && (query_atom_type = QueryMolecule::parseQueryAtom(mol.asQueryMolecule(), atom_idx, list)) != -1)
{
if (query_atom_type == QueryMolecule::QUERY_ATOM_A)
{
node->SetAttribute("NodeType", "GenericNickname");
node->SetAttribute("GenericNickname", "A");
}
else if (query_atom_type == QueryMolecule::QUERY_ATOM_Q)
{
node->SetAttribute("NodeType", "GenericNickname");
node->SetAttribute("GenericNickname", "Q");
}
else if (query_atom_type == QueryMolecule::QUERY_ATOM_X)
{
node->SetAttribute("NodeType", "GenericNickname");
node->SetAttribute("GenericNickname", "X");
}
else if (query_atom_type == QueryMolecule::QUERY_ATOM_LIST || query_atom_type == QueryMolecule::QUERY_ATOM_NOTLIST)
{
int k;
QS_DEF(Array<char>, buf);
ArrayOutput out(buf);
if (query_atom_type == QueryMolecule::QUERY_ATOM_NOTLIST)
out.writeString("NOT ");
for (k = 0; k < list.size(); k++)
{
out.printf("%d ", list[k]);
}
buf.pop();
buf.push(0);
node->SetAttribute("NodeType", "ElementList");
node->SetAttribute("ElementList", buf.ptr());
}
}
}
if (mol.have_xyz)
{
QS_DEF(Array<char>, buf);
ArrayOutput out(buf);
out.printf("%f %f", pos.x, -pos.y);
buf.push(0);
node->SetAttribute("p", buf.ptr());
if (have_z)
{
QS_DEF(Array<char>, buf);
ArrayOutput out(buf);
out.printf("%f %f %f", pos3.x, -pos3.y, -pos3.z);
buf.push(0);
node->SetAttribute("xyz", buf.ptr());
}
}
int enh_stereo_type = mol.stereocenters.getType(atom_idx);
if (enh_stereo_type > MoleculeStereocenters::ATOM_ANY)
{
int enh_stereo_grp = mol.stereocenters.getGroup(atom_idx);
node->SetAttribute("Geometry", "Tetrahedral");
const int* pyramid = mol.stereocenters.getPyramid(atom_idx);
// 0 means atom absence
QS_DEF(Array<char>, buf);
ArrayOutput out(buf);
for (int i = 0; i < 4; ++i)
{
if (i)
out.printf(" ");
out.printf("%d", _atoms_ids[pyramid[i] < 0 ? 0 : pyramid[i]]);
}
buf.push(0);
node->SetAttribute("BondOrdering", buf.ptr());
switch (enh_stereo_type)
{
case MoleculeStereocenters::ATOM_ABS:
node->SetAttribute("EnhancedStereoType", "Absolute");
break;
case MoleculeStereocenters::ATOM_OR:
node->SetAttribute("EnhancedStereoType", "Or");
node->SetAttribute("EnhancedStereoGroupNum", enh_stereo_grp);
break;
case MoleculeStereocenters::ATOM_AND:
node->SetAttribute("EnhancedStereoType", "And");
node->SetAttribute("EnhancedStereoGroupNum", enh_stereo_grp);
break;
default:
throw Error("Unknows enhanced stereo type %d", enh_stereo_type);
break;
}
}
if (mol.getVertex(atom_idx).degree() == 0 && atom_number == ELEM_C && charge == 0 && radical == 0)
{
XMLElement* t = create_text(node, pos.x, -pos.y, nullptr);
t->SetAttribute("Justification", "Center");
add_style_str(t, 3, 10, 96, "CH4");
add_charge(t, 3, 10, charge);
}
else if (mol.isRSite(atom_idx))
{
XMLElement* t = create_text(node, pos.x, -pos.y, "Left");
QS_DEF(Array<char>, buf);
mol.getAtomSymbol(atom_idx, buf);
buf.push(0);
add_style_str(t, 3, 10, 96, buf.ptr());
add_charge(t, 3, 10, charge);
}
else if (mol.isPseudoAtom(atom_idx))
{
XMLElement* t = create_text(node, pos.x, -pos.y, "Left");
add_style_str(t, 3, 10, 96, mol.getPseudoAtom(atom_idx));
add_charge(t, 3, 10, charge);
}
else if (atom_number > 0 && atom_number != ELEM_C)
{
XMLElement* t = create_text(node, pos.x, -pos.y, "Left");
QS_DEF(Array<char>, buf);
ArrayOutput out(buf);
mol.getAtomSymbol(atom_idx, buf);
if (hcount > 0)
{
buf.pop();
buf.push('H');
}
buf.push(0);
add_style_str(t, 3, 10, 96, buf.ptr());
if (hcount > 1)
{
out.clear();
out.printf("%d", hcount);
buf.push(0);
add_style_str(t, 3, 10, 32, buf.ptr());
}
add_charge(t, 3, 10, charge);
}
else if (atom_number < 0 && mol.isQueryMolecule())
{
XMLElement* t = create_text(node, pos.x, -pos.y, "Left");
QS_DEF(Array<char>, buf);
ArrayOutput out(buf);
QS_DEF(Array<int>, list);
int query_atom_type;
if (mol.isQueryMolecule() && (query_atom_type = QueryMolecule::parseQueryAtom(mol.asQueryMolecule(), atom_idx, list)) != -1)
{
if (query_atom_type == QueryMolecule::QUERY_ATOM_LIST || query_atom_type == QueryMolecule::QUERY_ATOM_NOTLIST)
{
int k;
if (query_atom_type == QueryMolecule::QUERY_ATOM_NOTLIST)
out.writeString("NOT ");
for (k = 0; k < list.size(); k++)
{
if (k > 0)
out.writeChar(',');
out.writeString(Element::toString(list[k]));
}
buf.push(0);
}
else
mol.getAtomSymbol(atom_idx, buf);
}
add_style_str(t, 3, 10, 96, buf.ptr());
}
}