/********************************************************************** RibbonEngine - Engine for "ribbon" display Copyright (C) 2007-2008 by Marcus D. Hanwell This file is part of the Avogadro molecular editor project. For more information, see Avogadro is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. Avogadro is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. **********************************************************************/ #include "ribbonengine.h" #include #include #include #include #include #include #include #include #include #include #include using Eigen::Vector3d; namespace Avogadro { const float chainColors[6][3] = { { 1.0, 0.0, 0.0 }, { 0.0, 1.0, 0.0 }, { 0.0, 0.0, 1.0 }, { 1.0, 0.0, 1.0 }, { 1.0, 1.0, 0.0 }, { 0.0, 1.0, 1.0 } }; RibbonEngine::RibbonEngine(QObject *parent) : Engine(parent), m_settingsWidget(0), m_type(0), m_radius(1.0), m_update(true), m_useNitrogens(2) { } Engine *RibbonEngine::clone() const { RibbonEngine *engine = new RibbonEngine(parent()); engine->setAlias(alias()); engine->m_type = m_type; engine->m_radius = m_radius; engine->setUseNitrogens(m_useNitrogens); engine->setEnabled(isEnabled()); return engine; } RibbonEngine::~RibbonEngine() { // Delete the settings widget if it exists if(m_settingsWidget) m_settingsWidget->deleteLater(); } bool RibbonEngine::renderOpaque(PainterDevice *pd) { // Check if the chains need updating before drawing them if (m_update) updateChains(pd); if (m_type == 0) { for (int i = 0; i < m_chains.size(); i++) { if (m_chains[i].size() <= 1) continue; pd->painter()->setColor(chainColors[i % 6][0], chainColors[i % 6][1], chainColors[i % 6][2]); pd->painter()->drawSpline(m_chains[i], m_radius); } } else { // Render cylinders between the points and spheres at each point for (int i = 0; i < m_chains.size(); i++) { if (m_chains[i].size() <= 1) continue; pd->painter()->setColor(chainColors[i % 6][0], chainColors[i % 6][1], chainColors[i % 6][2]); pd->painter()->drawSphere(&m_chains[i][0], m_radius); for (int j = 1; j < m_chains[i].size(); j++) { pd->painter()->drawSphere(&m_chains[i][j], m_radius); pd->painter()->drawCylinder(m_chains[i][j-1], m_chains[i][j], m_radius); } } } return true; } bool RibbonEngine::renderQuick(PainterDevice *pd) { // Just render cylinders between the backbone... double tRadius = m_radius / 2.0; for (int i = 0; i < m_chains.size(); i++) { if (m_chains[i].size() <= 1) continue; pd->painter()->setColor(chainColors[i % 6][0], chainColors[i % 6][1], chainColors[i % 6][2]); pd->painter()->drawSphere(&m_chains[i][0], tRadius); for (int j = 1; j < m_chains[i].size(); j++) { pd->painter()->drawSphere(&m_chains[i][j], tRadius); pd->painter()->drawCylinder(m_chains[i][j-1], m_chains[i][j], tRadius); } } return true; } double RibbonEngine::radius(const PainterDevice *, const Primitive *) const { return m_radius; } void RibbonEngine::setPrimitives(const PrimitiveList &primitives) { Engine::setPrimitives(primitives); m_update = true; } void RibbonEngine::addPrimitive(Primitive *primitive) { Engine::addPrimitive(primitive); m_update = true; } void RibbonEngine::updatePrimitive(Primitive *) { m_update = true; } void RibbonEngine::removePrimitive(Primitive *primitive) { Engine::removePrimitive(primitive); m_update = true; } void RibbonEngine::updateChains(PainterDevice *pd) { if (!isEnabled()) return; m_chains.clear(); QList list; list = primitives().subList(Primitive::ResidueType); unsigned int currentChain = 0; QVector pts; // Get a list of residues for the molecule const Molecule *molecule = pd->molecule(); foreach(Primitive *p, list) { Residue *r = static_cast(p); if(r->name() =="HOH") { continue; } if(r->chainNumber() != currentChain) { // this residue is on a new chain if(pts.size() > 0) m_chains.push_back(pts); currentChain = r->chainNumber(); pts.clear(); } foreach (unsigned long atom, r->atoms()) { // should be CA QString atomId = r->atomId(atom); atomId = atomId.trimmed(); if (atomId == "CA") { pts.push_back(*molecule->atomById(atom)->pos()); } else if (atomId == "N" && m_useNitrogens == 2) { pts.push_back(*molecule->atomById(atom)->pos()); } } // end atoms in residue } // end primitive list (i.e., all residues) m_chains.push_back(pts); // Add the last chain (possibly the only chain) m_update = false; } Engine::PrimitiveTypes RibbonEngine::primitiveTypes() const { return Engine::Atoms; } Engine::ColorTypes RibbonEngine::colorTypes() const { return Engine::IndexedColors; } void RibbonEngine::setType(int value) { m_type = value; emit changed(); } void RibbonEngine::setRadius(int value) { m_radius = 0.1 * value; emit changed(); } void RibbonEngine::setUseNitrogens(int setting) { m_useNitrogens = setting; m_update = true; emit changed(); } QWidget* RibbonEngine::settingsWidget() { if(!m_settingsWidget) { m_settingsWidget = new RibbonSettingsWidget(); connect(m_settingsWidget->renderType, SIGNAL(activated(int)), this, SLOT(setType(int))); connect(m_settingsWidget->radiusSlider, SIGNAL(valueChanged(int)), this, SLOT(setRadius(int))); connect(m_settingsWidget->useNitrogens, SIGNAL(stateChanged(int)), this, SLOT(setUseNitrogens(int))); connect(m_settingsWidget, SIGNAL(destroyed()), this, SLOT(settingsWidgetDestroyed())); m_settingsWidget->renderType->setCurrentIndex(m_type); m_settingsWidget->radiusSlider->setValue(int(10 * m_radius)); m_settingsWidget->useNitrogens->setCheckState((Qt::CheckState)m_useNitrogens); } return m_settingsWidget; } void RibbonEngine::settingsWidgetDestroyed() { m_settingsWidget = 0; } void RibbonEngine::writeSettings(QSettings &settings) const { Engine::writeSettings(settings); settings.setValue("radius", 10*m_radius); settings.setValue("type", m_type); settings.setValue("useNitrogens", m_useNitrogens); } void RibbonEngine::readSettings(QSettings &settings) { Engine::readSettings(settings); setType(settings.value("type", 0).toInt()); setRadius(settings.value("radius", 10).toInt()); setUseNitrogens(settings.value("useNitrogens", 2).toInt()); if (m_settingsWidget) { m_settingsWidget->renderType->setCurrentIndex(m_type); m_settingsWidget->radiusSlider->setValue(int(10 * m_radius)); m_settingsWidget->useNitrogens->setCheckState((Qt::CheckState)m_useNitrogens); } } } #include "ribbonengine.moc" Q_EXPORT_PLUGIN2(ribbonengine, Avogadro::RibbonEngineFactory)