source: src/UIElements/Views/Qt4/Qt3D/GLWorldView.cpp@ 15c8a9

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 15c8a9 was 15c8a9, checked in by Frederik Heber <heber@…>, 9 years ago

Added QtInstanceInformationBoard that handles ObservedValues through the QtGui interface.

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