From 1096caba881d7973c58377cb0e3585bc6d446aae Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 30 Nov 2024 11:10:54 -0500 Subject: [PATCH 1/2] Use PDB to import sequences At the moment, Open Babel doesn't properly mark atoms / residues But when that's fixed, this will automatically grab atom names and residue / backbone information Signed-off-by: Geoff Hutchison --- avogadro/qtplugins/insertdna/insertdna.cpp | 217 ++++++++++----------- 1 file changed, 108 insertions(+), 109 deletions(-) diff --git a/avogadro/qtplugins/insertdna/insertdna.cpp b/avogadro/qtplugins/insertdna/insertdna.cpp index 91a95dfb13..2e539d5b09 100644 --- a/avogadro/qtplugins/insertdna/insertdna.cpp +++ b/avogadro/qtplugins/insertdna/insertdna.cpp @@ -26,19 +26,19 @@ using Avogadro::QtGui::FileFormatDialog; namespace Avogadro::QtPlugins { - class InsertDNADialog : public QDialog, public Ui::InsertDNADialog - { - public: - InsertDNADialog(QWidget *parent=nullptr) : QDialog(parent) { - setWindowFlags(Qt::Dialog | Qt::Tool); - setupUi(this); - } - }; - +class InsertDNADialog : public QDialog, public Ui::InsertDNADialog +{ +public: + InsertDNADialog(QWidget* parent = nullptr) : QDialog(parent) + { + setWindowFlags(Qt::Dialog | Qt::Tool); + setupUi(this); + } +}; InsertDna::InsertDna(QObject* p) - : Avogadro::QtGui::ExtensionPlugin(p), m_molecule(nullptr), - m_reader(nullptr), m_dialog(nullptr) + : Avogadro::QtGui::ExtensionPlugin(p), m_molecule(nullptr), m_reader(nullptr), + m_dialog(nullptr) { auto* action = new QAction(tr("DNA/RNA…"), this); action->setProperty("menu priority", 870); @@ -72,7 +72,7 @@ void InsertDna::showDialog() if (m_molecule == nullptr) return; - // check to see if FASTA format is available from Open Babel + // check to see if FASTA format is available from Open Babel QWidget* parentAsWidget = qobject_cast(parent()); const FileFormat::Operations ops = FileFormat::Read | FileFormat::String; const FileFormat* fmt = FileFormatDialog::findFileFormat( @@ -91,49 +91,48 @@ void InsertDna::showDialog() m_dialog->show(); } +void InsertDna::constructDialog() +{ + if (m_dialog == nullptr) { + m_dialog = new InsertDNADialog(qobject_cast(parent())); - void InsertDna::constructDialog() - { - if (m_dialog == nullptr) { - m_dialog = new InsertDNADialog(qobject_cast(parent())); - - auto* numStrands = new QButtonGroup(m_dialog); - numStrands->addButton(m_dialog->singleStrandRadio, 0); - numStrands->addButton(m_dialog->doubleStrandRadio, 1); - numStrands->setExclusive(true); + auto* numStrands = new QButtonGroup(m_dialog); + numStrands->addButton(m_dialog->singleStrandRadio, 0); + numStrands->addButton(m_dialog->doubleStrandRadio, 1); + numStrands->setExclusive(true); - connect(m_dialog->insertButton, SIGNAL(clicked()), - this, SLOT(performInsert())); + connect(m_dialog->insertButton, SIGNAL(clicked()), this, + SLOT(performInsert())); - connect(m_dialog->bpCombo, SIGNAL(currentIndexChanged(int)), - this, SLOT(updateBPTurns(int))); + connect(m_dialog->bpCombo, SIGNAL(currentIndexChanged(int)), this, + SLOT(updateBPTurns(int))); - connect(m_dialog->typeComboBox, SIGNAL(currentIndexChanged(int)), - this, SLOT(changeNucleicType(int))); + connect(m_dialog->typeComboBox, SIGNAL(currentIndexChanged(int)), this, + SLOT(changeNucleicType(int))); - // Set the nucleic buttons to update the sequence - foreach(const QToolButton *child, m_dialog->findChildren()) { - connect(child, SIGNAL(clicked()), this, SLOT(updateText())); - } - connect(m_dialog, SIGNAL(destroyed()), this, SLOT(dialogDestroyed())); + // Set the nucleic buttons to update the sequence + foreach (const QToolButton* child, m_dialog->findChildren()) { + connect(child, SIGNAL(clicked()), this, SLOT(updateText())); } - m_dialog->sequenceText->setPlainText(QString()); + connect(m_dialog, SIGNAL(destroyed()), this, SLOT(dialogDestroyed())); } + m_dialog->sequenceText->setPlainText(QString()); +} - void InsertDna::updateText() - { - auto *button = qobject_cast(sender()); - if (button) { - QString sequenceText = m_dialog->sequenceText->toPlainText(); - sequenceText += button->text(); +void InsertDna::updateText() +{ + auto* button = qobject_cast(sender()); + if (button) { + QString sequenceText = m_dialog->sequenceText->toPlainText(); + sequenceText += button->text(); - m_dialog->sequenceText->setPlainText(sequenceText); - } + m_dialog->sequenceText->setPlainText(sequenceText); } +} - void InsertDna::updateBPTurns(int type) - { - switch(type) { +void InsertDna::updateBPTurns(int type) +{ + switch (type) { case 0: // A-DNA m_dialog->bpTurnsSpin->setValue(11.0); break; @@ -146,74 +145,74 @@ void InsertDna::showDialog() default: // anything the user wants break; - } } +} - void InsertDna::changeNucleicType(int type) - { - if (type == 1) { // RNA - m_dialog->bpCombo->setCurrentIndex(3); // other - m_dialog->bpTurnsSpin->setValue(11.0); // standard RNA - m_dialog->singleStrandRadio->setChecked(true); - m_dialog->singleStrandRadio->setEnabled(false); - m_dialog->doubleStrandRadio->setEnabled(false); - m_dialog->toolButton_TU->setText(tr("U", "uracil")); - m_dialog->toolButton_TU->setToolTip(tr("Uracil")); - return; - } - // DNA - m_dialog->singleStrandRadio->setEnabled(true); - m_dialog->doubleStrandRadio->setEnabled(true); - m_dialog->toolButton_TU->setText(tr("T", "thymine")); - m_dialog->toolButton_TU->setToolTip(tr("Thymine")); +void InsertDna::changeNucleicType(int type) +{ + if (type == 1) { // RNA + m_dialog->bpCombo->setCurrentIndex(3); // other + m_dialog->bpTurnsSpin->setValue(11.0); // standard RNA + m_dialog->singleStrandRadio->setChecked(true); + m_dialog->singleStrandRadio->setEnabled(false); + m_dialog->doubleStrandRadio->setEnabled(false); + m_dialog->toolButton_TU->setText(tr("U", "uracil")); + m_dialog->toolButton_TU->setToolTip(tr("Uracil")); + return; } + // DNA + m_dialog->singleStrandRadio->setEnabled(true); + m_dialog->doubleStrandRadio->setEnabled(true); + m_dialog->toolButton_TU->setText(tr("T", "thymine")); + m_dialog->toolButton_TU->setToolTip(tr("Thymine")); +} - void InsertDna::performInsert() - { - if (m_dialog == nullptr || m_molecule == nullptr || m_reader == nullptr) - return; - - QString sequence = m_dialog->sequenceText->toPlainText().toLower(); - bool dna = (m_dialog->typeComboBox->currentIndex() == 0); - if (sequence.isEmpty()) - return; // also nothing to do - // Add DNA/RNA tag for FASTA - sequence = '>' + m_dialog->typeComboBox->currentText() + '\n' - + sequence; - - // options - // if DNA, check if the user wants single-strands - json options; - json arguments; - - // if it's DNA, allow single-stranded - if (dna && m_dialog->singleStrandRadio->isChecked()) - arguments.push_back("-a1"); - - // Add the number of turns - QString turns = QString("-at %1").arg(m_dialog->bpTurnsSpin->value()); - arguments.push_back(turns.toStdString()); - - options["arguments"] = arguments; - - QProgressDialog progDlg; - progDlg.setModal(true); - progDlg.setWindowTitle(tr("Insert Molecule…")); - progDlg.setLabelText(tr("Generating 3D molecule…")); - progDlg.setRange(0, 0); - progDlg.setValue(0); - progDlg.show(); - - QtGui::Molecule newMol; - m_reader->setOptions(options.dump()); - m_reader->readString(sequence.toStdString(), newMol); - m_molecule->undoMolecule()->appendMolecule(newMol, "Insert Molecule"); - emit requestActiveTool("Manipulator"); - } +void InsertDna::performInsert() +{ + if (m_dialog == nullptr || m_molecule == nullptr || m_reader == nullptr) + return; - void InsertDna::dialogDestroyed() - { - m_dialog = nullptr; - } + QString sequence = m_dialog->sequenceText->toPlainText().toLower(); + bool dna = (m_dialog->typeComboBox->currentIndex() == 0); + if (sequence.isEmpty()) + return; // also nothing to do + // Add DNA/RNA tag for FASTA + sequence = '>' + m_dialog->typeComboBox->currentText() + '\n' + sequence; + + // options + // if DNA, check if the user wants single-strands + json options; + json arguments; + + // if it's DNA, allow single-stranded + if (dna && m_dialog->singleStrandRadio->isChecked()) + arguments.push_back("-a1"); + + // Add the number of turns + QString turns = QString("-at %1").arg(m_dialog->bpTurnsSpin->value()); + arguments.push_back(turns.toStdString()); + + options["arguments"] = arguments; + options["format"] = "pdb"; + + QProgressDialog progDlg; + progDlg.setModal(true); + progDlg.setWindowTitle(tr("Insert Molecule…")); + progDlg.setLabelText(tr("Generating 3D molecule…")); + progDlg.setRange(0, 0); + progDlg.setValue(0); + progDlg.show(); + + QtGui::Molecule newMol; + m_reader->setOptions(options.dump()); + m_reader->readString(sequence.toStdString(), newMol); + m_molecule->undoMolecule()->appendMolecule(newMol, "Insert Molecule"); + emit requestActiveTool("Manipulator"); +} + +void InsertDna::dialogDestroyed() +{ + m_dialog = nullptr; +} -} // namespace Avogadro +} // namespace Avogadro::QtPlugins From 2ace4ecbc39cf01da3e48e2e055c6be3cf58bae1 Mon Sep 17 00:00:00 2001 From: Geoff Hutchison Date: Sat, 30 Nov 2024 11:11:38 -0500 Subject: [PATCH 2/2] Add support for reading DNA / RNA backbones Some render types need tweaking (e.g., cartoon) but it works Signed-off-by: Geoff Hutchison --- avogadro/qtplugins/cartoons/cartoons.cpp | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/avogadro/qtplugins/cartoons/cartoons.cpp b/avogadro/qtplugins/cartoons/cartoons.cpp index 7a49af8959..d912db5c89 100644 --- a/avogadro/qtplugins/cartoons/cartoons.cpp +++ b/avogadro/qtplugins/cartoons/cartoons.cpp @@ -202,7 +202,7 @@ map Cartoons::getBackboneByResidues( { const auto& graph = molecule.graph(); map result; - map previousCA; + map previousAtom; for (const auto& residue : molecule.residues()) { if (!residue.isHeterogen()) { Atom caAtom = residue.getAtomByName("CA"); @@ -212,8 +212,18 @@ map Cartoons::getBackboneByResidues( m_layerManager.atomEnabled(layer, oAtom.index())) { // get the group ID and check if it's initialized in the map size_t group = graph.getConnectedID(caAtom.index()); - addBackBone(result, previousCA, caAtom, residue.color(), group, + addBackBone(result, previousAtom, caAtom, residue.color(), group, residue.secondaryStructure()); + } else { // maybe DNA + Atom c3Atom = residue.getAtomByName("C3'"); + Atom o3Atom = residue.getAtomByName("O3'"); + if (c3Atom.isValid() && o3Atom.isValid() && + m_layerManager.atomEnabled(layer, c3Atom.index()) && + m_layerManager.atomEnabled(layer, o3Atom.index())) { + size_t group = graph.getConnectedID(c3Atom.index()); + addBackBone(result, previousAtom, c3Atom, residue.color(), group, + residue.secondaryStructure()); + } } } }