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

Fix crashing with dipole moment #1847

Merged
merged 5 commits into from
Dec 7, 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
4 changes: 4 additions & 0 deletions avogadro/calc/chargemanager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ Vector3 ChargeManager::dipoleMoment(const std::string& identifier,
return Vector3(0.0, 0.0, 0.0);
}

if (molecule.atomCount() < 2) {
return Vector3(0.0, 0.0, 0.0);
}

const auto id = m_identifiers[lowerId];
const ChargeModel* model = m_models[id];
return model->dipoleMoment(molecule);
Expand Down
3 changes: 3 additions & 0 deletions avogadro/calc/chargemodel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ constexpr double M_PI = 3.14159265358979323846;

Vector3 ChargeModel::dipoleMoment(const Molecule& mol) const
{
if (mol.atomCount() < 2)
return Vector3(0.0, 0.0, 0.0);

// default is to get the set of partial atomic charges
// (some models might do something more sophisticated)
const MatrixX charges = partialCharges(mol);
Expand Down
47 changes: 31 additions & 16 deletions avogadro/qtopengl/glwidget.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ GLWidget::GLWidget(QWidget* p)
m_renderTimer(nullptr)
{
setFocusPolicy(Qt::ClickFocus);
connect(&m_scenePlugins,
SIGNAL(pluginStateChanged(Avogadro::QtGui::ScenePlugin*)),
SLOT(updateScene()));
connect(&m_scenePlugins, SIGNAL(pluginConfigChanged()), SLOT(updateScene()));
connect(&m_scenePlugins, &QtGui::ScenePluginModel::pluginStateChanged, this,
&GLWidget::updateScene);
connect(&m_scenePlugins, &QtGui::ScenePluginModel::pluginConfigChanged, this,
&GLWidget::updateScene);
m_renderer.setTextRenderStrategy(new QtTextRenderStrategy);
}

Expand All @@ -47,7 +47,13 @@ void GLWidget::setMolecule(QtGui::Molecule* mol)
m_molecule = mol;
foreach (QtGui::ToolPlugin* tool, m_tools)
tool->setMolecule(m_molecule);
connect(m_molecule, SIGNAL(changed(unsigned int)), SLOT(updateScene()));

if (m_molecule != nullptr) {
// update properties like dipole rendering
QTimer::singleShot(500, m_molecule, &QtGui::Molecule::update);
}

connect(m_molecule, &QtGui::Molecule::changed, this, &GLWidget::updateScene);
}

QtGui::Molecule* GLWidget::molecule()
Expand All @@ -60,6 +66,14 @@ const QtGui::Molecule* GLWidget::molecule() const
return m_molecule;
}

void GLWidget::updateMolecule()
{
if (m_molecule != nullptr) {
// update properties like dipole rendering
QTimer::singleShot(500, m_molecule, &QtGui::Molecule::update);
}
}

void GLWidget::updateScene()
{
// Build up the scene with the scene plugins, creating the appropriate nodes.
Expand Down Expand Up @@ -124,7 +138,8 @@ void GLWidget::addTool(QtGui::ToolPlugin* tool)
if (m_tools.contains(tool))
return;

connect(tool, SIGNAL(updateRequested()), SLOT(requestUpdate()));
connect(tool, &QtGui::ToolPlugin::updateRequested, this,
&GLWidget::requestUpdate);
tool->setParent(this);
tool->setGLWidget(this);
tool->setActiveWidget(this);
Expand All @@ -151,17 +166,17 @@ void GLWidget::setActiveTool(QtGui::ToolPlugin* tool)
return;

if (m_activeTool && m_activeTool != m_defaultTool) {
disconnect(m_activeTool, SIGNAL(drawablesChanged()), this,
SLOT(updateScene()));
disconnect(m_activeTool, &QtGui::ToolPlugin::drawablesChanged, this,
&GLWidget::updateScene);
}

if (tool)
addTool(tool);
m_activeTool = tool;

if (m_activeTool && m_activeTool != m_defaultTool) {
connect(m_activeTool, SIGNAL(drawablesChanged()), this,
SLOT(updateScene()));
connect(m_activeTool, &QtGui::ToolPlugin::drawablesChanged, this,
&GLWidget::updateScene);
}
}

Expand All @@ -184,26 +199,26 @@ void GLWidget::setDefaultTool(QtGui::ToolPlugin* tool)
return;

if (m_defaultTool && m_activeTool != m_defaultTool) {
disconnect(m_defaultTool, SIGNAL(drawablesChanged()), this,
SLOT(updateScene()));
disconnect(m_defaultTool, &QtGui::ToolPlugin::drawablesChanged, this,
&GLWidget::updateScene);
}

