Skip to content

Commit

Permalink
Merge pull request #1831 from ghutchis/dna-backbone-support
Browse files Browse the repository at this point in the history
Add support for reading and rendering DNA / RNA backbones
  • Loading branch information
ghutchis authored Nov 30, 2024
2 parents 141c595 + 2ace4ec commit c491afc
Show file tree
Hide file tree
Showing 2 changed files with 120 additions and 111 deletions.
14 changes: 12 additions & 2 deletions avogadro/qtplugins/cartoons/cartoons.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,7 @@ map<size_t, AtomsPairList> Cartoons::getBackboneByResidues(
{
const auto& graph = molecule.graph();
map<size_t, AtomsPairList> result;
map<size_t, BackboneResidue> previousCA;
map<size_t, BackboneResidue> previousAtom;
for (const auto& residue : molecule.residues()) {
if (!residue.isHeterogen()) {
Atom caAtom = residue.getAtomByName("CA");
Expand All @@ -212,8 +212,18 @@ map<size_t, AtomsPairList> 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());
}
}
}
}
Expand Down
217 changes: 108 additions & 109 deletions avogadro/qtplugins/insertdna/insertdna.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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<QWidget*>(parent());
const FileFormat::Operations ops = FileFormat::Read | FileFormat::String;
const FileFormat* fmt = FileFormatDialog::findFileFormat(
Expand All @@ -91,49 +91,48 @@ void InsertDna::showDialog()
m_dialog->show();
}

void InsertDna::constructDialog()
{
if (m_dialog == nullptr) {
m_dialog = new InsertDNADialog(qobject_cast<QWidget*>(parent()));

void InsertDna::constructDialog()
{
if (m_dialog == nullptr) {
m_dialog = new InsertDNADialog(qobject_cast<QWidget*>(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<QToolButton*>()) {
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<QToolButton*>()) {
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<QToolButton*>(sender());
if (button) {
QString sequenceText = m_dialog->sequenceText->toPlainText();
sequenceText += button->text();
void InsertDna::updateText()
{
auto* button = qobject_cast<QToolButton*>(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;
Expand All @@ -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

0 comments on commit c491afc

Please sign in to comment.