Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for reading and rendering DNA / RNA backbones #1831

Merged
merged 2 commits into from
Nov 30, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading