|
17 | 17 | ***************************************************************************/ |
18 | 18 |
|
19 | 19 | #include "indigo_abbreviations.h" |
| 20 | +#include "indigo_group_pseudoatoms_expand.h" |
20 | 21 |
|
21 | 22 | #include "base_c/bitarray.h" |
| 23 | +#include "base_cpp/array.h" |
22 | 24 | #include "base_cpp/scanner.h" |
23 | 25 | #include "molecule/elements.h" |
24 | 26 | #include "molecule/molecule.h" |
|
32 | 34 | #include "layout/molecule_layout.h" |
33 | 35 |
|
34 | 36 | #include <algorithm> |
| 37 | +#include <cstring> |
35 | 38 |
|
36 | 39 | namespace indigo |
37 | 40 | { |
@@ -850,4 +853,115 @@ namespace indigo |
850 | 853 | } |
851 | 854 |
|
852 | 855 | } // namespace abbreviations |
| 856 | + |
| 857 | + static bool isGroupPseudoatomLabel(const char* alias) |
| 858 | + { |
| 859 | + for (const char* const* p = GROUP_PSEUDOATOM_EXPAND_LABELS; *p != nullptr; ++p) |
| 860 | + { |
| 861 | + if (strcmp(alias, *p) == 0) |
| 862 | + return true; |
| 863 | + } |
| 864 | + return false; |
| 865 | + } |
| 866 | + |
| 867 | + static bool buildGroupFragment(const char* label, Molecule& fragment, int& attachment_idx) |
| 868 | + { |
| 869 | + fragment.clear(); |
| 870 | + attachment_idx = 0; |
| 871 | + |
| 872 | + if (strcmp(label, "OH") == 0) |
| 873 | + { |
| 874 | + int o = fragment.addAtom(ELEM_O); |
| 875 | + int h = fragment.addAtom(ELEM_H); |
| 876 | + fragment.addBond(o, h, BOND_SINGLE); |
| 877 | + fragment.setAtomXyz(o, 0, 0, 0); |
| 878 | + fragment.setAtomXyz(h, 1, 0, 0); |
| 879 | + attachment_idx = 0; |
| 880 | + return true; |
| 881 | + } |
| 882 | + if (strcmp(label, "NH2") == 0) |
| 883 | + { |
| 884 | + int n = fragment.addAtom(ELEM_N); |
| 885 | + int h1 = fragment.addAtom(ELEM_H); |
| 886 | + int h2 = fragment.addAtom(ELEM_H); |
| 887 | + fragment.addBond(n, h1, BOND_SINGLE); |
| 888 | + fragment.addBond(n, h2, BOND_SINGLE); |
| 889 | + fragment.setAtomXyz(n, 0, 0, 0); |
| 890 | + fragment.setAtomXyz(h1, 1, 0, 0); |
| 891 | + fragment.setAtomXyz(h2, -0.5f, 0.866f, 0); |
| 892 | + attachment_idx = 0; |
| 893 | + return true; |
| 894 | + } |
| 895 | + return false; |
| 896 | + } |
| 897 | + |
| 898 | + int expandGroupPseudoatomsInMolecule(Molecule& mol) |
| 899 | + { |
| 900 | + int count = 0; |
| 901 | + QS_DEF(Array<int>, pseudoatoms); |
| 902 | + pseudoatoms.clear(); |
| 903 | + for (int v = mol.vertexBegin(); v != mol.vertexEnd(); v = mol.vertexNext(v)) |
| 904 | + { |
| 905 | + if (mol.isPseudoAtom(v) && isGroupPseudoatomLabel(mol.getPseudoAtom(v))) |
| 906 | + pseudoatoms.push(v); |
| 907 | + } |
| 908 | + if (pseudoatoms.size() == 0) |
| 909 | + return 0; |
| 910 | + |
| 911 | + std::sort(pseudoatoms.ptr(), pseudoatoms.ptr() + pseudoatoms.size(), std::greater<int>()); |
| 912 | + |
| 913 | + for (int i = 0; i < pseudoatoms.size(); i++) |
| 914 | + { |
| 915 | + // Step 1 Build fragment |
| 916 | + int v = pseudoatoms[i]; |
| 917 | + const char* alias = mol.getPseudoAtom(v); |
| 918 | + Molecule fragment; |
| 919 | + int attachment_idx = -1; |
| 920 | + if (!buildGroupFragment(alias, fragment, attachment_idx)) |
| 921 | + continue; |
| 922 | + |
| 923 | + Vec3f pos = mol.getAtomXyz(v); |
| 924 | + const Vertex& vertex = mol.getVertex(v); |
| 925 | + |
| 926 | + // Step 2 merge fragment into the main structure. Now we have a |
| 927 | + // forest of atoms, disconnected. |
| 928 | + QS_DEF(Array<int>, mapping); |
| 929 | + mol.mergeWithMolecule(fragment, &mapping); |
| 930 | + int ap_new = mapping[attachment_idx]; |
| 931 | + |
| 932 | + // Step 3 connect fragment to the main structure. |
| 933 | + |
| 934 | + for (int k = vertex.neiBegin(); k != vertex.neiEnd(); k = vertex.neiNext(k)) |
| 935 | + { |
| 936 | + int nei = vertex.neiVertex(k); |
| 937 | + int edge_idx = mol.findEdgeIndex(v, nei); |
| 938 | + int order = mol.getBondOrder(edge_idx); |
| 939 | + mol.addBond_Silent(nei, ap_new, order); |
| 940 | + } |
| 941 | + |
| 942 | + for (int a = 0; a < fragment.vertexCount(); a++) |
| 943 | + { |
| 944 | + int mapped = mapping[a]; |
| 945 | + mol.setAtomXyz(mapped, pos.x, pos.y, pos.z); |
| 946 | + } |
| 947 | + |
| 948 | + mol.removeAtom(v); |
| 949 | + count++; |
| 950 | + } |
| 951 | + return count; |
| 952 | + } |
| 953 | + |
853 | 954 | } // namespace indigo |
| 955 | + |
| 956 | +CEXPORT int indigoExpandGroupPseudoatoms(int molecule) |
| 957 | +{ |
| 958 | + INDIGO_BEGIN |
| 959 | + { |
| 960 | + IndigoObject& obj = self.getObject(molecule); |
| 961 | + if (obj.type != IndigoObject::MOLECULE) |
| 962 | + throw IndigoError("indigoExpandGroupPseudoatoms(): expected molecule, got %s", obj.debugInfo()); |
| 963 | + Molecule& mol = obj.getMolecule(); |
| 964 | + return expandGroupPseudoatomsInMolecule(mol); |
| 965 | + } |
| 966 | + INDIGO_END(-1); |
| 967 | +} |
0 commit comments