00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025 #include "bsdyengine.h"
00026
00027 #include <config.h>
00028 #include <avogadro/camera.h>
00029 #include <avogadro/painter.h>
00030 #include <avogadro/color.h>
00031
00032 #include <QGLWidget>
00033 #include <QDebug>
00034
00035 using namespace std;
00036 using namespace OpenBabel;
00037 using namespace Eigen;
00038
00039 namespace Avogadro
00040 {
00041
00042
00043 Camera *camera = 0;
00044 bool sortCameraFarthest( const Primitive* lhs, const Primitive* rhs )
00045 {
00046 if ( !lhs ) {
00047 if ( rhs ) {
00048 return true;
00049 } else {
00050 return false;
00051 }
00052 }
00053
00054 if ( lhs->type() == Primitive::BondType && rhs->type() == Primitive::BondType ) {
00055 if ( camera ) {
00056 const Bond *l = static_cast<const Bond *>( lhs );
00057 const Bond *r = static_cast<const Bond *>( rhs );
00058
00059 const Atom* latom1 = static_cast<const Atom *>( l->GetBeginAtom() );
00060 const Atom* latom2 = static_cast<const Atom *>( l->GetEndAtom() );
00061 Vector3d lv1( latom1->pos() );
00062 Vector3d lv2( latom2->pos() );
00063 Vector3d ld1 = lv2 - lv1;
00064 ld1.normalize();
00065
00066 const Atom* ratom1 = static_cast<const Atom *>( r->GetBeginAtom() );
00067 const Atom* ratom2 = static_cast<const Atom *>( r->GetEndAtom() );
00068 Vector3d rv1( ratom1->pos() );
00069 Vector3d rv2( ratom2->pos() );
00070 Vector3d rd1 = rv2 - rv1;
00071 return camera->distance( ld1 ) >= camera->distance( rd1 );
00072 }
00073 } else if ( lhs->type() == Primitive::AtomType && rhs->type() == Primitive::AtomType ) {
00074 if ( camera ) {
00075 const Atom *l = static_cast<const Atom*>( lhs );
00076 const Atom *r = static_cast<const Atom*>( rhs );
00077 return camera->distance( l->pos() ) >= camera->distance( r->pos() );
00078 }
00079 }
00080 return false;
00081 }
00082
00083 BSDYEngine::BSDYEngine( QObject *parent ) : Engine( parent ),
00084 m_settingsWidget( 0 ), m_atomRadiusPercentage( 0.3 ), m_bondRadius( 0.1 ),
00085 m_showMulti(true)
00086 {
00087 setDescription( tr( "Renders primitives using Balls (atoms) and Sticks (bonds)." ) );
00088
00089 }
00090
00091 Engine *BSDYEngine::clone() const
00092 {
00093 BSDYEngine *engine = new BSDYEngine(parent());
00094 engine->setName(name());
00095 engine->m_atomRadiusPercentage = m_atomRadiusPercentage;
00096 engine->m_bondRadius = m_bondRadius;
00097 engine->m_showMulti = m_showMulti;
00098 engine->setEnabled(isEnabled());
00099
00100 return engine;
00101 }
00102
00103 BSDYEngine::~BSDYEngine()
00104 {
00105 if ( m_settingsWidget ) {
00106 m_settingsWidget->deleteLater();
00107 }
00108
00109 }
00110
00111 bool BSDYEngine::renderOpaque( PainterDevice *pd )
00112 {
00113 QList<Primitive *> list;
00114
00115 glPushAttrib( GL_TRANSFORM_BIT );
00116
00117 Color *map = colorMap();
00118 if (!map) map = pd->colorMap();
00119
00120
00121 list = primitives().subList( Primitive::BondType );
00122
00123 foreach(const Primitive *p, list ) {
00124 const Bond *b = static_cast<const Bond *>( p );
00125
00126 const Atom* atom1 = static_cast<const Atom *>( b->GetBeginAtom() );
00127 const Atom* atom2 = static_cast<const Atom *>( b->GetEndAtom() );
00128 Vector3d v1( atom1->pos() );
00129 Vector3d v2( atom2->pos() );
00130 Vector3d d = v2 - v1;
00131 d.normalize();
00132 Vector3d v3(( v1 + v2 + d*( radius( atom1 )-radius( atom2 ) ) ) / 2 );
00133
00134 double shift = 0.15;
00135 int order = 1;
00136 if (m_showMulti) order = b->GetBO();
00137
00138 map->set( atom1 );
00139 pd->painter()->setColor( map );
00140 pd->painter()->setName( b );
00141 pd->painter()->drawMultiCylinder( v1, v3, m_bondRadius, order, shift );
00142
00143 map->set( atom2 );
00144 pd->painter()->setColor( map );
00145 pd->painter()->setName( b );
00146 pd->painter()->drawMultiCylinder( v3, v2, m_bondRadius, order, shift );
00147 }
00148
00149 glDisable( GL_NORMALIZE );
00150 glEnable( GL_RESCALE_NORMAL );
00151
00152
00153 list = primitives().subList( Primitive::AtomType );
00154 foreach(const Primitive *p, list ) {
00155 const Atom *a = static_cast<const Atom *>( p );
00156
00157 map->set( a );
00158 pd->painter()->setColor( map );
00159 pd->painter()->setName( a );
00160 pd->painter()->drawSphere( a->pos(), radius( a ) );
00161 }
00162
00163
00164 glDisable( GL_RESCALE_NORMAL );
00165 glEnable( GL_NORMALIZE );
00166
00167 glPopAttrib();
00168
00169 return true;
00170 }
00171
00172 bool BSDYEngine::renderTransparent( PainterDevice *pd )
00173 {
00174 QList<Primitive *> list;
00175
00176 camera = pd->camera();
00177
00178 glPushAttrib( GL_TRANSFORM_BIT );
00179
00180 Color *map = colorMap();
00181 if (!map) map = pd->colorMap();
00182
00183
00184 list = primitives().subList( Primitive::BondType );
00185
00186
00187
00188
00189
00190 glDepthMask( GL_TRUE );
00191
00192
00193 foreach(const Primitive *p, list ) {
00194 const Bond *b = static_cast<const Bond *>( p );
00195
00196
00197 if ( pd->isSelected( b ) ) {
00198 const Atom* atom1 = static_cast<const Atom *>( b->GetBeginAtom() );
00199 const Atom* atom2 = static_cast<const Atom *>( b->GetEndAtom() );
00200 Vector3d v1( atom1->pos() );
00201 Vector3d v2( atom2->pos() );
00202
00203 double shift = 0.15;
00204 int order = b->GetBO();
00205
00206 map->setToSelectionColor();
00207 glEnable( GL_BLEND );
00208 pd->painter()->setColor( map );
00209 pd->painter()->setName( b );
00210 if (order == 1)
00211 pd->painter()->drawCylinder(v1, v2, SEL_BOND_EXTRA_RADIUS + m_bondRadius);
00212 else
00213 pd->painter()->drawMultiCylinder( v1, v2, SEL_BOND_EXTRA_RADIUS + m_bondRadius, order, shift );
00214 glDisable( GL_BLEND );
00215 }
00216 }
00217
00218 glDepthMask( GL_FALSE );
00219 glDisable( GL_NORMALIZE );
00220 glEnable( GL_RESCALE_NORMAL );
00221
00222
00223 list = primitives().subList( Primitive::AtomType );
00224
00225
00226
00227
00228 foreach(const Primitive *p, list ) {
00229 const Atom *a = static_cast<const Atom *>( p );
00230
00231
00232 if ( pd->isSelected( a ) ) {
00233 map->setToSelectionColor();
00234 glEnable( GL_BLEND );
00235 pd->painter()->setColor( map );
00236 pd->painter()->setName( a );
00237 pd->painter()->drawSphere( a->pos(), SEL_ATOM_EXTRA_RADIUS + radius( a ) );
00238 glDisable( GL_BLEND );
00239 }
00240 }
00241
00242
00243 glDisable( GL_RESCALE_NORMAL );
00244 glEnable( GL_NORMALIZE );
00245
00246 glPopAttrib();
00247
00248 return true;
00249 }
00250
00251 bool BSDYEngine::renderQuick(PainterDevice *pd)
00252 {
00253
00254 QList<Primitive *> list;
00255
00256 Color *map = colorMap();
00257 if (!map) map = pd->colorMap();
00258 Color cSel;
00259 cSel.setToSelectionColor();
00260
00261
00262 list = primitives().subList(Primitive::BondType);
00263
00264 foreach(const Primitive *p, list)
00265 {
00266 const Bond *b = static_cast<const Bond *>(p);
00267
00268 const Atom* atom1 = static_cast<const Atom *>(b->GetBeginAtom());
00269 const Atom* atom2 = static_cast<const Atom *>(b->GetEndAtom());
00270 Vector3d v1(atom1->pos());
00271 Vector3d v2(atom2->pos());
00272 Vector3d d = v2 - v1;
00273 d.normalize();
00274 Vector3d v3((v1 + v2 + d*(radius(atom1)-radius(atom2))) / 2);
00275
00276 double shift = 0.15;
00277 int order = 1;
00278 if (m_showMulti) order = b->GetBO();
00279
00280 if (pd->isSelected(b))
00281 {
00282 pd->painter()->setColor(&cSel);
00283 pd->painter()->setName(b);
00284 pd->painter()->drawMultiCylinder(v1, v2, SEL_BOND_EXTRA_RADIUS +
00285 m_bondRadius, order, shift);
00286 }
00287 else
00288 {
00289 map->set(atom1);
00290 pd->painter()->setColor(map);
00291 pd->painter()->setName(b);
00292 pd->painter()->drawMultiCylinder(v1, v3, m_bondRadius, order, shift);
00293
00294 map->set( atom2 );
00295 pd->painter()->setColor(map);
00296 pd->painter()->setName(b);
00297 pd->painter()->drawMultiCylinder(v3, v2, m_bondRadius, order, shift);
00298 }
00299 }
00300
00301 glDisable(GL_NORMALIZE);
00302 glEnable(GL_RESCALE_NORMAL);
00303
00304
00305 list = primitives().subList(Primitive::AtomType);
00306 foreach(const Primitive *p, list)
00307 {
00308 const Atom *a = static_cast<const Atom *>(p);
00309
00310 if (pd->isSelected(a))
00311 {
00312 pd->painter()->setColor(&cSel);
00313 pd->painter()->setName(a);
00314 pd->painter()->drawSphere(a->pos(), SEL_ATOM_EXTRA_RADIUS + radius(a));
00315 }
00316 else
00317 {
00318 map->set(a);
00319 pd->painter()->setColor(map);
00320 pd->painter()->setName(a);
00321 pd->painter()->drawSphere(a->pos(), radius(a));
00322 }
00323 }
00324
00325
00326 glDisable(GL_RESCALE_NORMAL);
00327 glEnable(GL_NORMALIZE);
00328 return true;
00329 }
00330
00331 inline double BSDYEngine::radius( const Atom *atom ) const
00332 {
00333 return etab.GetVdwRad( atom->GetAtomicNum() ) * m_atomRadiusPercentage;
00334 }
00335
00336 void BSDYEngine::setAtomRadiusPercentage( int percent )
00337 {
00338 m_atomRadiusPercentage = 0.1 * percent;
00339 emit changed();
00340 }
00341
00342 void BSDYEngine::setBondRadius( int value )
00343 {
00344 m_bondRadius = value * 0.05;
00345 emit changed();
00346 }
00347
00348 void BSDYEngine::setShowMulti(int value)
00349 {
00350 m_showMulti = value;
00351 emit changed();
00352 }
00353
00354 double BSDYEngine::radius( const PainterDevice *pd, const Primitive *p ) const
00355 {
00356
00357 if ( p->type() == Primitive::AtomType ) {
00358 if ( pd ) {
00359 if ( pd->isSelected( p ) )
00360 return radius( static_cast<const Atom *>( p ) ) + SEL_ATOM_EXTRA_RADIUS;
00361 }
00362 return radius( static_cast<const Atom *>( p ) );
00363 }
00364
00365 else if ( p->type() == Primitive::BondType ) {
00366 if ( pd ) {
00367 if ( pd->isSelected( p ) )
00368 return m_bondRadius + SEL_BOND_EXTRA_RADIUS;
00369 }
00370 return m_bondRadius;
00371 }
00372
00373 else
00374 return 0.;
00375 }
00376
00377 double BSDYEngine::transparencyDepth() const
00378 {
00379 return m_atomRadiusPercentage;
00380 }
00381
00382 QWidget *BSDYEngine::settingsWidget()
00383 {
00384 if (!m_settingsWidget) {
00385 m_settingsWidget = new BSDYSettingsWidget();
00386 connect(m_settingsWidget->atomRadiusSlider, SIGNAL(valueChanged(int)), this, SLOT(setAtomRadiusPercentage(int)));
00387 connect(m_settingsWidget->bondRadiusSlider, SIGNAL(valueChanged(int)), this, SLOT(setBondRadius(int)));
00388 connect(m_settingsWidget->showMulti, SIGNAL(stateChanged(int)), this, SLOT(setShowMulti(int)));
00389 connect(m_settingsWidget, SIGNAL(destroyed()), this, SLOT(settingsWidgetDestroyed()));
00390 m_settingsWidget->atomRadiusSlider->setValue(10*m_atomRadiusPercentage);
00391 m_settingsWidget->bondRadiusSlider->setValue(20*m_bondRadius);
00392 m_settingsWidget->showMulti->setCheckState((Qt::CheckState)m_showMulti);
00393 }
00394 return m_settingsWidget;
00395 }
00396
00397 void BSDYEngine::settingsWidgetDestroyed()
00398 {
00399 qDebug() << "Destroyed Settings Widget";
00400 m_settingsWidget = 0;
00401 }
00402
00403 void BSDYEngine::writeSettings(QSettings &settings) const
00404 {
00405 Engine::writeSettings(settings);
00406 settings.setValue("atomRadius", 10*m_atomRadiusPercentage);
00407 settings.setValue("bondRadius", 20*m_bondRadius);
00408 settings.setValue("showMulti", m_showMulti);
00409 }
00410
00411 void BSDYEngine::readSettings(QSettings &settings)
00412 {
00413 Engine::readSettings(settings);
00414 setAtomRadiusPercentage(settings.value("atomRadius", 3).toInt());
00415 setBondRadius(settings.value("bondRadius", 2).toInt());
00416 setShowMulti(settings.value("showMulti", 2).toInt());
00417
00418 if (m_settingsWidget) {
00419 m_settingsWidget->atomRadiusSlider->setValue(10*m_atomRadiusPercentage);
00420 m_settingsWidget->bondRadiusSlider->setValue(20*m_bondRadius);
00421 m_settingsWidget->showMulti->setCheckState((Qt::CheckState)m_showMulti);
00422 }
00423 }
00424
00425
00426 Engine::EngineFlags BSDYEngine::flags() const
00427 {
00428 return Engine::Transparent | Engine::Atoms | Engine::Bonds;
00429 }
00430
00431
00432 }
00433
00434 #include "bsdyengine.moc"
00435
00436 Q_EXPORT_PLUGIN2( bsdyengine, Avogadro::BSDYEngineFactory )