void MoleculeCdxmlSaver::addNodeToFragment()

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());
    }
}