source: src/UIElements/Views/Qt4/Qt3D/GLWorldView.cpp@ 026bef

Action_Thermostats Add_AtomRandomPerturbation Add_FitFragmentPartialChargesAction Add_RotateAroundBondAction Add_SelectAtomByNameAction Added_ParseSaveFragmentResults AddingActions_SaveParseParticleParameters Adding_Graph_to_ChangeBondActions Adding_MD_integration_tests Adding_ParticleName_to_Atom Adding_StructOpt_integration_tests AtomFragments Automaking_mpqc_open AutomationFragmentation_failures Candidate_v1.5.4 Candidate_v1.6.0 Candidate_v1.6.1 ChangeBugEmailaddress ChangingTestPorts ChemicalSpaceEvaluator CombiningParticlePotentialParsing Combining_Subpackages Debian_Package_split Debian_package_split_molecuildergui_only Disabling_MemDebug Docu_Python_wait EmpiricalPotential_contain_HomologyGraph EmpiricalPotential_contain_HomologyGraph_documentation Enable_parallel_make_install Enhance_userguide Enhanced_StructuralOptimization Enhanced_StructuralOptimization_continued Example_ManyWaysToTranslateAtom Exclude_Hydrogens_annealWithBondGraph FitPartialCharges_GlobalError Fix_BoundInBox_CenterInBox_MoleculeActions Fix_ChargeSampling_PBC Fix_ChronosMutex Fix_FitPartialCharges Fix_FitPotential_needs_atomicnumbers Fix_ForceAnnealing Fix_IndependentFragmentGrids Fix_ParseParticles Fix_ParseParticles_split_forward_backward_Actions Fix_PopActions Fix_QtFragmentList_sorted_selection Fix_Restrictedkeyset_FragmentMolecule Fix_StatusMsg Fix_StepWorldTime_single_argument Fix_Verbose_Codepatterns Fix_fitting_potentials Fixes ForceAnnealing_goodresults ForceAnnealing_oldresults ForceAnnealing_tocheck ForceAnnealing_with_BondGraph ForceAnnealing_with_BondGraph_continued ForceAnnealing_with_BondGraph_continued_betteresults ForceAnnealing_with_BondGraph_contraction-expansion FragmentAction_writes_AtomFragments FragmentMolecule_checks_bonddegrees GeometryObjects Gui_Fixes Gui_displays_atomic_force_velocity ImplicitCharges IndependentFragmentGrids IndependentFragmentGrids_IndividualZeroInstances IndependentFragmentGrids_IntegrationTest IndependentFragmentGrids_Sole_NN_Calculation JobMarket_RobustOnKillsSegFaults JobMarket_StableWorkerPool JobMarket_unresolvable_hostname_fix MoreRobust_FragmentAutomation ODR_violation_mpqc_open PartialCharges_OrthogonalSummation PdbParser_setsAtomName PythonUI_with_named_parameters QtGui_reactivate_TimeChanged_changes Recreated_GuiChecks Rewrite_FitPartialCharges RotateToPrincipalAxisSystem_UndoRedo SaturateAtoms_findBestMatching SaturateAtoms_singleDegree StoppableMakroAction Subpackage_CodePatterns Subpackage_JobMarket Subpackage_LinearAlgebra Subpackage_levmar Subpackage_mpqc_open Subpackage_vmg Switchable_LogView ThirdParty_MPQC_rebuilt_buildsystem TrajectoryDependenant_MaxOrder TremoloParser_IncreasedPrecision TremoloParser_MultipleTimesteps TremoloParser_setsAtomName Ubuntu_1604_changes stable
Last change on this file since 026bef was 026bef, checked in by Frederik Heber <heber@…>, 9 years ago

Changed GLMoleculeObject_...:countSubjectKilled() to taking id parameter.

  • this is a precursor for when the ObservedValues reside with QtInstanceInformationBoard.
  • enhanced ObservedValue_wCallback to take a bound getIndex function().
  • additionally, we route internally to ObservedValue::get() and this gets us out of the painful situation where we need to supply an index getter to the ObservedValue that monitors the index (and hence must be present already to bind to its get function).
  • Property mode set to 100644