if (tool)
addTool(tool);
m_defaultTool = tool;

if (m_defaultTool && m_activeTool != m_defaultTool) {
connect(m_defaultTool, SIGNAL(drawablesChanged()), this,
SLOT(updateScene()));
connect(m_defaultTool, &QtGui::ToolPlugin::drawablesChanged, this,
&GLWidget::updateScene);
}
}

void GLWidget::requestUpdate()
{
if (!m_renderTimer) {
m_renderTimer = new QTimer(this);
connect(m_renderTimer, SIGNAL(timeout()), SLOT(updateTimeout()));
m_renderTimer->setSingleShot(1000 / 30);
connect(m_renderTimer, &QTimer::timeout, this, &GLWidget::updateTimeout);
m_renderTimer->setSingleShot(1000 / 30); // 30 fps
m_renderTimer->start();
}
}
Expand Down
9 changes: 7 additions & 2 deletions avogadro/qtopengl/glwidget.h
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,11 @@ public slots:
*/
void updateScene();

/**
* Request update of molecule properties (e.g., dipole moment)
*/
void updateMolecule();

/**
* Clear the contents of the scene.
*/
Expand Down Expand Up @@ -201,7 +206,7 @@ protected slots:
QTimer* m_renderTimer;
};

} // End QtOpenGL namespace
} // End Avogadro namespace
} // namespace QtOpenGL
} // namespace Avogadro

#endif // AVOGADRO_QTOPENGL_GLWIDGET_H
57 changes: 45 additions & 12 deletions avogadro/qtplugins/dipole/dipole.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,26 @@ Dipole::~Dipole() {}
void Dipole::process(const QtGui::Molecule& molecule,
Rendering::GroupNode& node)
{
// check if the molecule is empty
// (single atoms don't have a dipole moment)
if (molecule.atomCount() < 0)
return;

// check if the molecule has the dipole set
if (!m_customDipole) {
if (molecule.hasData("dipoleMoment")) {
m_dipoleVector = molecule.data("dipoleMoment").toVector3();
} else {
// connect to molecule changes
connect(&molecule, &QtGui::Molecule::update, this, &Dipole::updateDipole);
connect(&molecule, SIGNAL(changed(unsigned int)), SLOT(updateDipole()));
}
} else {
// custom dipole moment set
m_dipoleVector = m_customDipoleVector;
}

// okay if we have all that, set up the arrow
auto* geometry = new GeometryNode;
node.addChild(geometry);

Expand All @@ -44,20 +64,33 @@ void Dipole::process(const QtGui::Molecule& molecule,
geometry->addDrawable(arrow);

Vector3f origin = Vector3f::Zero();
arrow->addSingleArrow(m_dipoleVector.cast<float>(), origin);
}

// check if the molecule has the dipole set
if (!m_customDipole) {
if (molecule.hasData("dipoleMoment")) {
m_dipoleVector = molecule.data("dipoleMoment").toVector3();
} else {
if (!molecule.isInteractive()) {
m_dipoleVector =
Calc::ChargeManager::instance().dipoleMoment(m_type, molecule);
}
}
}
void Dipole::updateFinished()
{
m_updateNeeded = true;
emit drawablesChanged();
}

arrow->addSingleArrow(m_dipoleVector.cast<float>(), origin);
void Dipole::updateDipole()
{
QtGui::Molecule* molecule = qobject_cast<QtGui::Molecule*>(sender());
if (molecule == nullptr || molecule->isInteractive())
return;

// if the molecule has a dipole moment set, use it
if (molecule->hasData("dipoleMoment"))
return;

// otherwise, calculate it
if (m_updateNeeded) {
m_updateNeeded = false;
m_dipoleVector =
Calc::ChargeManager::instance().dipoleMoment(m_type, *molecule);
// single-shot
QTimer::singleShot(0, this, SLOT(updateFinished()));
}
}

QWidget* Dipole::setupWidget()
Expand Down
6 changes: 6 additions & 0 deletions avogadro/qtplugins/dipole/dipole.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,12 +41,18 @@ class Dipole : public QtGui::ScenePlugin
QWidget* setupWidget() override;
bool hasSetupWidget() const override { return false; }

public slots:
void updateDipole();
void updateFinished();

private:
std::string m_name = "Dipole Moment";
std::string m_type = "MMFF94";
std::vector<std::string> m_types;
Vector3 m_dipoleVector;
Vector3 m_customDipoleVector;
bool m_customDipole = false; // Custom dipole moment set
bool m_updateNeeded = true;
};

} // end namespace QtPlugins
Expand Down
Loading