/********************************************************************** StickEngine - Engine for "stick" display Copyright (C) 2006-2008 Geoffrey R. Hutchison Copyright (C) 2008 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 "stickengine.h" #include #include #include #include #include #include #include #include #include #include #include using namespace Eigen; // Conversion from integers to double // Default has been 20.0 // i.e., smallest radius = 0.05 (1/20), default is 0.25 (5/20), max is 0.5 (10/20) #define SCALING_FACTOR 20.0 namespace Avogadro { StickEngine::StickEngine(QObject *parent) : Engine(parent), m_settingsWidget(0), m_radius(0.25) { } StickEngine::~StickEngine() { // Delete the settings widget if it exists if(m_settingsWidget) m_settingsWidget->deleteLater(); } Engine* StickEngine::clone() const { StickEngine* engine = new StickEngine(parent()); engine->setAlias(alias()); engine->setEnabled(isEnabled()); engine->setRadius(m_radius * SCALING_FACTOR); return engine; } bool StickEngine::renderOpaque(PainterDevice *pd) { // glPushAttrib(GL_TRANSFORM_BIT); glDisable( GL_NORMALIZE ); glEnable( GL_RESCALE_NORMAL ); // Render the atoms foreach(Atom *a, atoms()) renderOpaque(pd, a); // render bonds (sticks) glDisable( GL_RESCALE_NORMAL ); glEnable( GL_NORMALIZE ); foreach(Bond *b, bonds()) renderOpaque(pd, b); // glPopAttrib(); return true; } bool StickEngine::renderTransparent(PainterDevice *pd) { glDisable( GL_NORMALIZE ); glEnable( GL_RESCALE_NORMAL ); Color *map = colorMap(); // possible custom color map if (!map) map = pd->colorMap(); // fall back to global color map map->setToSelectionColor(); pd->painter()->setColor(map); // Render the atoms foreach(Atom *a, atoms()) { if (pd->isSelected(a)) { pd->painter()->setName(a); pd->painter()->drawSphere(a->pos(), SEL_ATOM_EXTRA_RADIUS + radius(a)); } } // render bonds (sticks) glDisable( GL_RESCALE_NORMAL ); glEnable( GL_NORMALIZE ); foreach(Bond *b, bonds()) { if (pd->isSelected(b)) { Atom* atom1 = pd->molecule()->atomById(b->beginAtomId()); Atom* atom2 = pd->molecule()->atomById(b->endAtomId()); Vector3d v1 (*atom1->pos()); Vector3d v2 (*atom2->pos()); Vector3d v3 (( v1 + v2 ) / 2); pd->painter()->setName(b); pd->painter()->drawCylinder(v1, v2, SEL_BOND_EXTRA_RADIUS + radius(atom1)); } } return true; } inline bool StickEngine::renderOpaque(PainterDevice *pd, const Atom* a) { Color *map = colorMap(); // possible custom color map if (!map) map = pd->colorMap(); // fall back to global color map map->set(a); pd->painter()->setColor(map); pd->painter()->setName(a); pd->painter()->drawSphere( a->pos(), radius(a) ); return true; } inline bool StickEngine::renderOpaque(PainterDevice *pd, const Bond* b) { Color *map = colorMap(); // possible custom color map if (!map) map = pd->colorMap(); // fall back to global color map Atom* atom1 = pd->molecule()->atomById(b->beginAtomId()); Atom* atom2 = pd->molecule()->atomById(b->endAtomId()); Vector3d v1 (*atom1->pos()); Vector3d v2 (*atom2->pos()); Vector3d v3 (( v1 + v2 ) / 2); map->set(atom1); pd->painter()->setColor(map); pd->painter()->setName(b); pd->painter()->drawCylinder( v1, v3, radius(atom1) ); map->set(atom2); pd->painter()->setColor(map); pd->painter()->setName(b); pd->painter()->drawCylinder( v3, v2, radius(atom1) ); return true; } double StickEngine::radius(const PainterDevice *pd, const Primitive *p) const { // Atom radius if (p->type() == Primitive::AtomType) { if (pd) { if (pd->isSelected(p)) return radius(static_cast(p)) + SEL_ATOM_EXTRA_RADIUS; } return radius(static_cast(p)); } // Bond radius else if (p->type() == Primitive::BondType) { const Atom* a = pd->molecule()->atomById(static_cast(p)->beginAtomId()); if (pd) { if (pd->isSelected(p)) return radius(a) + SEL_BOND_EXTRA_RADIUS; } return radius(a); } // Something else else return 0.; } inline double StickEngine::radius(const Atom*) const { return m_radius; } Engine::Layers StickEngine::layers() const { return Engine::Opaque | Engine::Transparent; } // **** Settings Widget *** void StickEngine::setRadius(int value) { m_radius = value / SCALING_FACTOR; emit changed(); } QWidget* StickEngine::settingsWidget() { if(!m_settingsWidget) { m_settingsWidget = new StickSettingsWidget(); connect(m_settingsWidget->radiusSlider, SIGNAL(valueChanged(int)), this, SLOT(setRadius(int))); connect(m_settingsWidget, SIGNAL(destroyed()), this, SLOT(settingsWidgetDestroyed())); m_settingsWidget->radiusSlider->setValue(SCALING_FACTOR*m_radius); } return m_settingsWidget; } void StickEngine::settingsWidgetDestroyed() { m_settingsWidget = 0; } void StickEngine::writeSettings(QSettings &settings) const { Engine::writeSettings(settings); settings.setValue("radius", SCALING_FACTOR*m_radius); } void StickEngine::readSettings(QSettings &settings) { Engine::readSettings(settings); // default = 0.25 as far as m_radius setRadius(settings.value("radius", 5).toInt()); if (m_settingsWidget) { m_settingsWidget->radiusSlider->setValue(SCALING_FACTOR*m_radius); } } } #include "stickengine.moc" Q_EXPORT_PLUGIN2(stickengine, Avogadro::StickEngineFactory)