File size: 28.3 KB
Line 
1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
6 *
7 *
8 * This file is part of MoleCuilder.
9 *
10 * MoleCuilder is free software: you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation, either version 2 of the License, or
13 * (at your option) any later version.
14 *
15 * MoleCuilder is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU General Public License
21 * along with MoleCuilder. If not, see <http://www.gnu.org/licenses/>.
22 */
23
24/*
25 * GLWorldView.cpp
26 *
27 * Created on: Aug 1, 2010
28 * Author: heber
29 */
30
31// include config.h
32#ifdef HAVE_CONFIG_H
33#include <config.h>
34#endif
35
36#include "GLWorldView.hpp"
37
38#include <Qt/qevent.h>
39#include <Qt/qaction.h>
40#include <QtGui/QMenu>
41#include <QtGui/QToolBar>
42#include <QtGui/QToolButton>
43#include <Qt/qtimer.h>
44#include <Qt/qsettings.h>
45#include <Qt3D/qglbuilder.h>
46#include <Qt3D/qglscenenode.h>
47#include <Qt3D/qglsphere.h>
48#include <Qt3D/qglcylinder.h>
49#include <Qt3D/qglcube.h>
50
51#include "GLWorldScene.hpp"
52
53#include "CodePatterns/MemDebug.hpp"
54
55#include "Atom/AtomObserver.hpp"
56#include "Atom/atom_observable.hpp"
57#include "Box.hpp"
58#include "CodePatterns/Log.hpp"
59#include "CodePatterns/Observer/Notification.hpp"
60#include "CodePatterns/Observer/ObserverLog.hpp"
61#include "Descriptors/MoleculeIdDescriptor.hpp"
62#include "molecule.hpp"
63#include "Shapes/ShapeRegistry.hpp"
64#include "World.hpp"
65#include "WorldTime.hpp"
66
67GLWorldView::GLWorldView(QWidget *parent)
68 : QGLView(parent), Observer("GLWorldView"), worldscene(NULL), changesPresent(false), needsRedraw(false)
69{
70 worldscene = new GLWorldScene(this);
71
72 setOption(QGLView::ObjectPicking, true);
73 setOption(QGLView::CameraNavigation, false);
74 setFocusPolicy(Qt::StrongFocus);
75 setCameraControlMode(Rotate);
76 defaultEyeSeparation = 4.0;
77
78 createDomainBox();
79 createDreiBein();
80 //changeMaterials(false);
81
82 qRegisterMetaType<atomId_t>("atomId_t");
83 qRegisterMetaType<moleculeId_t>("moleculeId_t");
84
85 connect(this, SIGNAL(ShapeAdded(const std::string &)), worldscene, SLOT(addShape(const std::string &)));
86 connect(this, SIGNAL(ShapeRemoved(const std::string &)), worldscene, SLOT(removeShape(const std::string &)));
87// connect(this, SIGNAL(TimeChanged()), worldscene, SIGNAL(updated()));
88 connect(worldscene, SIGNAL(changeOccured()), this, SLOT(changeSignalled()));
89 connect(worldscene, SIGNAL(changed()), this, SIGNAL(changed()));
90 connect(worldscene, SIGNAL(hoverChanged(const atomId_t)), this, SLOT(sceneHoverSignalled(const atomId_t)));
91 connect(worldscene, SIGNAL(hoverChanged(const moleculeId_t, int)), this, SLOT(sceneHoverSignalled(const moleculeId_t, int)));
92 //connect(this, SIGNAL(changed()), this, SLOT(updateGL()));
93 connect(this, SIGNAL(changed()), this, SLOT(sceneChangeSignalled()));
94 connect(this, SIGNAL(moleculesVisibilityChanged(const moleculeId_t,bool)), worldscene, SLOT(moleculesVisibilityChanged(const moleculeId_t,bool)));
95
96 // sign on to changes in the world
97 World::getInstance().signOn(this);
98 World::getInstance().signOn(this, World::MoleculeInserted);
99 World::getInstance().signOn(this, World::SelectionChanged);
100// WorldTime::getInstance().signOn(this, WorldTime::TimeChanged);
101 AtomObserver::getInstance().signOn(this, AtomObservable::PositionChanged);
102
103 ShapeRegistry::getInstance().signOn(this);
104 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeInserted);
105 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeRemoved);
106 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::SelectionChanged);
107
108 redrawTimer = new QTimer(this);
109}
110
111GLWorldView::~GLWorldView()
112{
113 // remove me from all observed molecules
114 for (ObservedMolecules_t::iterator iter = ObservedMolecules.begin();
115 !ObservedMolecules.empty();
116 iter = ObservedMolecules.begin())
117 signOffFromMolecule(*iter);
118
119 QSettings settings;
120 settings.beginGroup("WorldView");
121 settings.setValue("domainBoxEnabled", (meshDomainBox->options() & QGLSceneNode::HideNode) == 0);
122 settings.setValue("dreiBeinEnabled", (meshDreiBein->options() & QGLSceneNode::HideNode) == 0);
123 settings.endGroup();
124
125
126 World::getInstance().signOff(this);
127 World::getInstance().signOff(this, World::MoleculeInserted);
128 World::getInstance().signOff(this, World::SelectionChanged);
129// WorldTime::getInstance().signOff(this, WorldTime::TimeChanged);
130 AtomObserver::getInstance().signOff(this, AtomObservable::PositionChanged);
131 ShapeRegistry::getInstance().signOff(this);
132 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeInserted);
133 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeRemoved);
134 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::SelectionChanged);
135 delete worldscene;
136
137 delete(domainBoxMaterial);
138 for (int i=0;i<3;i++)
139 delete(dreiBeinMaterial[i]);
140}
141
142
143/**
144 * Add some widget specific actions to the toolbar:
145 * - camera rotation/translation mode
146 * - camera fit to domain
147 */
148void GLWorldView::addToolBarActions(QToolBar *toolbar)
149{
150 // camera control mode
151 toolbar->addSeparator();
152 QAction *transAction = new QAction(QIcon::fromTheme("forward"), tr("camera translation mode"), this);
153 connect(transAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeTranslation()));
154 toolbar->addAction(transAction);
155 QAction *rotAction = new QAction(QIcon::fromTheme("object-rotate-left"), tr("camera rotation mode"), this);
156 connect(rotAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeRotation()));
157 toolbar->addAction(rotAction);
158 QAction *fitAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("camera fit to domain"), this);
159 connect(fitAction, SIGNAL(triggered()), this, SLOT(fitCameraToDomain()));
160 toolbar->addAction(fitAction);
161
162 // stereo mode
163 QToolButton *stereoButton = new QToolButton(toolbar);
164 QMenu *stereoMenu = new QMenu();
165 QAction *stereoDisableAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("disable"), this);
166 connect(stereoDisableAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeDisable()));
167 stereoMenu->addAction(stereoDisableAction);
168 QAction *stereoHardwareAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("hardware"), this);
169 connect(stereoHardwareAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeHardware()));
170 stereoMenu->addAction(stereoHardwareAction);
171 QAction *stereoLeftRightAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("left right"), this);
172 connect(stereoLeftRightAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeLeftRight()));
173 stereoMenu->addAction(stereoLeftRightAction);
174 QAction *stereoRightLeftAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("right left"), this);
175 connect(stereoRightLeftAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeRightLeft()));
176 stereoMenu->addAction(stereoRightLeftAction);
177 QAction *stereoTopBottomAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("top bottom"), this);
178 connect(stereoTopBottomAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeTopBottom()));
179 stereoMenu->addAction(stereoTopBottomAction);
180 QAction *stereoBottomTopAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("bottom top"), this);
181 connect(stereoBottomTopAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeBottomTop()));
182 stereoMenu->addAction(stereoBottomTopAction);
183 QAction *stereoAnaglyphAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("anaglyph"), this);
184 connect(stereoAnaglyphAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeAnaglyph()));
185 stereoMenu->addAction(stereoAnaglyphAction);
186 stereoButton->setMenu(stereoMenu);
187 stereoButton->setIcon(QIcon(QPixmap(":/icon_view_stereo.png")));
188 stereoButton->setPopupMode(QToolButton::InstantPopup);
189 toolbar->addWidget(stereoButton);
190
191 // selection mode
192 toolbar->addSeparator();
193 QAction *selAtomAction = new QAction(QIcon(QPixmap(":/icon_select_atom.png")), tr("select atom by clicking"), this);
194 connect(selAtomAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeAtom()));
195 toolbar->addAction(selAtomAction);
196 QAction *selMolAction = new QAction(QIcon(QPixmap(":/icon_select_molecule.png")), tr("select molecule by clicking"), this);
197 connect(selMolAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeMolecule()));
198 toolbar->addAction(selMolAction);
199
200 // dreiBein/domain enabler
201 toolbar->addSeparator();
202 QAction *seldreiBein = new QAction(QIcon(QPixmap(":/icon_dreiBein.png")), tr("enable/disable dreiBein"), this);
203 connect(seldreiBein, SIGNAL(triggered()), this, SLOT(changeDreiBein()));
204 toolbar->addAction(seldreiBein);
205 QAction *seldomain = new QAction(QIcon(QPixmap(":/icon_domain.png")), tr("enable/disable domain box"), this);
206 connect(seldomain, SIGNAL(triggered()), this, SLOT(changeDomain()));
207 toolbar->addAction(seldomain);
208}
209
210void GLWorldView::createDomainBox()
211{
212 QSettings settings;
213 settings.beginGroup("WorldView");
214 QColor colorFrame = settings.value("domainBoxColorFrame", QColor(150,160,200,255)).value<QColor>();
215 QColor colorAmbient = settings.value("domainBoxColorAmbient", QColor(50,60,100,255)).value<QColor>();
216 QColor colorDiffuse = settings.value("domainBoxColorDiffuse", QColor(150,160,200,180)).value<QColor>();
217 settings.setValue("domainBoxColorFrame", colorFrame);
218 settings.setValue("domainBoxColorAmbient", colorAmbient);
219 settings.setValue("domainBoxColorDiffuse", colorDiffuse);
220 const bool status = settings.value("domainBoxEnabled").toBool();
221 settings.endGroup();
222
223 domainBoxMaterial = new QGLMaterial;
224 domainBoxMaterial->setAmbientColor(QColor(0,0,0,255));
225 domainBoxMaterial->setDiffuseColor(QColor(0,0,0,255));
226 domainBoxMaterial->setEmittedLight(colorFrame);
227
228
229 QGLMaterial *material = new QGLMaterial;
230 material->setAmbientColor(colorAmbient);
231 material->setDiffuseColor(colorDiffuse);
232
233 QGLBuilder builder;
234 builder << QGL::Faceted;
235 builder << QGLCube(-1.0); // "inverted" => inside faces are used as front.
236 meshDomainBox = builder.finalizedSceneNode();
237 QMatrix4x4 mat;
238 mat.translate(0.5f, 0.5f, 0.5f);
239 meshDomainBox->setLocalTransform(mat);
240 meshDomainBox->setMaterial(material);
241
242 setDomainStatus( status );
243}
244
245void GLWorldView::createDreiBein()
246{
247 QSettings settings;
248 settings.beginGroup("WorldView");
249 QColor colorX = settings.value("dreiBeinColorX", QColor(255,50,50,255)).value<QColor>();
250 QColor colorY = settings.value("dreiBeinColorY", QColor(50,255,50,255)).value<QColor>();
251 QColor colorZ = settings.value("dreiBeinColorZ", QColor(50,50,255,255)).value<QColor>();
252 settings.setValue("dreiBeinColorX", colorX);
253 settings.setValue("dreiBeinColorY", colorY);
254 settings.setValue("dreiBeinColorZ", colorZ);
255 const bool status = settings.value("dreiBeinEnabled").toBool();
256 settings.endGroup();
257
258 // Create 3 color for the 3 axes.
259 dreiBeinMaterial[0] = new QGLMaterial;
260 dreiBeinMaterial[0]->setColor(colorX);
261 dreiBeinMaterial[1] = new QGLMaterial;
262 dreiBeinMaterial[1]->setColor(colorY);
263 dreiBeinMaterial[2] = new QGLMaterial;
264 dreiBeinMaterial[2]->setColor(colorZ);
265
266 // Create the basic meshes (cylinder and cone).
267 QGLBuilder builderCyl;
268 builderCyl << QGLCylinder(.15,.15,1.6,16);
269 QGLSceneNode *cyl = builderCyl.finalizedSceneNode();
270
271 QGLBuilder builderCone;
272 builderCone << QGLCylinder(0,.4,0.4,16);
273 QGLSceneNode *cone = builderCone.finalizedSceneNode();
274 {
275 QMatrix4x4 mat;
276 mat.translate(0.0f, 0.0f, 1.0f);
277 cone->setLocalTransform(mat);
278 }
279
280 // Create a scene node from the 3 axes.
281 meshDreiBein = new QGLSceneNode(this);
282
283 // X-direction
284 QGLSceneNode *node = new QGLSceneNode(meshDreiBein);
285 node->setMaterial(dreiBeinMaterial[0]);
286 node->addNode(cyl);
287 node->setPosition(QVector3D(.8f, 0.f, 0.f));
288 node->addNode(cone);
289 {
290 QMatrix4x4 mat;
291 mat.rotate(90, 0.0f, 1.0f, 0.0f);
292 node->setLocalTransform(mat);
293 }
294
295 // Y-direction
296 node = new QGLSceneNode(meshDreiBein);
297 node->setMaterial(dreiBeinMaterial[1]);
298 node->addNode(cyl);
299 node->addNode(cone);
300 {
301 QMatrix4x4 mat;
302 mat.rotate(-90, 1.0f, 0.0f, 0.0f);
303 node->setLocalTransform(mat);
304 }
305 node->setPosition(QVector3D(0.f, .8f, 0.f));
306
307 // Z-direction
308 node = new QGLSceneNode(meshDreiBein);
309 node->setMaterial(dreiBeinMaterial[2]);
310 node->addNode(cyl);
311 node->addNode(cone);
312 node->setPosition(QVector3D(0.f, 0.f, .8f));
313
314 setdreiBeinStatus( status );
315}
316
317void GLWorldView::setSelectionChangedAgent(QtSelectionChangedAgent *agent)
318{
319 worldscene->setSelectionChangedAgent(agent);
320}
321
322/**
323 * Update operation which can be invoked by the observable (which should be the
324 * change tracker here).
325 */
326void GLWorldView::update(Observable *publisher)
327{
328// emit changed();
329}
330
331void GLWorldView::signOnToMolecule(const molecule *_mol)
332{
333 ASSERT( _mol != NULL,
334 "GLWorldView::signOnToMolecule() - molecule ref is NULL.");
335 _mol->signOn(this, molecule::AtomInserted);
336 _mol->signOn(this, molecule::AtomRemoved);
337
338 ObservedMolecules.insert(const_cast<molecule *>(_mol));
339}
340
341void GLWorldView::signOffFromMolecule(const molecule *_mol)
342{
343 ObservedMolecules_t::const_iterator iter = ObservedMolecules.find(
344 const_cast<molecule *>(_mol));
345 ASSERT( iter != ObservedMolecules.end(),
346 "GLWorldView::signOffFromMolecule() - molecule "+toString(_mol)
347 +" gave subjectKilled we are not signed on.");
348// LOG(1, "INFO: Erasing " << mol << " from ObservedMolecules.");
349 ObservedMolecules.erase(iter);
350
351 ASSERT( _mol != NULL,
352 "GLWorldView::signOffFromMolecule() - molecule ref is NULL.");
353 _mol->signOff(this, molecule::AtomInserted);
354 _mol->signOff(this, molecule::AtomRemoved);
355}
356
357/**
358 * The observable can tell when it dies.
359 */
360void GLWorldView::subjectKilled(Observable *publisher)
361{
362 molecule * mol = static_cast<molecule *>(publisher);
363
364// std::copy(ObservedMolecules.begin(), ObservedMolecules.end(),
365// std::ostream_iterator<molecule *>(std::cout, "\n"));
366
367 if (mol != NULL) {
368 ObservedMolecules.erase(mol);
369//
370// // sign off
371// signOffFromMolecule(mol);
372
373 // emit removed signal
374 const moleculeId_t _id = mol->getId();
375 emit moleculeRemoved(_id);
376 }
377}
378
379/** Listen to specific changes to the world.
380 *
381 * @param publisher ref to observable.
382 * @param notification type of notification
383 */
384void GLWorldView::recieveNotification(Observable *publisher, Notification_ptr notification)
385{
386 if (static_cast<World *>(publisher) == World::getPointer()) {
387 switch (notification->getChannelNo()) {
388 case World::SelectionChanged:
389 {
390 #ifdef LOG_OBSERVER
391 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that selection has changed.";
392 #endif
393 emit worldSelectionChanged();
394 break;
395 }
396 case World::MoleculeInserted:
397 {
398 const moleculeId_t _id = const_cast<const World &>(World::getInstance()).lastChangedMolId();
399 #ifdef LOG_OBSERVER
400 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that molecule "+toString(_id)+" has been inserted.";
401 #endif
402 const molecule * const _molecule = const_cast<const World &>(World::getInstance()).
403 getMolecule(MoleculeById(_id));
404 if (_molecule != NULL) {
405 signOnToMolecule(_molecule);
406
407 emit moleculeInserted(_id);
408 }
409 break;
410 }
411 default:
412 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for World.");
413 break;
414 }
415 } else if (static_cast<WorldTime *>(publisher) == WorldTime::getPointer()) {
416 switch (notification->getChannelNo()) {
417 case WorldTime::TimeChanged:
418 {
419#ifdef LOG_OBSERVER
420 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that WorldTime's time has changed.";
421#endif
422 emit changed();
423 emit TimeChanged();
424 break;
425 }
426 default:
427 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for WorldTime.");
428 break;
429 }
430 } else if (dynamic_cast<molecule *>(publisher) != NULL) {
431 const molecule * mol = const_cast<const molecule * const>(dynamic_cast<molecule *>(publisher));
432 const moleculeId_t molid = mol->getId();
433 const atomId_t atomid = mol->lastChangedAtomId();
434 switch (notification->getChannelNo()) {
435 case molecule::AtomInserted:
436 {
437#ifdef LOG_OBSERVER
438 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this))
439 << " received notification that atom "+toString(atomid)+" has been inserted into molecule "+toString(molid)+".";
440#endif
441 emit atomInserted(molid, atomid);
442 break;
443 }
444 case World::AtomRemoved:
445 {
446#ifdef LOG_OBSERVER
447 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this))
448 << " received notification that atom "+toString(atomid)+" has been removed from molecule "+toString(molid)+".";
449#endif
450 emit atomRemoved(molid, atomid);
451 break;
452 }
453 default:
454 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for molecule.");
455 break;
456 }
457 } else if (dynamic_cast<AtomObservable *>(publisher) != NULL) {
458 switch (notification->getChannelNo()) {
459 case AtomObservable::PositionChanged:
460 {
461 #ifdef LOG_OBSERVER
462 const atom *_atom = dynamic_cast<const atom *>(publisher);
463 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_atom->getId())+" has changed its position.";
464 #endif
465 emit changed();
466 break;
467 }
468 default:
469 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for AtomObservable.");
470 break;
471 }
472 } else if (static_cast<ShapeRegistry*>(publisher) == ShapeRegistry::getPointer()) {
473 switch (notification->getChannelNo()) {
474 case ShapeRegistry::ShapeInserted:
475 {
476 emit ShapeAdded(ShapeRegistry::getInstance().lastChanged()->getName());
477 break;
478 }
479 case ShapeRegistry::ShapeRemoved:
480 {
481 emit ShapeRemoved(ShapeRegistry::getInstance().lastChanged()->getName());
482 break;
483 }
484 case ShapeRegistry::SelectionChanged:
485 {
486 worldscene->updateSelectedShapes();
487 break;
488 }
489 default:
490 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for ShapeRegistry.");
491 break;
492 }
493 }
494}
495
496void GLWorldView::checkChanges()
497{
498 updateGL();
499 needsRedraw = false;
500}
501
502void GLWorldView::changeDreiBein()
503{
504 // invert to new status
505 const bool status = ((meshDreiBein->options() & QGLSceneNode::HideNode) == 0);
506 setdreiBeinStatus(!status);
507 // realize
508 updateGL();
509 needsRedraw = true;
510}
511
512void GLWorldView::setdreiBeinStatus(const bool status)
513{
514 if (status)
515 meshDreiBein->setOptions( meshDreiBein->options() & (255-QGLSceneNode::HideNode) );
516 else
517 meshDreiBein->setOptions( meshDreiBein->options() | QGLSceneNode::HideNode );
518}
519
520void GLWorldView::changeDomain()
521{
522 // invert to new status
523 const bool status = ((meshDomainBox->options() & QGLSceneNode::HideNode) == 0);
524 setDomainStatus(!status);
525 // realize
526 updateGL();
527 needsRedraw = true;
528}
529
530void GLWorldView::setDomainStatus(const bool status)
531{
532 if (status)
533 meshDomainBox->setOptions( meshDomainBox->options() & (255-QGLSceneNode::HideNode) );
534 else
535 meshDomainBox->setOptions( meshDomainBox->options() | QGLSceneNode::HideNode );
536}
537
538void GLWorldView::sceneChangeSignalled()
539{
540 if (!needsRedraw){
541 redrawTimer->singleShot(0, this, SLOT(checkChanges()));
542 needsRedraw = true;
543 redrawTimer->start();
544 }
545}
546
547void GLWorldView::initializeGL(QGLPainter *painter)
548{
549 worldscene->initialize(this, painter);
550 changesPresent = false;
551}
552
553void GLWorldView::paintGL(QGLPainter *painter)
554{
555 if (changesPresent) {
556 initializeGL(painter);
557 changesPresent = false;
558 }
559
560 QVector3D cameraDir = camera()->center() - camera()->eye();
561 cameraDir.normalize();
562 QVector4D cameraPlane(cameraDir, QVector3D::dotProduct(cameraDir, camera()->eye()));
563 worldscene->draw(painter, cameraPlane);
564
565 drawDreiBein(painter);
566
567 // Domain box has to be last because of its transparency.
568 drawDomainBox(painter);
569}
570
571void GLWorldView::keyPressEvent(QKeyEvent *e)
572{
573 // Find the distance between the eye and focus point.
574 QVector3D d = camera()->eye() - camera()->center();
575// LOG(1, "Distance vector eye and center is "
576// << d.x() << "," << d.y() << "," << d.z());
577 // scale the move unit by the eye <-> domain center distance
578 const double key_move_unit = 0.04*(d.length()/50.);
579
580 if (e->key() == Qt::Key_Tab) {
581 // The Tab key turns the ShowPicking option on and off,
582 // which helps show what the pick buffer looks like.
583 setOption(QGLView::ShowPicking, ((options() & QGLView::ShowPicking) == 0));
584 updateGL();
585 } else if ((e->key() == Qt::Key_Minus) || (e->key() == Qt::Key_Plus)) {
586 // Scale the distance.
587 if (e->key() == Qt::Key_Minus)
588 d *= 1.2;
589 else if (e->key() == Qt::Key_Plus)
590 d /= 1.2;
591 // Set new eye position.
592 camera()->setEye(camera()->center() + d);
593 } else if ((e->key() == Qt::Key_Left) || (e->key() == Qt::Key_Right)) {
594 // Translate the camera.
595 const double d = (e->key() == Qt::Key_Left) ? -key_move_unit : key_move_unit;
596 camera()->translateCenter( d, 0., 0);
597 camera()->translateEye( d, 0., 0);
598 } else if ((e->key() == Qt::Key_Up) || (e->key() == Qt::Key_Down)) {
599 // Translate the camera.
600 const double d = (e->key() == Qt::Key_Up) ? -key_move_unit : key_move_unit;
601 camera()->translateCenter( 0., d, 0);
602 camera()->translateEye( 0., d, 0);
603 } else if ((e->key() == Qt::Key_PageUp) || (e->key() == Qt::Key_PageDown)) {
604 // Translate the camera.
605 const double d = (e->key() == Qt::Key_PageUp) ? -key_move_unit : key_move_unit;
606 camera()->translateCenter( 0., 0., d);
607 camera()->translateEye( 0., 0., d);
608 }
609 QGLView::keyPressEvent(e);
610}
611
612void GLWorldView::changeSignalled()
613{
614 changesPresent = true;
615}
616
617
618/**
619 * Set the current camera control mode.
620 */
621void GLWorldView::setCameraControlMode(GLWorldView::CameraControlModeType mode)
622{
623 cameraControlMode = mode;
624}
625
626void GLWorldView::setCameraControlModeRotation()
627{
628 setCameraControlMode(Rotate);
629}
630
631void GLWorldView::setCameraControlModeTranslation()
632{
633 setCameraControlMode(Translate);
634}
635
636/**
637 * Returns the current camera control mode.
638 * This needs to be invertable (rotation - translation), if the shift key is pressed.
639 */
640GLWorldView::CameraControlModeType GLWorldView::getCameraControlMode(bool inverted)
641{
642 if (inverted){
643 if (cameraControlMode == Rotate)
644 return Translate;
645 if (cameraControlMode == Translate)
646 return Rotate;
647 return Rotate;
648 }else
649 return cameraControlMode;
650}
651
652/**
653 * Set the camera so it can oversee the whole domain.
654 */
655void GLWorldView::fitCameraToDomain()
656{
657 // Move the camera focus point to the center of the domain box.
658 Vector v = World::getInstance().getDomain().translateIn(Vector(0.5, 0.5, 0.5));
659 camera()->setCenter(QVector3D(v[0], v[1], v[2]));
660
661 // Guess some eye distance.
662 double dist = v.Norm() * 3;
663 camera()->setEye(QVector3D(v[0], v[1], v[2] + dist));
664 camera()->setUpVector(QVector3D(0, 1, 0));
665}
666
667void GLWorldView::setCameraStereoModeDisable()
668{
669 setStereoType(QGLView::Hardware);
670 camera()->setEyeSeparation(0.0);
671 updateGL();
672}
673
674void GLWorldView::setCameraStereoModeHardware()
675{
676 setStereoType(QGLView::Hardware);
677 camera()->setEyeSeparation(defaultEyeSeparation);
678 updateGL();
679}
680
681void GLWorldView::setCameraStereoModeLeftRight()
682{
683 setStereoType(QGLView::LeftRight);
684 camera()->setEyeSeparation(defaultEyeSeparation);
685 updateGL();
686}
687
688void GLWorldView::setCameraStereoModeRightLeft()
689{
690 setStereoType(QGLView::RightLeft);
691 camera()->setEyeSeparation(defaultEyeSeparation);
692 updateGL();
693}
694
695void GLWorldView::setCameraStereoModeTopBottom()
696{
697 setStereoType(QGLView::TopBottom);
698 camera()->setEyeSeparation(defaultEyeSeparation);
699 updateGL();
700}
701
702void GLWorldView::setCameraStereoModeBottomTop()
703{
704 setStereoType(QGLView::BottomTop);
705 camera()->setEyeSeparation(defaultEyeSeparation);
706 updateGL();
707}
708
709void GLWorldView::setCameraStereoModeAnaglyph()
710{
711 setStereoType(QGLView::RedCyanAnaglyph);
712 camera()->setEyeSeparation(defaultEyeSeparation);
713 updateGL();
714}
715
716void GLWorldView::mousePressEvent(QMouseEvent *event)
717{
718 QGLView::mousePressEvent(event);
719
720 // Reset the saved mouse position.
721 lastMousePos = event->posF();
722}
723
724/**
725 * Handle a mouse move event.
726 * This is used to control the camera (rotation and translation) when the left button is being pressed.
727 */
728void GLWorldView::mouseMoveEvent(QMouseEvent *event)
729{
730 if (event->buttons() & Qt::LeftButton){
731 // Find the mouse distance since the last event.
732 QPointF d = event->posF() - lastMousePos;
733 lastMousePos = event->posF();
734
735 // Rotate or translate? (inverted by shift key)
736 CameraControlModeType mode = getCameraControlMode(event->modifiers() & Qt::ShiftModifier);
737
738 if (mode == Rotate){
739 // Rotate the camera.
740 d *= 0.3;
741 camera()->tiltPanRollCenter(- d.y(), - d.x(), 0);
742 }else if (mode == Translate){
743 // Translate the camera.
744 d *= 0.02;
745 camera()->translateCenter(- d.x(), d.y(), 0);
746 camera()->translateEye(- d.x(), d.y(), 0);
747 }
748 }else{
749 // Without this Qt would not test for hover events (i.e. mouse over an atom).
750 QGLView::mouseMoveEvent(event);
751 }
752}
753
754/**
755 * When the mouse wheel is used, zoom in or out.
756 */
757void GLWorldView::wheelEvent(QWheelEvent *event)
758{
759 // Find the distance between the eye and focus point.
760 QVector3D d = camera()->eye() - camera()->center();
761
762 // Scale the distance.
763 if (event->delta() < 0)
764 d *= 1.2;
765 else if (event->delta() > 0)
766 d /= 1.2;
767
768 // Set new eye position.
769 camera()->setEye(camera()->center() + d);
770}
771
772/**
773 * Draw a transparent cube representing the domain.
774 */
775void GLWorldView::drawDomainBox(QGLPainter *painter) const
776{
777 // Apply the domain matrix.
778 RealSpaceMatrix m = World::getInstance().getDomain().getM();
779 painter->modelViewMatrix().push();
780 painter->modelViewMatrix() *= QMatrix4x4(m.at(0,0), m.at(0,1), m.at(0,2), 0.0,
781 m.at(1,0), m.at(1,1), m.at(1,2), 0.0,
782 m.at(2,0), m.at(2,1), m.at(2,2), 0.0,
783 0.0, 0.0, 0.0, 1.0);
784
785 // Draw the transparent cube.
786 painter->setStandardEffect(QGL::LitMaterial);
787 glCullFace(GL_BACK);
788 glEnable(GL_CULL_FACE);
789 glEnable(GL_BLEND);
790 glDepthMask(0);
791 //glDisable(GL_DEPTH_TEST);
792 meshDomainBox->draw(painter);
793 //glEnable(GL_DEPTH_TEST);
794 glDepthMask(1);
795 glDisable(GL_BLEND);
796 glDisable(GL_CULL_FACE);
797
798 // Draw the outlines (if we have drawn the box itself)
799 if ((meshDomainBox->options() & QGLSceneNode::HideNode) == 0) {
800 painter->setFaceMaterial(QGL::AllFaces, domainBoxMaterial);
801 //glEnable(GL_LINE_SMOOTH);
802 QVector3DArray array;
803 array.append(0, 0, 0); array.append(1, 0, 0);
804 array.append(1, 0, 0); array.append(1, 1, 0);
805 array.append(1, 1, 0); array.append(0, 1, 0);
806 array.append(0, 1, 0); array.append(0, 0, 0);
807
808 array.append(0, 0, 1); array.append(1, 0, 1);
809 array.append(1, 0, 1); array.append(1, 1, 1);
810 array.append(1, 1, 1); array.append(0, 1, 1);
811 array.append(0, 1, 1); array.append(0, 0, 1);
812
813 array.append(0, 0, 0); array.append(0, 0, 1);
814 array.append(1, 0, 0); array.append(1, 0, 1);
815 array.append(0, 1, 0); array.append(0, 1, 1);
816 array.append(1, 1, 0); array.append(1, 1, 1);
817 painter->clearAttributes();
818 painter->setVertexAttribute(QGL::Position, array);
819 painter->draw(QGL::Lines, 24);
820 }
821
822 painter->modelViewMatrix().pop();
823}
824
825void GLWorldView::drawDreiBein(QGLPainter *painter)
826{
827 painter->modelViewMatrix().push();
828 painter->modelViewMatrix().translate(camera()->center());
829 painter->setStandardEffect(QGL::LitMaterial);
830 painter->setFaceMaterial(QGL::FrontFaces, NULL);
831 meshDreiBein->draw(painter);
832 painter->modelViewMatrix().pop();
833}
834
835void GLWorldView::sceneHoverSignalled(const atomId_t _id)
836{
837 emit hoverChanged(_id);
838}
839
840void GLWorldView::sceneHoverSignalled(const moleculeId_t _id, int _i)
841{
842 emit hoverChanged(_id, _i);
843}
Note: See TracBrowser for help on using the repository browser.