/* * Project: MoleCuilder * Description: creates and alters molecular systems * Copyright (C) 2010 University of Bonn. All rights reserved. * Please see the LICENSE file or "Copyright notice" in builder.cpp for details. */ /* * GLMoleculeView.cpp * * Created on: Aug 1, 2010 * Author: heber */ // include config.h #ifdef HAVE_CONFIG_H #include #endif #include "GLMoleculeView.hpp" #include #include #include #include "ui_dialoglight.h" #include "CodePatterns/MemDebug.hpp" #include #include #include "LinearAlgebra/Line.hpp" #include "atom.hpp" #include "Bond/bond.hpp" #include "element.hpp" #include "molecule.hpp" #include "periodentafel.hpp" #include "World.hpp" #if defined(Q_CC_MSVC) #pragma warning(disable:4305) // init: truncation from const double to float #endif GLMoleculeView::GLMoleculeView(QWidget *parent) : QGLWidget(parent), Observer("GLMoleculeView"), X(Vector(1,0,0)), Y(Vector(0,1,0)), Z(Vector(0,0,1)) { xRot = yRot = zRot = 0.0; // default object rotation scale = 5.; // default object scale object = 0; LightPosition[0] = 0.0f; LightPosition[1] = 2.0f; LightPosition[2] = 2.0f; LightPosition[3] = 0.0f; LightDiffuse[0] = 0.5f; LightDiffuse[1] = 0.5f; LightDiffuse[2] = 0.5f; LightDiffuse[3] = 0.0f; LightAmbient[0] = 0.0f; LightAmbient[1] = 0.0f; LightAmbient[2] = 0.0f; LightAmbient[3] = 0.0f; SelectionColor[0] = 0; SelectionColor[1] = 128; SelectionColor[2] = 128; MultiViewEnabled = true; isSignaller = false; World::getInstance().signOn(this); } /** Destructor of GLMoleculeView. * Free's the CallList. */ GLMoleculeView::~GLMoleculeView() { makeCurrent(); glDeleteLists( object, 1 ); World::getInstance().signOff(this); } /** Paints the conents of the OpenGL window. * Clears the GL buffers, enables lighting and depth. * Window is either quartered (if GLMoleculeView::MultiViewEnabled) and xy, xz, yz planar views * are added. Uses the CallList, constructed during InitializeGL(). */ void GLMoleculeView::paintGL() { Vector spot; glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glShadeModel(GL_SMOOTH); // Enable Smooth Shading glEnable(GL_LIGHTING); // Enable Light One glEnable(GL_DEPTH_TEST); // Enables Depth Testing glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations // 3d viewport if (MultiViewEnabled) glViewport( 0, 0, (GLint)width/2, (GLint)height/2 ); else glViewport( 0, 0, (GLint)width, (GLint)height ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glFrustum( -1.0, 1.0, -1.0, 1.0, 1.0, 50.0 ); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // calculate point of view and direction glTranslated(position[0],position[1],position[2]); glTranslated(0.0, 0.0, -scale); glRotated(xRot, 1.0, 0.0, 0.0); glRotated(yRot, 0.0, 1.0, 0.0); glRotated(zRot, 0.0, 0.0, 1.0); // render scene glCallList(object); // enable light glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light glEnable(GL_LIGHT1); // Enable Light One if (MultiViewEnabled) { // xy view port glViewport( (GLint)width/2, 0, (GLint)width/2, (GLint)height/2 ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glScalef(1./scale, 1./scale,1./scale); glOrtho(0, width/2, 0, height/2, 0,0); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // calculate point of view and direction view = position; spot = Vector(0.,0.,scale); top = Vector(0.,1.,0.); gluLookAt( spot[0], spot[1], spot[2], view[0], view[1], view[2], top[0], top[1], top[2]); // enable light glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light glEnable(GL_LIGHT1); // Enable Light One // render scene glCallList(object); // xz viewport glViewport( 0, (GLint)height/2, (GLint)width/2, (GLint)height/2 ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glScalef(1./scale, 1./scale,1./scale); glOrtho(0, width/2, 0, height/2, 0,0); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // calculate point of view and direction view = position; spot = Vector(0.,scale,0.); top = Vector(1.,0.,0.); gluLookAt( spot[0], spot[1], spot[2], view[0], view[1], view[2], top[0], top[1], top[2]); // enable light glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light glEnable(GL_LIGHT1); // Enable Light One // render scene glCallList(object); //yz viewport glViewport( (GLint)width/2, (GLint)height/2, (GLint)width/2, (GLint)height/2 ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); glScalef(1./scale, 1./scale,1./scale); glOrtho(0, width/2, 0, height/2, 0,0); glMatrixMode( GL_MODELVIEW ); glLoadIdentity(); // calculate point of view and direction view= position; spot = Vector(scale,0.,0.); top = Vector(0.,1.,0.); gluLookAt( spot[0], spot[1], spot[2], view[0], view[1], view[2], top[0], top[1], top[2]); // enable light glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light glEnable(GL_LIGHT1); // Enable Light One // render scene glCallList(object); } //CoordinatesBar->setText( QString ("X: %1, Y: %2, Z: %3").arg(position[0]).arg(position[1]).arg(position[2]) ); } //void polarView{GLdouble distance, GLdouble twist, // GLdouble elevation, GLdouble azimuth) //{ // glTranslated(0.0, 0.0, -distance); // glRotated(-twist, 0.0, 0.0, 1.0); // glRotated(-elevation, 1.0, 0.0, 0.0); // glRotated(azimuth, 0.0, 0.0, 1.0); //} /** Make a sphere. * \param x position * \param radius radius * \param color[3] color rgb values */ void GLMoleculeView::makeSphere(const Vector &x, double radius, const unsigned char color[3]) { float blueMaterial[] = { 255./(float)color[0], 255./(float)color[1], 255./(float)color[2], 1 }; // need to recast from [0,255] with integers into [0,1] with floats GLUquadricObj* q = gluNewQuadric (); gluQuadricOrientation(q, GLU_OUTSIDE); std::cout << "Setting sphere at " << x << " with color r" << (int)color[0] << ",g" << (int)color[1] << ",b" << (int)color[2] << "." << endl; glPushMatrix(); glTranslatef( x[0], x[1], x[2]); // glRotatef( xRot, 1.0, 0.0, 0.0); // glRotatef( yRot, 0.0, 1.0, 0.0); // glRotatef( zRot, 0.0, 0.0, 1.0); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial); gluSphere (q, (GLdouble)radius, 10, 10); glPopMatrix(); } /** Make a cylinder. * \param x origin * \param y direction * \param radius thickness * \param height length * \color[3] color rgb values */ void GLMoleculeView::makeCylinder(const Vector &x, const Vector &y, double radius, double height, const unsigned char color[3]) { float blueMaterial[] = { 255./(float)color[0], 255./(float)color[1], 255./(float)color[2], 1 }; GLUquadricObj* q = gluNewQuadric (); gluQuadricOrientation(q, GLU_OUTSIDE); Vector a,b; Vector OtherAxis; double alpha; a = x - y; // construct rotation axis b = a; b.VectorProduct(Z); Line axis(zeroVec, b); // calculate rotation angle alpha = a.Angle(Z); // construct other axis to check right-hand rule OtherAxis = b; OtherAxis.VectorProduct(Z); // assure right-hand rule for the rotation if (a.ScalarProduct(OtherAxis) < MYEPSILON) alpha = M_PI-alpha; // check Vector a_rotated = axis.rotateVector(a, alpha); std::cout << "Setting cylinder from "// << x << " to " << y << a << " to " << a_rotated << " around " << b << " by " << alpha/M_PI*180. << ", respectively, " << " with color r" << (int)color[0] << ",g" << (int)color[1] << ",b" << (int)color[2] << "." << endl; glPushMatrix(); glTranslatef( x[0], x[1], x[2]); glRotatef( alpha/M_PI*180., b[0], b[1], b[2]); glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial); gluCylinder (q, (GLdouble)radius, (GLdouble)radius, (GLdouble)height, 10, 10); glPopMatrix(); } /** Defines the display CallList. * Goes through all molecules and their atoms and adds spheres for atoms and cylinders * for bonds. Heeds GLMoleculeView::SelectedAtom and GLMoleculeView::SelectedMolecule. */ void GLMoleculeView::initializeGL() { double x[3] = {-1, 0, -10}; unsigned char white[3] = {255,255,255}; Vector Position, OtherPosition; QSize window = size(); width = window.width(); height = window.height(); std::cout << "Setting width to " << width << " and height to " << height << std::endl; GLfloat shininess[] = { 0.0 }; GLfloat specular[] = { 0, 0, 0, 1 }; glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Let OpenGL clear to black object = glGenLists(1); glNewList( object, GL_COMPILE ); glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular); glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess); const std::vector &molecules = World::getInstance().getAllMolecules(); if (molecules.size() > 0) { for (std::vector::const_iterator Runner = molecules.begin(); Runner != molecules.end(); Runner++) { for (molecule::const_iterator atomiter = (*Runner)->begin(); atomiter != (*Runner)->end(); ++atomiter) { // create atom const element *ptr = (*atomiter)->getType(); boost::shared_ptr MolCenter((*Runner)->DetermineCenterOfGravity()); Position = (*atomiter)->getPosition() - *MolCenter; const unsigned char* color = NULL; if ((World::getInstance().isSelected(*atomiter)) || (World::getInstance().isSelected((*Runner)))) color = SelectionColor; else color = ptr->getColor(); makeSphere(Position, ptr->getVanDerWaalsRadius()*0.25, color); // create bonds const BondList &bonds = (*atomiter)->getListOfBonds(); for (BondList::const_iterator bonditer = bonds.begin(); bonditer != bonds.end(); ++bonditer) { if ((*bonditer)->leftatom->getId() == (*atomiter)->getId()) { Position = (*bonditer)->leftatom->getPosition() - *MolCenter; OtherPosition = (*bonditer)->rightatom->getPosition() - *MolCenter; const double distance = sqrt(Position.DistanceSquared(OtherPosition))/2.; const unsigned char *color1 = (*bonditer)->leftatom->getType()->getColor(); const unsigned char *color2 = (*bonditer)->rightatom->getType()->getColor(); makeCylinder(Position, OtherPosition, 0.1, distance, color1); makeCylinder(OtherPosition, Position, 0.1, distance, color2); } } } } } else { makeSphere( x,1, white); } glEndList(); } /* ================================== SLOTS ============================== */ /** Initializes some public variables. * \param *ptr pointer to QLabel statusbar */ void GLMoleculeView::init(QLabel *ptr) { StatusBar = ptr; } /** Initializes the viewport statusbar. * \param *ptr pointer to QLabel for showing view pointcoordinates. */ void GLMoleculeView::initCoordinates(QLabel *ptr) { CoordinatesBar = ptr; } /** Slot to be called when to initialize GLMoleculeView::MolData. */ void GLMoleculeView::createView( ) { initializeGL(); updateGL(); } /** Slot of window is resized. * Copies new width and height to GLMoleculeView::width and GLMoleculeView::height and calls updateGL(). * \param w new width of window * \param h new height of window */ void GLMoleculeView::resizeGL( int w, int h ) { width = w; height = h; updateGL(); } /** Sets x rotation angle. * sets GLMoleculeView::xRot and calls updateGL(). * \param degrees new rotation angle in degrees */ void GLMoleculeView::setXRotation( int degrees ) { xRot = (GLfloat)(degrees % 360); updateGL(); } /** Sets y rotation angle. * sets GLMoleculeView::yRot and calls updateGL(). * \param degrees new rotation angle in degrees */ void GLMoleculeView::setYRotation( int degrees ) { yRot = (GLfloat)(degrees % 360); updateGL(); } /** Sets z rotation angle. * sets GLMoleculeView::zRot and calls updateGL(). * \param degrees new rotation angle in degrees */ void GLMoleculeView::setZRotation( int degrees ) { zRot = (GLfloat)(degrees % 360); updateGL(); } /** Sets the scale of the scene. * sets GLMoleculeView::scale and calls updateGL(). * \param distance distance divided by 100 is the new scale */ void GLMoleculeView::setScale( int distance ) { scale = (GLfloat)(distance / 100.); updateGL(); } /** Update the ambient light. * \param light[4] light strength per axis and position (w) */ void GLMoleculeView::setLightAmbient( int *light ) { for(int i=0;i<4;i++) LightAmbient[i] = light[i]; updateGL(); } /** Update the diffuse light. * \param light[4] light strength per axis and position (w) */ void GLMoleculeView::setLightDiffuse( int *light ) { for(int i=0;i<4;i++) LightDiffuse[i] = light[i]; updateGL(); } /** Update the position of light. * \param light[4] light strength per axis and position (w) */ void GLMoleculeView::setLightPosition( int *light ) { for(int i=0;i<4;i++) LightPosition[i] = light[i]; updateGL(); } /** Toggles the boolean GLMoleculeView::MultiViewEnabled. * Flips the boolean and calls updateGL(). */ void GLMoleculeView::toggleMultiViewEnabled ( ) { MultiViewEnabled = !MultiViewEnabled; cout << "Setting MultiView to " << MultiViewEnabled << "." << endl; updateGL(); } /** Launch a dialog to configure the lights. */ void GLMoleculeView::createDialogLight() { // Ui_DialogLight *Lights = new Ui_DialogLight(); // if (Lights == NULL) // return; // // Set up the dynamic dialog here // QLineEdit *Field = NULL; // Field = Lights->findChild("LightPositionX"); // if (Field) Field->setText( QString("%1").arg(LightPosition[0]) ); // Field = Lights->findChild("LightPositionY"); // if (Field) Field->setText( QString("%1").arg(LightPosition[1]) ); // Field = Lights->findChild("LightPositionZ"); // if (Field) Field->setText( QString("%1").arg(LightPosition[2]) ); // Field = Lights->findChild("LightPositionW"); // if (Field) Field->setText( QString("%1").arg(LightPosition[3]) ); // // Field = Lights->findChild("LightDiffuseX"); // if (Field) Field->setText( QString("%1").arg(LightDiffuse[0]) ); // Field = Lights->findChild("LightDiffuseY"); // if (Field) Field->setText( QString("%1").arg(LightDiffuse[1]) ); // Field = Lights->findChild("LightDiffuseZ"); // if (Field) Field->setText( QString("%1").arg(LightDiffuse[2]) ); // Field = Lights->findChild("LightDiffuseW"); // if (Field) Field->setText( QString("%1").arg(LightDiffuse[3]) ); // // Field = Lights->findChild("LightAmbientX"); // if (Field) Field->setText( QString("%1").arg(LightAmbient[0]) ); // Field = Lights->findChild("LightAmbientY"); // if (Field) Field->setText( QString("%1").arg(LightAmbient[1]) ); // Field = Lights->findChild("LightAmbientZ"); // if (Field) Field->setText( QString("%1").arg(LightAmbient[2]) ); // Field = Lights->findChild("LightAmbientW"); // if (Field) Field->setText( QString("%1").arg(LightAmbient[3]) ); // // if ( Lights->exec() ) { // //cout << "User accepted.\n"; // // The user accepted, act accordingly // Field = Lights->findChild("LightPositionX"); // if (Field) LightPosition[0] = Field->text().toDouble(); // Field = Lights->findChild("LightPositionY"); // if (Field) LightPosition[1] = Field->text().toDouble(); // Field = Lights->findChild("LightPositionZ"); // if (Field) LightPosition[2] = Field->text().toDouble(); // Field = Lights->findChild("LightPositionW"); // if (Field) LightPosition[3] = Field->text().toDouble(); // // Field = Lights->findChild("LightDiffuseX"); // if (Field) LightDiffuse[0] = Field->text().toDouble(); // Field = Lights->findChild("LightDiffuseY"); // if (Field) LightDiffuse[1] = Field->text().toDouble(); // Field = Lights->findChild("LightDiffuseZ"); // if (Field) LightDiffuse[2] = Field->text().toDouble(); // Field = Lights->findChild("LightDiffuseW"); // if (Field) LightDiffuse[3] = Field->text().toDouble(); // // Field = Lights->findChild("LightAmbientX"); // if (Field) LightAmbient[0] = Field->text().toDouble(); // Field = Lights->findChild("LightAmbientY"); // if (Field) LightAmbient[1] = Field->text().toDouble(); // Field = Lights->findChild("LightAmbientZ"); // if (Field) LightAmbient[2] = Field->text().toDouble(); // Field = Lights->findChild("LightAmbientW"); // if (Field) LightAmbient[3] = Field->text().toDouble(); // updateGL(); // } else { // //cout << "User reclined.\n"; // } // delete(Lights); } /** Slot for event of pressed mouse button. * Switch discerns between buttons and stores position of event in GLMoleculeView::LeftButtonPos, * GLMoleculeView::MiddleButtonPos or GLMoleculeView::RightButtonPos. * \param *event structure containing information of the event */ void GLMoleculeView::mousePressEvent(QMouseEvent *event) { std::cout << "MousePressEvent." << endl; QPoint *pos = NULL; switch (event->button()) { // get the right array case Qt::LeftButton: pos = &LeftButtonPos; std::cout << "Left Button" << endl; break; case Qt::MidButton: pos = &MiddleButtonPos; std::cout << "Middle Button" << endl; break; case Qt::RightButton: pos = &RightButtonPos; std::cout << "Right Button" << endl; break; default: break; } if (pos) { // store the position pos->setX(event->pos().x()); pos->setY(event->pos().y()); std::cout << "Stored src position is (" << pos->x() << "," << pos->y() << ")." << endl; } else { std::cout << "pos is NULL." << endl; } } /** Slot for event of pressed mouse button. * Switch discerns between buttons: * -# Left Button: Rotates the view of the GLMoleculeView, relative to GLMoleculeView::LeftButtonPos. * -# Middle Button: nothing * -# Right Button: Shifts the selected molecule or atom, relative to GLMoleculeView::RightButtonPos. * \param *event structure containing information of the event */ void GLMoleculeView::mouseReleaseEvent(QMouseEvent *event) { std::cout << "MouseReleaseEvent." << endl; QPoint *srcpos = NULL; QPoint destpos = event->pos(); int Width = (MultiViewEnabled) ? width/2 : width; int Height = (MultiViewEnabled) ? height/2 : height; std::cout << "Received dest position is (" << destpos.x() << "," << destpos.y() << ")." << endl; switch (event->button()) { // get the right array case Qt::LeftButton: // LeftButton rotates the view srcpos = &LeftButtonPos; std::cout << "Left Button" << endl; if (srcpos) { // subtract the position and act std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl; destpos -= *srcpos; std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl; std::cout << "Width and Height are " << Width << "," << Height << "." << endl; int pos = (int)floor((double)srcpos->x()/(double)Width) + ((int)floor((double)srcpos->y()/(double)Height))*2; if ((MultiViewEnabled) && (pos != 2)) { // means four regions, and we are in a shifting one // switch between three regions // decide into which of the four screens the initial click has been made std::cout << "Position is " << pos << "." << endl; switch(pos) { case 0: // lower left = xz position[0] += -destpos.y()/100.; position[2] += destpos.x()/100.; break; case 1: // lower right = yz position[1] += -destpos.y()/100.; position[2] += -destpos.x()/100.; break; case 2: // upper left = projected std::cout << "This is impossible: Shifting in the projected region, we should rotate!." << endl; break; case 3: // upper right = xy position[0] += destpos.x()/100.; position[1] += -destpos.y()/100.; break; default: std::cout << "click was not in any of the four regions." << endl; break; } updateGL(); } else { // we are in rotation region QWidget *Parent = parentWidget(); QSlider *sliderX = Parent->findChild("sliderX"); QSlider *sliderY = Parent->findChild("sliderY"); std::cout << sliderX << " and " << sliderY << endl; if (sliderX) { int xrange = sliderX->maximum() - sliderX->minimum(); double xValue = ((destpos.x() + Width) % Width); xValue *= (double)xrange/(double)Width; xValue += sliderX->value(); int xvalue = (int) xValue % xrange; std::cout << "Setting x to " << xvalue << " within range " << xrange << "." << endl; setXRotation(xvalue); sliderX->setValue(xvalue); } else { std::cout << "sliderX is NULL." << endl; } if (sliderY) { int yrange = sliderY->maximum() - sliderY->minimum(); double yValue = ((destpos.y() + Height) % Height); yValue *= (double)yrange/(double)Height; yValue += sliderY->value(); int yvalue = (int) yValue % yrange; std::cout << "Setting y to " << yvalue << " within range " << yrange << "." << endl; setYRotation(yvalue); sliderY->setValue(yvalue); } else { std::cout << "sliderY is NULL." << endl; } } } else { std::cout << "srcpos is NULL." << endl; } break; case Qt::MidButton: // MiddleButton has no function so far srcpos = &MiddleButtonPos; std::cout << "Middle Button" << endl; if (srcpos) { // subtract the position and act QWidget *Parent = parentWidget(); QSlider *sliderZ = Parent->findChild("sliderZ"); QSlider *sliderScale = Parent->findChild("sliderScale"); std::cout << sliderZ << " and " << sliderScale << endl; std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl; destpos -= *srcpos; std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl; std::cout << "Width and Height are " << Width << "," << Height << "." << endl; if (sliderZ) { int xrange = sliderZ->maximum() - sliderZ->minimum(); double xValue = ((destpos.x() + Width) % Width); xValue *= (double)xrange/(double)Width; xValue += sliderZ->value(); int xvalue = (int) xValue % xrange; std::cout << "Setting x to " << xvalue << " within range " << xrange << "." << endl; setZRotation(xvalue); sliderZ->setValue(xvalue); } else { std::cout << "sliderZ is NULL." << endl; } if (sliderScale) { int yrange = sliderScale->maximum() - sliderScale->minimum(); double yValue = ((destpos.y() + Height) % Height); yValue *= (double)yrange/(double)Height; yValue += sliderScale->value(); int yvalue = (int) yValue % yrange; std::cout << "Setting y to " << yvalue << " within range " << yrange << "." << endl; setScale(yvalue); sliderScale->setValue(yvalue); } else { std::cout << "sliderScale is NULL." << endl; } } else { std::cout << "srcpos is NULL." << endl; } break; break; case Qt::RightButton: // RightButton moves eitstdher the selected molecule or atom srcpos = &RightButtonPos; std::cout << "Right Button" << endl; if (srcpos) { // subtract the position and act std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl; destpos -= *srcpos; std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl; std::cout << "Width and Height are " << Width << "," << Height << "." << endl; if (MultiViewEnabled) { // which vector to change Vector SelectedPosition; const std::vector &SelectedAtoms = World::getInstance().getSelectedAtoms(); const std::vector &SelectedMolecules = World::getInstance().getSelectedMolecules(); if (SelectedMolecules.size()) { if (SelectedAtoms.size()) SelectedPosition = (*SelectedAtoms.begin())->getPosition(); else SelectedPosition = (*(*SelectedMolecules.begin())->begin())->getPosition(); } // decide into which of the four screens the initial click has been made int pos = (int)floor((double)srcpos->x()/(double)Width) + ((int)floor((double)srcpos->y()/(double)Height))*2; if (!SelectedPosition.IsZero()) { std::cout << "Position is " << pos << "." << endl; switch(pos) { case 0: // lower left = xz SelectedPosition[0] += -destpos.y()/100.; SelectedPosition[2] += destpos.x()/100.; break; case 1: // lower right = yz SelectedPosition[1] += -destpos.y()/100.; SelectedPosition[2] += -destpos.x()/100.; break; case 2: // upper left = projected SelectedPosition[0] += destpos.x()/100.; SelectedPosition[1] += destpos.y()/100.; SelectedPosition[2] += destpos.y()/100.; break; case 3: // upper right = xy SelectedPosition[0] += destpos.x()/100.; SelectedPosition[1] += -destpos.y()/100.; break; default: std::cout << "click was not in any of the four regions." << endl; break; } } else { std::cout << "Nothing selected." << endl; } // update Tables if (SelectedMolecules.size()) { isSignaller = true; if (SelectedAtoms.size()) emit notifyAtomChanged( (*SelectedMolecules.begin()), (*SelectedAtoms.begin()), AtomPosition); else emit notifyMoleculeChanged( (*SelectedMolecules.begin()), MoleculePosition ); } // update graphic initializeGL(); updateGL(); } else { cout << "MultiView is not enabled." << endl; } } else { cout << "srcpos is NULL." << endl; } break; default: break; } } /* ======================================== SLOTS ================================ */ /** Hear announcement of selected molecule. * \param *mol pointer to selected molecule */ void GLMoleculeView::hearMoleculeSelected(molecule *mol) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } initializeGL(); updateGL(); }; /** Hear announcement of selected atom. * \param *mol pointer to molecule containing atom * \param *Walker pointer to selected atom */ void GLMoleculeView::hearAtomSelected(molecule *mol, atom *Walker) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } initializeGL(); updateGL(); }; /** Hear announcement of changed molecule. * \param *mol pointer to changed molecule * \param type of change */ void GLMoleculeView::hearMoleculeChanged(molecule *mol, enum ChangesinMolecule type) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } initializeGL(); updateGL(); }; /** Hear announcement of changed atom. * \param *mol pointer to molecule containing atom * \param *Walker pointer to changed atom * \param type type of change */ void GLMoleculeView::hearAtomChanged(molecule *mol, atom *Walker, enum ChangesinAtom type) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } initializeGL(); updateGL(); }; /** Hear announcement of changed element. * \param *Runner pointer to changed element * \param type of change */ void GLMoleculeView::hearElementChanged(element *Runner, enum ChangesinElement type) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } switch(type) { default: case ElementName: case ElementSymbol: case ElementMass: case ElementValence: case ElementZ: break; case ElementCovalent: case ElementVanderWaals: initializeGL(); updateGL(); break; } }; /** Hear announcement of added molecule. * \param *mol pointer to added molecule */ void GLMoleculeView::hearMoleculeAdded(molecule *mol) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } initializeGL(); updateGL(); }; /** Hear announcement of added atom. * \param *mol pointer to molecule containing atom * \param *Walker pointer to added atom */ void GLMoleculeView::hearAtomAdded(molecule *mol, atom *Walker) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } initializeGL(); updateGL(); }; /** Hear announcement of removed molecule. * \param *mol pointer to removed molecule */ void GLMoleculeView::hearMoleculeRemoved(molecule *mol) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } initializeGL(); updateGL(); }; /** Hear announcement of removed atom. * \param *mol pointer to molecule containing atom * \param *Walker pointer to removed atom */ void GLMoleculeView::hearAtomRemoved(molecule *mol, atom *Walker) { if (isSignaller) { // if we emitted the signal, return isSignaller = false; return; } initializeGL(); updateGL(); }; void GLMoleculeView::update(Observable *publisher) { initializeGL(); updateGL(); } /** * This method is called when a special named change * of the Observable occured */ void GLMoleculeView::recieveNotification(Observable *publisher, Notification_ptr notification) { initializeGL(); updateGL(); } /** * This method is called when the observed object is destroyed. */ void GLMoleculeView::subjectKilled(Observable *publisher) { }