void Molecule::addHydrogens(Atom *a, const QList<unsigned long> &atomIds, const QList<unsigned long> &bondIds) { if (atomIds.size() != bondIds.size()) { qDebug() << "Error, addHydrogens called with atom & bond id lists of different size!"; } // Construct an OBMol, call AddHydrogens and translate the changes OpenBabel::OBMol obmol = OBMol(); if (a) { OpenBabel::OBAtom *obatom = obmol.GetAtom(a->index()+1); // Set implicit valence for unusual elements not handled by OpenBabel // PR#2803076 switch (obatom->GetAtomicNum()) { case 3: case 11: case 19: case 37: case 55: case 85: case 87: obatom->SetImplicitValence(1); obatom->SetHyb(1); obmol.SetImplicitValencePerceived(); break; case 4: case 12: case 20: case 38: case 56: case 88: obatom->SetImplicitValence(2); obatom->SetHyb(2); obmol.SetImplicitValencePerceived(); break; case 84: // Po obatom->SetImplicitValence(2); obatom->SetHyb(3); obmol.SetImplicitValencePerceived(); break; default: // do nothing break; } obmol.AddHydrogens(obatom); } else obmol.AddHydrogens(); // All new atoms in the OBMol must be the additional hydrogens unsigned int numberAtoms = numAtoms(); int j = 0; for (unsigned int i = numberAtoms+1; i <= obmol.NumAtoms(); ++i, ++j) { if (obmol.GetAtom(i)->IsHydrogen()) { OpenBabel::OBAtom *obatom = obmol.GetAtom(i); Atom *atom; if (atomIds.isEmpty()) atom = addAtom(); else if (j < atomIds.size()) atom = addAtom(atomIds.at(j)); else { qDebug() << "Error - not enough unique ids in addHydrogens."; break; } atom->setOBAtom(obatom); // Get the neighbor atom OpenBabel::OBBondIterator iter; OpenBabel::OBAtom *next = obatom->BeginNbrAtom(iter); Bond *bond; if (bondIds.isEmpty()) bond = addBond(); else // Already confirmed by atom ids bond = addBond(bondIds.at(j)); bond->setEnd(Molecule::atom(atom->index())); bond->setBegin(Molecule::atom(next->GetIdx()-1)); } } for (unsigned int i = 1; i <= numberAtoms; ++i) { // Warning -- OB atom index off-by-one here atom(i-1)->setPartialCharge(obmol.GetAtom(i)->GetPartialCharge()); } }