in core/indigo-core/molecule/src/query_molecule.cpp [611:842]
void QueryMolecule::writeSmartsAtom(Output& output, Atom* atom, int aam, int chirality, int depth, bool has_or_parent, bool has_not_parent, int original_format)
{
int i;
bool brackets_used = false;
if (depth == 0) // "organic" subset can be used without [], but CNOPS need explicit aromatic to use letter
if (!isOrganicSubset(atom) || isAromaticByCaseAtom(atom))
{
bool atom_by_case = false;
bool aromaticity = false;
if (atom->type == OP_AND && atom->children.size() == 2)
{
atom_by_case = isAromaticByCaseAtom(atom->child(0)) || isAromaticByCaseAtom(atom->child(1));
aromaticity = (atom->child(0)->type == ATOM_AROMATICITY || atom->child(1)->type == ATOM_AROMATICITY);
}
if (!atom_by_case || !aromaticity)
{
output.writeChar('[');
brackets_used = true;
}
}
switch (atom->type)
{
case OP_NOT: {
if (isNotAtom(*atom, ELEM_H))
{
output.printf("*");
break;
}
output.writeChar('!');
writeSmartsAtom(output, atom->child(0), aam, chirality, depth + 1, has_or_parent, true, original_format);
break;
}
case OP_AND: {
bool has_number = false;
bool has_aromatic = false;
bool aromatic = false;
char atom_name[10];
long long cur_pos = output.tell();
for (i = 0; i < atom->children.size(); i++)
{
if (isAromaticByCaseAtom(atom->children[i]))
{
has_number = true;
strncpy(atom_name, Element::toString(atom->child(i)->value_max), sizeof(atom_name));
}
if (atom->children[i]->type == ATOM_AROMATICITY)
{
has_aromatic = true;
aromatic = atom->child(i)->value_min == ATOM_AROMATIC;
}
}
if (has_aromatic && has_number)
{ // Convert a & #6 -> c, A & #6 -> C
if (aromatic)
atom_name[0] = static_cast<char>(tolower(atom_name[0]));
output.printf("%s", atom_name);
}
for (i = 0; i < atom->children.size(); i++)
{
if (has_aromatic && has_number && (atom->children[i]->type == ATOM_AROMATICITY || atom->children[i]->type == ATOM_NUMBER))
{
continue;
}
if (atom->children[i]->type == ATOM_RADICAL || atom->children[i]->type == ATOM_VALENCE)
{
continue;
}
if (output.tell() > cur_pos)
{
output.writeChar(has_or_parent ? '&' : ';');
cur_pos = output.tell();
}
writeSmartsAtom(output, atom->child(i), aam, chirality, depth + 1, has_or_parent, has_not_parent, original_format);
}
break;
}
case OP_OR: {
for (i = 0; i < atom->children.size(); i++)
{
if (atom->children[i]->type == QueryMolecule::ATOM_RADICAL || atom->children[i]->type == QueryMolecule::ATOM_VALENCE)
{
continue;
}
if (i > 0)
output.printf(has_not_parent ? "!" : ",");
writeSmartsAtom(output, atom->child(i), aam, chirality, depth + 1, true, has_not_parent, original_format);
}
break;
}
case ATOM_ISOTOPE:
output.printf("%d", atom->value_max);
break;
case ATOM_NUMBER: {
if (isAromaticByCaseAtom(atom))
output.printf("#%d", atom->value_max);
else
output.printf("%s", Element::toString(atom->value_max));
switch (original_format)
{
case SMARTS:
case KET:
// SMARTS and ket save chirality in ATOM_CHIRALITY for query molecule
break;
default:
if (chirality == CHIRALITY_ANTICLOCKWISE)
output.printf("@");
else if (chirality == CHIRALITY_CLOCKWISE)
output.printf("@@");
break;
}
if (aam > 0)
output.printf(":%d", aam);
break;
}
case ATOM_CHARGE: {
int charge = atom->value_max;
if (charge > 1)
output.printf("+%d", charge);
else if (charge < -1)
output.printf("-%d", -charge);
else if (charge == 1)
output.printf("+");
else if (charge == -1)
output.printf("-");
else
output.printf("+0");
break;
}
case ATOM_FRAGMENT: {
if (atom->fragment->fragment_smarts.ptr() == 0)
throw Error("fragment_smarts has unexpectedly gone");
output.printf("$(%s)", atom->fragment->fragment_smarts.ptr());
break;
}
case ATOM_AROMATICITY: {
if (atom->value_min == ATOM_AROMATIC)
output.printf("a");
else
output.printf("A");
break;
}
case OP_NONE:
output.writeChar('*');
break;
case ATOM_TOTAL_H: {
_write_num(output, 'H', atom->value_min);
break;
}
case ATOM_SSSR_RINGS: {
_write_num_if_set(output, 'R', atom->value_min, atom->value_max);
break;
}
case ATOM_RING_BONDS_AS_DRAWN: {
output.printf("x0"); // exact value should be writed in extended part
break;
}
case ATOM_RING_BONDS: {
_write_num_if_set(output, 'x', atom->value_min, atom->value_max);
break;
}
case ATOM_IMPLICIT_H: {
_write_num_if_set(output, 'h', atom->value_min, atom->value_max);
break;
}
case ATOM_UNSATURATION: {
output.printf("$([*,#1]=,#,:[*,#1])");
break;
}
case ATOM_SMALLEST_RING_SIZE: {
_write_num_if_set(output, 'r', atom->value_min, atom->value_max);
break;
}
case ATOM_SUBSTITUENTS: {
output.printf("D%d", atom->value_min);
break;
}
case ATOM_SUBSTITUENTS_AS_DRAWN: {
output.printf("D%d", atom->value_min);
break;
}
case ATOM_PSEUDO: {
// output.writeString(atom->alias.ptr());
output.writeChar('*');
break;
}
case ATOM_TEMPLATE: {
output.writeString(atom->alias.ptr());
break;
}
case ATOM_CONNECTIVITY: {
output.printf("X%d", atom->value_min);
break;
}
case ATOM_TOTAL_BOND_ORDER: {
_write_num(output, 'v', atom->value_min);
break;
}
case ATOM_CHIRALITY: {
_getAtomChiralityDescription(atom, output);
break;
}
case ATOM_RSITE:
output.printf("*:%d", atom->value_min);
break;
default: {
throw Error("Unknown atom attribute %d", atom->type);
break;
}
}
if (brackets_used)
output.writeChar(']');
}