00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00019
00027
00028
00029
00031
00032
00033 #include <cassert>
00034 #include <cmath>
00035
00036
00037 #include <algorithm>
00038
00039
00040 #include <qapplication.h>
00041 #include <qdom.h>
00042 #include <qfiledialog.h>
00043 #include <qmessagebox.h>
00044 #include <qpoint.h>
00045 #include <qstringlist.h>
00046
00047
00048 #include "atomset.h"
00049 #include "domutils.h"
00050 #include "glsimplemoleculeview.h"
00051 #include "point3d.h"
00052 #include "vector3d.h"
00053
00057
00059 GLSimpleMoleculeView::GLSimpleMoleculeView(AtomSet* atomset, QWidget* parent, const char* name ) : GLView(parent, name),
00060 chargeType(AtomSet::None),
00061 atoms(atomset),
00062 scaleFactor(1.0f)
00064 {
00065 moleculeStyle = moleculeParameters.defaultMoleculeStyle;
00066 forcesStyle = moleculeParameters.defaultForcesStyle;
00067 showElements = moleculeParameters.showElements;
00068 showNumbers = moleculeParameters.showNumbers;
00069 assert(atomset != 0);
00070 centerMolecule();
00071 reorderShapes();
00072 labelFont = QApplication::font();
00073 #ifndef WIN32
00074
00075
00076
00077 labelFont.setStyleHint(QFont::AnyStyle, QFont::PreferBitmap);
00078 labelFont.setPointSize(QApplication::font().pointSize());
00079
00080 #endif
00081 }
00082
00084 GLSimpleMoleculeView::~GLSimpleMoleculeView()
00086 {
00087 makeCurrent();
00088 glDeleteLists(atomObject, 4);
00089 }
00090
00092 unsigned int GLSimpleMoleculeView::displayStyle(const DisplaySource source) const
00094 {
00095 if(source == Molecule)
00096 return moleculeStyle;
00097 else
00098 return forcesStyle;
00099 }
00100
00102 bool GLSimpleMoleculeView::isShowingElements() const
00104 {
00105 return showElements;
00106 }
00107
00109 bool GLSimpleMoleculeView::isShowingNumbers() const
00111 {
00112 return showNumbers;
00113 }
00114
00116 bool GLSimpleMoleculeView::isShowingCharges(const unsigned int type) const
00118 {
00119 return type == chargeType;
00120 }
00121
00123 unsigned int GLSimpleMoleculeView::selectedAtoms() const
00125 {
00126 return selectionList.size();
00127 }
00129 void GLSimpleMoleculeView::loadCML(QDomElement* root)
00131 {
00132 float wQuat = 0.0f, xQuat = 0.0f, yQuat = 0.0f, zQuat = 0.0f;
00133 QDomNode childNode = root->firstChild();
00134 const QString prefix = "view_";
00135 while(!childNode.isNull())
00136 {
00137 if(childNode.isElement() && childNode.nodeName() == "parameter")
00138 {
00139 if(DomUtils::dictEntry(childNode, prefix + "orientation-w"))
00140 DomUtils::readNode(&childNode, &wQuat);
00141 else if(DomUtils::dictEntry(childNode, prefix + "orientation-x"))
00142 DomUtils::readNode(&childNode, &xQuat);
00143 else if(DomUtils::dictEntry(childNode, prefix + "orientation-y"))
00144 DomUtils::readNode(&childNode, &yQuat);
00145 else if(DomUtils::dictEntry(childNode, prefix + "orientation-z"))
00146 DomUtils::readNode(&childNode, &zQuat);
00147 else if(DomUtils::dictEntry(childNode, prefix + "position-x"))
00148 DomUtils::readNode(&childNode, &xPos);
00149 else if(DomUtils::dictEntry(childNode, prefix + "position-y"))
00150 DomUtils::readNode(&childNode, &yPos);
00151 else if(DomUtils::dictEntry(childNode, prefix + "position-z"))
00152 DomUtils::readNode(&childNode, &zPos);
00153 else if(DomUtils::dictEntry(childNode, prefix + "center-x"))
00154 DomUtils::readNode(&childNode, ¢erX);
00155 else if(DomUtils::dictEntry(childNode, prefix + "center-y"))
00156 DomUtils::readNode(&childNode, ¢erY);
00157 else if(DomUtils::dictEntry(childNode, prefix + "center-z"))
00158 DomUtils::readNode(&childNode, ¢erZ);
00159 else if(DomUtils::dictEntry(childNode, prefix + "style_molecule"))
00160 DomUtils::readNode(&childNode, &moleculeStyle);
00161 else if(DomUtils::dictEntry(childNode, prefix + "style_forces"))
00162 DomUtils::readNode(&childNode, &forcesStyle);
00163 else if(DomUtils::dictEntry(childNode, prefix + "show_elements"))
00164 DomUtils::readNode(&childNode, &showElements);
00165 else if(DomUtils::dictEntry(childNode, prefix + "show_numbers"))
00166 DomUtils::readNode(&childNode, &showNumbers);
00167 else if(DomUtils::dictEntry(childNode, prefix + "show_charges_type"))
00168 DomUtils::readNode(&childNode, &chargeType);
00169 }
00170 childNode = childNode.nextSibling();
00171 }
00172 orientationQuaternion->setValues(wQuat, xQuat, yQuat, zQuat);
00173
00174 makeCurrent();
00175 updateFog(boundingSphereRadius());
00176 updateGL();
00177 }
00178
00180 void GLSimpleMoleculeView::saveCML(QDomElement* root)
00182 {
00183 const QString prefix = "view_";
00184 DomUtils::makeNode(root, orientationQuaternion->w(), prefix + "orientation-w");
00185 DomUtils::makeNode(root, orientationQuaternion->x(), prefix + "orientation-x");
00186 DomUtils::makeNode(root, orientationQuaternion->y(), prefix + "orientation-y");
00187 DomUtils::makeNode(root, orientationQuaternion->z(), prefix + "orientation-z");
00188 DomUtils::makeNode(root, static_cast<float>(xPos), prefix + "position-x");
00189 DomUtils::makeNode(root, static_cast<float>(yPos), prefix + "position-y");
00190 DomUtils::makeNode(root, static_cast<float>(zPos), prefix + "position-z");
00191 DomUtils::makeNode(root, static_cast<float>(centerX), prefix + "center-x");
00192 DomUtils::makeNode(root, static_cast<float>(centerY), prefix + "center-y");
00193 DomUtils::makeNode(root, static_cast<float>(centerZ), prefix + "center-z");
00194 DomUtils::makeNode(root, moleculeStyle, prefix + "style_molecule");
00195 DomUtils::makeNode(root, forcesStyle, prefix + "style_forces");
00196 DomUtils::makeNode(root, showElements, prefix + "show_elements");
00197 DomUtils::makeNode(root, showNumbers, prefix + "show_numbers");
00198 DomUtils::makeNode(root, chargeType, prefix + "show_charges_type");
00199 }
00200
00202 void GLSimpleMoleculeView::setDisplayStyle(const DisplaySource source, const unsigned int style)
00204 {
00205 if(source == Molecule)
00206 {
00207 if(style > VanDerWaals)
00208 moleculeStyle = BallAndStick;
00209 else
00210 moleculeStyle = style;
00211 }
00212 else
00213 {
00214 if(style > Tubes)
00215 forcesStyle = Tubes;
00216 else
00217 forcesStyle = style;
00218 }
00219 setModified();
00220 }
00221
00223 void GLSimpleMoleculeView::setLabels(const bool element, const bool number, const unsigned int type)
00225 {
00226 showElements = element;
00227 showNumbers = number;
00228 if(type > AtomSet::Stockholder)
00229 chargeType = AtomSet::None;
00230 else
00231 chargeType = type;
00232 setModified();
00233 }
00234
00236 void GLSimpleMoleculeView::setParameters(GLMoleculeParameters params)
00239 {
00240 moleculeParameters = params;
00241
00242 }
00243
00247
00249 void GLSimpleMoleculeView::updateAtomSet(const bool reset)
00255 {
00256 centerMolecule();
00257 if(reset)
00258 {
00259 resetView(false);
00260 unselectAll(false);
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277
00278
00279
00280
00281
00282 switch(selectionList.size())
00283 {
00284 case 0: selectionType = SELECTION_NONE;
00285 break;
00286 case 1: selectionType = SELECTION_ATOM;
00287 break;
00288 case 2: selectionType = SELECTION_BOND;
00289 break;
00290 case 3: selectionType = SELECTION_ANGLE;
00291 break;
00292 case 4: selectionType = SELECTION_TORSION;
00293 break;
00294 default: selectionType = SELECTION_GROUP;
00295 }
00296
00297 }
00298 updateGL();
00299 }
00300
00302 void GLSimpleMoleculeView::selectAll(const bool update)
00304 {
00305 unselectAll(false);
00306 for(unsigned int i = 0; i < atoms->count(); i++)
00307 selectionList.push_back(i);
00308 switch(selectionList.size())
00309 {
00310 case 0: selectionType = SELECTION_NONE;
00311 break;
00312 case 1: selectionType = SELECTION_ATOM;
00313 break;
00314 case 2: selectionType = SELECTION_BOND;
00315 break;
00316 case 3: selectionType = SELECTION_ANGLE;
00317 break;
00318 case 4: selectionType = SELECTION_TORSION;
00319 break;
00320 default: selectionType = SELECTION_GROUP;
00321 }
00322 if(update)
00323 updateGL();
00324 emit changed();
00325 }
00326
00328 void GLSimpleMoleculeView::unselectAll(const bool update)
00330 {
00331 selectionList.clear();
00332 selectionType = SELECTION_NONE;
00333
00334 if(update)
00335 updateGL();
00336 emit changed();
00337 }
00338
00342
00344 void GLSimpleMoleculeView::reorderShapes()
00346 {
00347 updateShapes();
00348 std::sort(shapes.begin(), shapes.end());
00349 }
00350
00354
00356 void GLSimpleMoleculeView::keyPressEvent(QKeyEvent* e)
00359 {
00360 if(e->state() & Qt::ControlButton && (e->key() == Qt::Key_Plus || e->key() == Qt::Key_1))
00361 {
00362 labelFont.setPointSize(labelFont.pointSize() + 1);
00363 qDebug("increasing font size by 1");
00364 updateGL();
00365 }
00366 else if(e->state() & Qt::ControlButton && (e->key() == Qt::Key_Minus || e->key() == Qt::Key_2))
00367 {
00368 labelFont.setPointSize(labelFont.pointSize() - 1);
00369 qDebug("decreasing font size by 1");
00370 updateGL();
00371 }
00372 else
00373 GLView::keyPressEvent(e);
00374 }
00375
00377 void GLSimpleMoleculeView::initializeGL()
00379 {
00380 int numSlices = static_cast<int>(pow(2.0,static_cast<double>(moleculeParameters.quality)));
00381 atomObject = makeObjects(numSlices);
00382 bondObject = atomObject + 1;
00383 forceObjectLines = atomObject + 2;
00384 forceObjectTubes = atomObject + 3;
00385 updateGLSettings();
00386
00387 GLView::initializeGL();
00388 }
00389
00391 float GLSimpleMoleculeView::boundingSphereRadius()
00393 {
00394 float radius = 0.0;
00395 float x, y, z, tempradius;
00396 for(unsigned int i = 0; i < atoms->count(); i++)
00397 {
00398 x = static_cast<float>(atoms->x(i) - centerX);
00399 y = static_cast<float>(atoms->y(i) - centerY);
00400 z = static_cast<float>(atoms->z(i) - centerZ);
00402 tempradius = sqrt(x*x + y*y + z*z) + static_cast<float>(AtomSet::vanderWaals(atoms->atomicNumber(i)))/2.0f;
00403 if(tempradius > radius)
00404 radius = tempradius;
00405 }
00406 if(radius > 25.0f)
00407 {
00408 scaleFactor = 25.0f/radius;
00409 radius = 25.0f;
00410 }
00411 else
00412 scaleFactor = 1.0f;
00413 if(radius < 0.4f)
00414 radius = 0.4f;
00415 return radius;
00416 }
00417
00419 void GLSimpleMoleculeView::drawItem(const unsigned int)
00423 {
00424
00425 }
00426
00428 void GLSimpleMoleculeView::clicked(const QPoint& position)
00430 {
00431 selectEntity(position);
00432 }
00433
00435 void GLSimpleMoleculeView::updateGLSettings()
00439 {
00440 GLView::updateGLSettings();
00441
00444
00445 changeObjects(atomObject, moleculeParameters.quality);
00446
00449
00450 GLfloat lwRange[] = {0.0f, 0.0f};
00451 glGetFloatv(GL_LINE_WIDTH_RANGE, lwRange);
00452 GLfloat psRange[] = {0.0f, 0.0f};
00453 glGetFloatv(GL_POINT_SIZE_RANGE, psRange);
00455 selectionLineWidth = moleculeParameters.sizeLines * 3.0f;
00456 if(selectionLineWidth < 3.0f)
00457 selectionLineWidth = 3.0f;
00458 if(selectionLineWidth > lwRange[1])
00459 selectionLineWidth = lwRange[1];
00461 selectionPointSize = moleculeParameters.sizeLines * 5.0f;
00462 if(selectionPointSize < 5.0f)
00463 selectionPointSize = 5.0f;
00464 if(selectionPointSize > psRange[1])
00465 selectionPointSize = psRange[1];
00466
00468 glLineWidth(moleculeParameters.sizeLines);
00469
00471 reorderShapes();
00472 }
00473
00475 void GLSimpleMoleculeView::updateShapes()
00477 {
00478 shapes.clear();
00479 ShapeProperties prop;
00480
00481
00482 prop.id = 0;
00483 prop.opacity = 100;
00484 prop.type = SHAPE_ATOMS;
00485 shapes.push_back(prop);
00486
00487 prop.id = 0;
00488 prop.opacity = 100;
00489 prop.type = SHAPE_BONDS;
00490 shapes.push_back(prop);
00491
00492 prop.id = 0;
00493 prop.opacity = moleculeParameters.opacityForces;
00494 prop.type = SHAPE_FORCES;
00495 shapes.push_back(prop);
00496
00497 prop.id = 0;
00498 prop.opacity = 100;
00499 prop.type = SHAPE_LABELS;
00500 shapes.push_back(prop);
00501
00502 prop.id = 0;
00503 prop.opacity = 100;
00504 prop.type = SHAPE_IC;
00505 shapes.push_back(prop);
00506
00507 prop.id = 0;
00508 prop.opacity = moleculeParameters.opacitySelections;
00509 prop.type = SHAPE_SELECTION;
00510 shapes.push_back(prop);
00511 }
00512
00516
00518 GLuint GLSimpleMoleculeView::makeObjects(const int numSlices)
00520 {
00521 GLuint startList = glGenLists(4);
00522 changeObjects(startList, numSlices);
00523 return startList;
00524 }
00525
00527 void GLSimpleMoleculeView::changeObjects(const GLuint startList, const int numSlices)
00529 {
00530 GLUquadricObj* qobj;
00531 qobj = gluNewQuadric();
00533
00534 gluQuadricNormals(qobj, GLU_SMOOTH);
00535 gluQuadricOrientation(qobj, GLU_OUTSIDE);
00536
00538 glNewList(startList, GL_COMPILE);
00539 gluSphere(qobj, 1.0f, numSlices, numSlices);
00540 glEndList();
00541
00543 glNewList(startList + 1, GL_COMPILE);
00544 gluCylinder(qobj, 1.0f, 1.0f, cylinderHeight, numSlices, 1);
00545 glEndList();
00546
00548 glNewList(startList + 2, GL_COMPILE);
00549 glBegin(GL_LINES);
00550
00551 glVertex3f(0.0f, 0.0f, 0.0f);
00552 glVertex3f(0.0f, 0.0f, cylinderHeight);
00553
00554 glVertex3f(0.0f, 0.0f, cylinderHeight);
00555 glVertex3f(-0.1f, -0.1f, 0.9f * cylinderHeight);
00556 glVertex3f(0.0f, 0.0f, cylinderHeight);
00557 glVertex3f(0.1f, 0.1f, 0.9f * cylinderHeight);
00558 glEnd();
00559 glEndList();
00560
00562 glNewList(startList + 3, GL_COMPILE);
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575 gluCylinder(qobj, 1.0f, 1.0f, cylinderHeight - 2.4f, numSlices, 1);
00576 glTranslatef(0.0f, 0.0f, cylinderHeight - 2.4f);
00577 gluCylinder(qobj, 1.2f, 0.0f, 2.4f, numSlices, 1);
00578 gluQuadricOrientation(qobj, GLU_INSIDE);
00579 gluDisk(qobj, 0.0f, 1.2f, numSlices, 1);
00580 glEndList();
00581
00582 gluDeleteQuadric(qobj);
00583 }
00584
00586 void GLSimpleMoleculeView::selectEntity(const QPoint position)
00588 {
00589 makeCurrent();
00591 const unsigned int BUFFER_SIZE = 64;
00592 GLuint selectionBuffer[BUFFER_SIZE];
00593 GLuint* pBuffer = selectionBuffer;
00594 GLint viewport[4];
00595
00597 glSelectBuffer(BUFFER_SIZE, pBuffer);
00598 glGetIntegerv(GL_VIEWPORT, viewport);
00599 glMatrixMode(GL_PROJECTION);
00600 glPushMatrix();
00601 glRenderMode(GL_SELECT);
00602 glLoadIdentity();
00603 GLint xPosition = position.x();
00604 GLint yPosition = viewport[3] - position.y();
00605 gluPickMatrix(xPosition, yPosition, 2, 2, viewport);
00606 setPerspective();
00607 glMatrixMode(GL_MODELVIEW);
00608
00609 if(moleculeStyle == None || moleculeStyle == Lines)
00610 {
00612 unsigned int oldStyle = moleculeStyle;
00613 moleculeStyle = Tubes;
00614 updateGL();
00615 moleculeStyle = oldStyle;
00616 }
00617 else
00618 updateGL();
00619
00621 GLint hits = glRenderMode(GL_RENDER);
00622
00624 glMatrixMode(GL_PROJECTION);
00625 glPopMatrix();
00626 glMatrixMode(GL_MODELVIEW);
00627
00629 if(hits != 0)
00630 {
00631 pBuffer++;
00632 pBuffer++;
00633 pBuffer++;
00634 GLuint id = *pBuffer;
00635
00636
00637 processSelection(id);
00638 updateGL();
00639 }
00640 emit changed();
00641 }
00642
00644 void GLSimpleMoleculeView::processSelection(const unsigned int id)
00647 {
00648 switch(id)
00649 {
00650 case START_BONDS: selectionList.clear();
00651 selectionType = SELECTION_BONDS;
00652 break;
00653 case START_FORCES: selectionList.clear();
00654 selectionType = SELECTION_FORCES;
00655 break;
00656 default: if(id >= START_ATOMS)
00657 {
00658 unsigned int selectedAtom = id - START_ATOMS;
00659
00661 std::list<unsigned int>::iterator it = std::find(selectionList.begin(), selectionList.end(), selectedAtom);
00662 if(it == selectionList.end())
00663 {
00665 selectionList.push_back(selectedAtom);
00666 }
00667 else
00668 {
00670 selectionList.erase(it);
00671 }
00672
00674 switch(selectionList.size())
00675 {
00676 case 0: selectionType = SELECTION_NONE;
00677 break;
00678 case 1: selectionType = SELECTION_ATOM;
00679 break;
00680 case 2: selectionType = SELECTION_BOND;
00681 break;
00682 case 3: selectionType = SELECTION_ANGLE;
00683 break;
00684 case 4: selectionType = SELECTION_TORSION;
00685 break;
00686 default: selectionType = SELECTION_GROUP;
00687 }
00688 }
00689 }
00690 }
00691
00693 void GLSimpleMoleculeView::centerMolecule()
00696 {
00697 centerX = 0.0f;
00698 centerY = 0.0f;
00699 centerZ = 0.0f;
00700
00701 if(atoms->count() == 0)
00702 return;
00703
00705 double maxx = atoms->x(0);
00706 double maxy = atoms->y(0);
00707 double maxz = atoms->z(0);
00708 double minx = maxx;
00709 double miny = maxy;
00710 double minz = maxz;
00711 for(unsigned int i = 1; i < atoms->count(); i++)
00712 {
00713 if(atoms->x(i) > maxx)
00714 maxx = atoms->x(i);
00715 else if(atoms->x(i) < minx)
00716 minx = atoms->x(i);
00717 if(atoms->y(i) > maxy)
00718 maxy = atoms->y(i);
00719 else if(atoms->y(i) < miny)
00720 miny = atoms->y(i);
00721 if(atoms->z(i) > maxz)
00722 maxz = atoms->z(i);
00723 else if(atoms->z(i) < minz)
00724 minz = atoms->z(i);
00725 }
00727 centerX = static_cast<GLfloat>((maxx + minx)/2.0);
00728 centerY = static_cast<GLfloat>((maxy + miny)/2.0);
00729 centerZ = static_cast<GLfloat>((maxz + minz)/2.0);
00730 }
00731
00733 void GLSimpleMoleculeView::drawScene()
00739 {
00740
00741 if(scaleFactor < 1.0f)
00742 glScalef(scaleFactor, scaleFactor, scaleFactor);
00743
00744 glTranslatef(-centerX, -centerY, -centerZ);
00745
00746 glInitNames();
00747 glPushName(0);
00748
00750 unsigned int oldMoleculeStyle = moleculeStyle;
00751 unsigned int oldForcesStyle = forcesStyle;
00752 bool oldShowElements = showElements;
00753 bool oldShowNumbers = showNumbers;
00754 unsigned int oldChargeType = chargeType;
00755 if(atoms->count() > moleculeParameters.fastRenderLimit)
00756 {
00757 moleculeStyle = Lines;
00758 forcesStyle = None;
00759 showElements = false;
00760 showNumbers = false;
00761 chargeType = AtomSet::None;
00762 }
00763
00764 bool usedBlending = false;
00766 for(unsigned int i = 0; i < shapes.size(); i++)
00767 {
00769 if(!usedBlending && shapes[i].opacity < 100)
00770 {
00771 usedBlending = true;
00772 glEnable(GL_BLEND);
00773 }
00774 switch(shapes[i].type)
00775 {
00776 case SHAPE_ATOMS:
00777 drawAtoms();
00778 break;
00779 case SHAPE_BONDS:
00780 drawBonds();
00781 break;
00782 case SHAPE_FORCES:
00783 drawForces();
00784 break;
00785 case SHAPE_LABELS:
00786 drawLabels();
00787 break;
00788 case SHAPE_IC:
00789 drawICValue();
00790 break;
00791 case SHAPE_SELECTION:
00792 drawSelections();
00793 break;
00794 default:
00795
00796 drawItem(i);
00797 }
00798 }
00799 if(usedBlending)
00800 glDisable(GL_BLEND);
00801
00803 if(atoms->count() > moleculeParameters.fastRenderLimit)
00804 {
00805 moleculeStyle = oldMoleculeStyle;
00806 forcesStyle = oldForcesStyle;
00807 showElements = oldShowElements;
00808 showNumbers = oldShowNumbers;
00809 chargeType = oldChargeType;
00810 }
00811 }
00812
00814 void GLSimpleMoleculeView::drawAtoms()
00816 {
00817
00818 if(moleculeStyle == None || moleculeStyle == Lines)
00819 return;
00820
00821 for(unsigned int i = 0; i < atoms->count(); i++)
00822 {
00823 glPushMatrix();
00824 qglColor(atoms->color(i));
00825 glTranslatef(atoms->x(i), atoms->y(i), atoms->z(i));
00826 if(moleculeStyle == Tubes)
00827 {
00828 glScalef(moleculeParameters.sizeBonds,
00829 moleculeParameters.sizeBonds,
00830 moleculeParameters.sizeBonds);
00831 }
00832 else if(moleculeStyle == BallAndStick)
00833 {
00834 glScalef(AtomSet::vanderWaals(atoms->atomicNumber(i))/2.0f,
00835 AtomSet::vanderWaals(atoms->atomicNumber(i))/2.0f,
00836 AtomSet::vanderWaals(atoms->atomicNumber(i))/2.0f);
00837 }
00838 else if(moleculeStyle == VanDerWaals)
00839 {
00840 glScalef(AtomSet::vanderWaals(atoms->atomicNumber(i))*1.5f,
00841 AtomSet::vanderWaals(atoms->atomicNumber(i))*1.5f,
00842 AtomSet::vanderWaals(atoms->atomicNumber(i))*1.5f);
00843 }
00844 glLoadName(START_ATOMS+i);
00845 glCallList(atomObject);
00846 glPopMatrix();
00847 }
00848 glLoadName(START_BONDS);
00849 }
00850
00852 void GLSimpleMoleculeView::drawBonds()
00856 {
00857
00858 if(moleculeStyle == None || moleculeStyle == VanDerWaals)
00859 return;
00860
00861 float distance, distanceXY, x1, x2, y1, y2, z1, z2, phi, theta;
00862 vector<unsigned int>* firstAtom;
00863 vector<unsigned int>* secondAtom;
00864 atoms->bonds(firstAtom, secondAtom);
00865
00866 if(moleculeStyle == Lines)
00867 {
00868 glLineWidth(moleculeParameters.sizeLines);
00869 glDisable(GL_LIGHTING);
00870 glBegin(GL_LINES);
00871 for(unsigned int i = 0; i < firstAtom->size(); i++)
00872 {
00873 const unsigned int atom1 = firstAtom->operator[](i);
00874 const unsigned int atom2 = secondAtom->operator[](i);
00875 if(atoms->color(atom1) == atoms->color(atom2))
00876 {
00878 qglColor(atoms->color(atom1));
00879 glVertex3d(atoms->x(atom1), atoms->y(atom1), atoms->z(atom1));
00880 glVertex3d(atoms->x(atom2), atoms->y(atom2), atoms->z(atom2));
00881 }
00882 else
00883 {
00885 const double midX = (atoms->x(atom1) + atoms->x(atom2))/2.0;
00886 const double midY = (atoms->y(atom1) + atoms->y(atom2))/2.0;
00887 const double midZ = (atoms->z(atom1) + atoms->z(atom2))/2.0;
00888 qglColor(atoms->color(atom1));
00889 glVertex3d(atoms->x(atom1), atoms->y(atom1), atoms->z(atom1));
00890 glVertex3d(midX, midY, midZ);
00891
00892 qglColor(atoms->color(atom2));
00893 glVertex3d(midX, midY, midZ);
00894 glVertex3d(atoms->x(atom2), atoms->y(atom2), atoms->z(atom2));
00895 }
00896 }
00897 glEnd();
00898 glEnable(GL_LIGHTING);
00899 return;
00900 }
00901
00904 for(unsigned int i = 0; i < firstAtom->size(); i++)
00905 {
00907 const unsigned int atom1 = firstAtom->operator[](i);
00908 const unsigned int atom2 = secondAtom->operator[](i);
00909
00910 x1 = static_cast<float>(atoms->x(atom1));
00911 x2 = static_cast<float>(atoms->x(atom2));
00912 y1 = static_cast<float>(atoms->y(atom1));
00913 y2 = static_cast<float>(atoms->y(atom2));
00914 z1 = static_cast<float>(atoms->z(atom1));
00915 z2 = static_cast<float>(atoms->z(atom2));
00916 distanceXY = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
00917 distance = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2));
00918 if(distance < 0.01f)
00919 continue;
00920
00921 glPushMatrix();
00922
00924 glTranslatef(x1, y1, z1);
00925
00928 phi = acos((z2 - z1)/distance);
00930 if(distanceXY <= 0.0f)
00931 theta = 0.0f;
00932 else
00933 {
00934 theta = acos((x2 - x1)/distanceXY);
00935 if(y2 < y1)
00936 theta = 2.0f*Point3D<float>::PI - theta;
00937 }
00939 phi *= Point3D<float>::RADTODEG;
00940 theta *= Point3D<float>::RADTODEG;
00941 glRotatef(theta, 0.0f, 0.0f, 1.0f);
00942 glRotatef(phi, 0.0f, 1.0f, 0.0f);
00943
00945 float scaleFactor = 1.0f;
00946 if(atoms->color(atom1) != atoms->color(atom2))
00947 scaleFactor = 2.0f;
00948 glScalef(moleculeParameters.sizeBonds, moleculeParameters.sizeBonds, distance/(scaleFactor*cylinderHeight));
00949
00950 if(atoms->color(atom1) == atoms->color(atom2))
00951 {
00953 qglColor(atoms->color(atom1));
00954 glCallList(bondObject);
00955 }
00956 else
00957 {
00960 qglColor(atoms->color(atom1));
00961 glCallList(bondObject);
00963 qglColor(atoms->color(atom2));
00964 glTranslatef(0.0f, 0.0f, cylinderHeight);
00965 glCallList(bondObject);
00966 }
00967 glPopMatrix();
00968 }
00969 }
00970
00972 void GLSimpleMoleculeView::drawLabels()
00974 {
00975
00976 if(!(showElements || showNumbers || chargeType != AtomSet::None))
00977 return;
00978
00979
00980 Vector3D<float> axis;
00981 float angle;
00982 orientationQuaternion->getAxisAngle(axis, angle);
00983
00984
00985 glDisable(GL_LIGHTING);
00986 qglColor(moleculeParameters.colorLabels);
00987
00988
00989 for(unsigned int i = 0; i < atoms->count(); i++)
00990 {
00991 glPushMatrix();
00992 glTranslated(atoms->x(i), atoms->y(i), atoms->z(i));
00993 glRotatef(-angle, axis.x(), axis.y(), axis.z());
00994 QString label;
00995 if(showElements)
00996 label = AtomSet::numToAtom(atoms->atomicNumber(i)).stripWhiteSpace();
00997 if(showNumbers)
00998 label += QString::number(i + 1);
00999 if(chargeType != AtomSet::None)
01000 {
01001 if(showElements || showNumbers)
01002 label += "(";
01003
01004 if(chargeType == AtomSet::Mulliken)
01005 label += QString::number(atoms->charge(AtomSet::Mulliken, i),'f',3);
01006 else
01007 label += QString::number(atoms->charge(AtomSet::Stockholder, i),'f',3);
01008
01009 if(showElements || showNumbers)
01010 label += ")";
01011 }
01012 renderText(0.0, 0.0, AtomSet::vanderWaals(atoms->atomicNumber(i))/2.0 + 0.05, label, labelFont);
01013 glPopMatrix();
01014 }
01015
01016
01017 glEnable(GL_LIGHTING);
01018 }
01019
01021 void GLSimpleMoleculeView::drawForces()
01025 {
01026
01027 if(forcesStyle == None || !atoms->hasForces())
01028 return;
01029
01030
01031
01032 const float scaleFactor = 0.1f/0.0009f;
01033
01034 const GLfloat opacity = moleculeParameters.opacityForces/100.0f;
01035 if(moleculeParameters.forcesOneColor)
01036 {
01037
01038 const GLfloat red = QColor(moleculeParameters.colorForces).red()/255.0f;
01039 const GLfloat green = QColor(moleculeParameters.colorForces).green()/255.0f;
01040 const GLfloat blue = QColor(moleculeParameters.colorForces).blue()/255.0f;
01041 glColor4f(red, green, blue, opacity);
01042 }
01043
01044 float x1, y1, z1, x2, y2, z2, distance, distanceXY, phi, theta;
01045 for(unsigned int i = 0; i < atoms->count(); i++)
01046 {
01047 x1 = static_cast<float>(atoms->x(i));
01048 y1 = static_cast<float>(atoms->y(i));
01049 z1 = static_cast<float>(atoms->z(i));
01050 x2 = static_cast<float>(atoms->dx(i));
01051 y2 = static_cast<float>(atoms->dy(i));
01052 z2 = static_cast<float>(atoms->dz(i));
01053 distanceXY = sqrt(x2*x2 + y2*y2);
01054 distance = sqrt(x2*x2 + y2*y2 + z2*z2);
01055 if(distance < 0.1f/scaleFactor)
01056 continue;
01057
01058 glPushMatrix();
01059
01061 glTranslatef(x1, y1, z1);
01064 phi = acos(z2/distance);
01066 if(distanceXY <= 0.01f)
01067 theta = 0.0f;
01068 else
01069 {
01070 theta = acos(x2/distanceXY);
01071 if(y2 < 0.0f)
01072 theta = 2.0f*Point3D<float>::PI - theta;
01073 }
01075 phi *= Point3D<float>::RADTODEG;
01076 theta *= Point3D<float>::RADTODEG;
01077 glRotatef(theta, 0.0f, 0.0f, 1.0f);
01078 glRotatef(phi, 0.0f, 1.0f, 0.0f);
01080 if(forcesStyle == Lines)
01081 glScalef(1.0f, 1.0f, scaleFactor*distance/(2.0f*cylinderHeight));
01082 else
01083 glScalef(moleculeParameters.sizeForces, moleculeParameters.sizeForces, scaleFactor*distance/(2.0f*cylinderHeight));
01084
01085 if(!moleculeParameters.forcesOneColor)
01086 {
01087 const GLfloat red = atoms->color(i).red()/255.0f;
01088 const GLfloat green = atoms->color(i).green()/255.0f;
01089 const GLfloat blue = atoms->color(i).blue()/255.0f;
01090 glColor4f(red, green, blue, opacity);
01091 }
01092
01093
01094 if(forcesStyle == Lines)
01095 glCallList(forceObjectLines);
01096 else
01097 glCallList(forceObjectTubes);
01098
01099 glPopMatrix();
01100 }
01101 }
01102
01104 void GLSimpleMoleculeView::drawICValue()
01107 {
01108
01110 glDisable(GL_LIGHTING);
01111 qglColor(moleculeParameters.colorICs);
01112
01113 std::list<unsigned int>::iterator it = selectionList.begin();
01114 switch(selectionList.size())
01115 {
01116 case 2:
01117 {
01118
01119 unsigned int atom1 = *it++;
01120 unsigned int atom2 = *it;
01121 float x1 = static_cast<float>(atoms->x(atom1));
01122 float x2 = static_cast<float>(atoms->x(atom2));
01123 float y1 = static_cast<float>(atoms->y(atom1));
01124 float y2 = static_cast<float>(atoms->y(atom2));
01125 float z1 = static_cast<float>(atoms->z(atom1));
01126 float z2 = static_cast<float>(atoms->z(atom2));
01127
01128 float distance = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2));
01129
01131
01132
01133
01134
01135
01136
01137
01139
01140 GLdouble modelview[16];
01141 GLdouble projection[16];
01142 GLint viewport[4];
01143 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
01144 glGetDoublev(GL_PROJECTION_MATRIX, projection);
01145 glGetIntegerv(GL_VIEWPORT, viewport);
01146 GLdouble xwin, ywin, zwin;
01147 GLint result = gluProject((atoms->x(atom1)+atoms->x(atom2))/2.0, (atoms->y(atom1)+atoms->y(atom2))/2.0, (atoms->z(atom1)+atoms->z(atom2))/2.0, modelview, projection, viewport, &xwin, &ywin, &zwin);
01148 if(result == GL_FALSE)
01149 break;
01150 renderText(static_cast<int>(xwin), height() - static_cast<int>(ywin), QString::number(distance, 'f', 4), labelFont);
01151 break;
01152 }
01153 case 3:
01154 {
01155
01156 unsigned int atom1 = *it++;
01157 unsigned int atom2 = *it++;
01158 unsigned int atom3 = *it;
01159 float x1 = static_cast<float>(atoms->x(atom1));
01160 float x2 = static_cast<float>(atoms->x(atom2));
01161 float x3 = static_cast<float>(atoms->x(atom3));
01162 float y1 = static_cast<float>(atoms->y(atom1));
01163 float y2 = static_cast<float>(atoms->y(atom2));
01164 float y3 = static_cast<float>(atoms->y(atom3));
01165 float z1 = static_cast<float>(atoms->z(atom1));
01166 float z2 = static_cast<float>(atoms->z(atom2));
01167 float z3 = static_cast<float>(atoms->z(atom3));
01168
01169 Vector3D<float> bond1(x2, y2, z2, x1, y1, z1);
01170 Vector3D<float> bond2(x2, y2, z2, x3, y3, z3);
01171 float localAngle = bond1.angle(bond2);
01172
01174
01175
01176
01177
01178
01179
01180
01182 GLdouble modelview[16];
01183 GLdouble projection[16];
01184 GLint viewport[4];
01185 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
01186 glGetDoublev(GL_PROJECTION_MATRIX, projection);
01187 glGetIntegerv(GL_VIEWPORT, viewport);
01188 GLdouble xwin, ywin, zwin;
01189 GLint result = gluProject((atoms->x(atom1)+atoms->x(atom3))/2.0, (atoms->y(atom1)+atoms->y(atom3))/2.0, (atoms->z(atom1)+atoms->z(atom3))/2.0, modelview, projection, viewport, &xwin, &ywin, &zwin);
01190 if(result == GL_FALSE)
01191 break;
01192 renderText(static_cast<int>(xwin), height() - static_cast<int>(ywin), QString::number(localAngle, 'f', 2), labelFont);
01193 break;
01194 }
01195 case 4:
01196 {
01197
01198 unsigned int atom1 = *it++;
01199 unsigned int atom2 = *it++;
01200 unsigned int atom3 = *it++;
01201 unsigned int atom4 = *it;
01202 float x1 = static_cast<float>(atoms->x(atom1));
01203 float x2 = static_cast<float>(atoms->x(atom2));
01204 float x3 = static_cast<float>(atoms->x(atom3));
01205 float x4 = static_cast<float>(atoms->x(atom4));
01206 float y1 = static_cast<float>(atoms->y(atom1));
01207 float y2 = static_cast<float>(atoms->y(atom2));
01208 float y3 = static_cast<float>(atoms->y(atom3));
01209 float y4 = static_cast<float>(atoms->y(atom4));
01210 float z1 = static_cast<float>(atoms->z(atom1));
01211 float z2 = static_cast<float>(atoms->z(atom2));
01212 float z3 = static_cast<float>(atoms->z(atom3));
01213 float z4 = static_cast<float>(atoms->z(atom4));
01214
01215 Vector3D<float> bond1(x2, y2, z2, x1, y1, z1);
01216 Vector3D<float> bond2(x3, y3, z3, x4, y4, z4);
01217 Vector3D<float> centralbond(x2, y2, z2, x3, y3, z3);
01218 float localAngle = bond1.torsion(bond2, centralbond);
01219
01221
01222
01223
01224
01225
01226
01227
01229 GLdouble modelview[16];
01230 GLdouble projection[16];
01231 GLint viewport[4];
01232 glGetDoublev(GL_MODELVIEW_MATRIX, modelview);
01233 glGetDoublev(GL_PROJECTION_MATRIX, projection);
01234 glGetIntegerv(GL_VIEWPORT, viewport);
01235 GLdouble xwin, ywin, zwin;
01236 GLint result = gluProject((atoms->x(atom2)+atoms->x(atom3))/2.0, (atoms->y(atom2)+atoms->y(atom3))/2.0, (atoms->z(atom2)+atoms->z(atom3))/2.0, modelview, projection, viewport, &xwin, &ywin, &zwin);
01237 if(result == GL_FALSE)
01238 break;
01239 renderText(static_cast<int>(xwin), height() - static_cast<int>(ywin), QString::number(localAngle, 'f', 2), labelFont);
01240 break;
01241 }
01242 }
01243 glEnable(GL_LIGHTING);
01244 }
01245
01247 void GLSimpleMoleculeView::drawSelections()
01249 {
01250
01251 if(moleculeStyle == None || moleculeStyle == Lines)
01252 {
01253 qglColor(moleculeParameters.colorSelections);
01254 glDisable(GL_LIGHTING);
01256 glPointSize(selectionPointSize);
01257 glBegin(GL_POINTS);
01258 std::list<unsigned int>::iterator it = selectionList.begin();
01259 while(it != selectionList.end())
01260 {
01261 glVertex3d(atoms->x(*it), atoms->y(*it), atoms->z(*it));
01262 it++;
01263 }
01264 glEnd();
01266 if(selectionList.size() >= 2 && selectionList.size() <= 4)
01267 {
01268 glLineWidth(selectionLineWidth);
01270 std::list<unsigned int>::iterator it = selectionList.begin();
01271 glBegin(GL_LINE_STRIP);
01272 while(it != selectionList.end())
01273 {
01274 glVertex3d(atoms->x(*it), atoms->y(*it), atoms->z(*it));
01275 it++;
01276 }
01277 glEnd();
01278 glLineWidth(moleculeParameters.sizeLines);
01279 }
01280 glEnable(GL_LIGHTING);
01281 return;
01282 }
01283
01284 const GLfloat red = QColor(moleculeParameters.colorSelections).red()/255.0f;
01285 const GLfloat green = QColor(moleculeParameters.colorSelections).green()/255.0f;
01286 const GLfloat blue = QColor(moleculeParameters.colorSelections).blue()/255.0f;
01287 const GLfloat opacity = moleculeParameters.opacitySelections/100.0f;
01288 glColor4f(red, green, blue, opacity);
01289
01291 std::list<unsigned int>::iterator it = selectionList.begin();
01292 while(it != selectionList.end())
01293 {
01294
01295 glPushMatrix();
01296 glTranslatef(atoms->x(*it), atoms->y(*it), atoms->z(*it));
01297 if(moleculeStyle == VanDerWaals)
01298 {
01299 glScalef(AtomSet::vanderWaals(atoms->atomicNumber(*it))*1.5f * 1.1f,
01300 AtomSet::vanderWaals(atoms->atomicNumber(*it))*1.5f * 1.1f,
01301 AtomSet::vanderWaals(atoms->atomicNumber(*it))*1.5f * 1.1f);
01302 }
01303 else if(moleculeStyle == Tubes)
01304 {
01305 glScalef(moleculeParameters.sizeBonds * 1.6f,
01306 moleculeParameters.sizeBonds * 1.6f,
01307 moleculeParameters.sizeBonds * 1.6f);
01308 }
01309 else
01310 {
01311 glScalef(AtomSet::vanderWaals(atoms->atomicNumber(*it))/2.0f * 1.1f,
01312 AtomSet::vanderWaals(atoms->atomicNumber(*it))/2.0f * 1.1f,
01313 AtomSet::vanderWaals(atoms->atomicNumber(*it))/2.0f * 1.1f);
01314 }
01315
01316 glLoadName(START_SELECTEDATOMS);
01317 glCallList(atomObject);
01318 glPopMatrix();
01319 it++;
01320 }
01321
01323 if(selectionList.size() >= 2 && selectionList.size() <= 4)
01324 {
01325 float x1, y1, z1, x2, y2, z2, distance, distanceXY, phi, theta;
01326
01327 std::list<unsigned int>::iterator it = selectionList.begin();
01328 unsigned int atom1 = *it++;
01329 unsigned int atom2 = *it;
01330 while(it != selectionList.end())
01331 {
01332 x1 = static_cast<float>(atoms->x(atom1));
01333 x2 = static_cast<float>(atoms->x(atom2));
01334 y1 = static_cast<float>(atoms->y(atom1));
01335 y2 = static_cast<float>(atoms->y(atom2));
01336 z1 = static_cast<float>(atoms->z(atom1));
01337 z2 = static_cast<float>(atoms->z(atom2));
01338 distanceXY = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2));
01339 distance = sqrt((x1 - x2)*(x1 - x2) + (y1 - y2)*(y1 - y2) + (z1 - z2)*(z1 - z2));
01340 if(distance < 0.01f)
01341 continue;
01342
01343 glPushMatrix();
01345 glTranslatef(x1, y1, z1);
01347 phi = acos((z2 - z1)/distance);
01348 if(distanceXY <= 0.0f)
01349 theta = 0.0f;
01350 else
01351 {
01352 theta = acos((x2 - x1)/distanceXY);
01353 if(y2 < y1)
01354 theta = 2.0f*Point3D<float>::PI - theta;
01355 }
01356 phi *= Point3D<float>::RADTODEG;
01357 theta *= Point3D<float>::RADTODEG;
01358 glRotatef(theta, 0.0f, 0.0f, 1.0f);
01359 glRotatef(phi, 0.0f, 1.0f, 0.0f);
01361 glScalef(moleculeParameters.sizeBonds * 1.1f, moleculeParameters.sizeBonds * 1.1f, distance/cylinderHeight);
01362 glLoadName(START_SELECTEDBONDS);
01363 glCallList(bondObject);
01364
01365 glPopMatrix();
01366 atom1 = atom2;
01367 atom2 = *(++it);
01368 }
01369 }
01370 }
01371
01375
01376 const float GLSimpleMoleculeView::cylinderHeight = 10.0f;
01377 GLMoleculeParameters GLSimpleMoleculeView::moleculeParameters = {5, 1.0f, 0.2f, 0.2f, BallAndStick, Tubes, 1000, false, true,
01378 0x00FF00, 0x00FFFF, 0xFFFF00, 50, 0xFFFF0, false, 100};
01379