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

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

Changed atom ptr into atomicId_t param for atomInserted of GLWorld... classes.

  • Property mode set to 100644
File size: 58.8 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 "molecule.hpp"
62#include "Shapes/ShapeRegistry.hpp"
63#include "World.hpp"
64#include "WorldTime.hpp"
65
66GLWorldView::GLWorldView(QWidget *parent)
67 : QGLView(parent), Observer("GLWorldView"), worldscene(NULL), changesPresent(false), needsRedraw(false)
68{
69 worldscene = new GLWorldScene(this);
70
71 setOption(QGLView::ObjectPicking, true);
72 setOption(QGLView::CameraNavigation, false);
73 setCameraControlMode(Rotate);
74 defaultEyeSeparation = 4.0;
75
76 createDomainBox();
77 createDreiBein();
78 //changeMaterials(false);
79
80 qRegisterMetaType<atomicNumber_t>("atomicNumber_t");
81
82 connect(this, SIGNAL(ShapeAdded()), worldscene, SLOT(addShape()));
83 connect(this, SIGNAL(ShapeRemoved()), worldscene, SLOT(removeShape()));
84 connect(worldscene, SIGNAL(changeOccured()), this, SLOT(changeSignalled()));
85 connect(worldscene, SIGNAL(changed()), this, SIGNAL(changed()));
86 connect(worldscene, SIGNAL(hoverChanged(const atom *)), this, SLOT(sceneHoverSignalled(const atom *)));
87 connect(this, SIGNAL(atomInserted(const atomicNumber_t)), worldscene, SLOT(atomInserted(const atomicNumber_t)));
88 connect(this, SIGNAL(atomRemoved(const atomicNumber_t)), worldscene, SLOT(atomRemoved(const atomicNumber_t)));
89 connect(this, SIGNAL(worldSelectionChanged()), worldscene, SLOT(worldSelectionChanged()));
90 connect(this, SIGNAL(moleculeRemoved(const molecule *)), worldscene, SLOT(moleculeRemoved(const molecule *)));
91 //connect(this, SIGNAL(moleculeInserted(const molecule *)), worldscene, SLOT(moleculeInserted(const molecule *)));
92 //connect(this, SIGNAL(changed()), this, SLOT(updateGL()));
93 connect(this, SIGNAL(changed()), this, SLOT(sceneChangeSignalled()));
94
95 // sign on to changes in the world
96 World::getInstance().signOn(this);
97 World::getInstance().signOn(this, World::AtomInserted);
98 World::getInstance().signOn(this, World::AtomRemoved);
99 World::getInstance().signOn(this, World::MoleculeInserted);
100 World::getInstance().signOn(this, World::MoleculeRemoved);
101 World::getInstance().signOn(this, World::SelectionChanged);
102 WorldTime::getInstance().signOn(this, WorldTime::TimeChanged);
103 AtomObserver::getInstance().signOn(this, AtomObservable::PositionChanged);
104
105 ShapeRegistry::getInstance().signOn(this);
106 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeInserted);
107 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::ShapeRemoved);
108 ShapeRegistry::getInstance().signOn(this, ShapeRegistry::SelectionChanged);
109
110 redrawTimer = new QTimer(this);
111}
112
113GLWorldView::~GLWorldView()
114{
115 World::getInstance().signOff(this);
116 World::getInstance().signOff(this, World::AtomInserted);
117 World::getInstance().signOff(this, World::AtomRemoved);
118 World::getInstance().signOff(this, World::MoleculeInserted);
119 World::getInstance().signOff(this, World::MoleculeRemoved);
120 World::getInstance().signOff(this, World::SelectionChanged);
121 WorldTime::getInstance().signOff(this, WorldTime::TimeChanged);
122 AtomObserver::getInstance().signOff(this, AtomObservable::PositionChanged);
123 ShapeRegistry::getInstance().signOff(this);
124 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeInserted);
125 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::ShapeRemoved);
126 ShapeRegistry::getInstance().signOff(this, ShapeRegistry::SelectionChanged);
127 delete worldscene;
128
129 delete(domainBoxMaterial);
130 for (int i=0;i<3;i++)
131 delete(dreiBeinMaterial[i]);
132}
133
134
135/**
136 * Add some widget specific actions to the toolbar:
137 * - camera rotation/translation mode
138 * - camera fit to domain
139 */
140void GLWorldView::addToolBarActions(QToolBar *toolbar)
141{
142 // camera control mode
143 toolbar->addSeparator();
144 QAction *transAction = new QAction(QIcon::fromTheme("forward"), tr("camera translation mode"), this);
145 connect(transAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeTranslation()));
146 toolbar->addAction(transAction);
147 QAction *rotAction = new QAction(QIcon::fromTheme("object-rotate-left"), tr("camera rotation mode"), this);
148 connect(rotAction, SIGNAL(triggered()), this, SLOT(setCameraControlModeRotation()));
149 toolbar->addAction(rotAction);
150 QAction *fitAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("camera fit to domain"), this);
151 connect(fitAction, SIGNAL(triggered()), this, SLOT(fitCameraToDomain()));
152 toolbar->addAction(fitAction);
153
154 // stereo mode
155 QToolButton *stereoButton = new QToolButton(toolbar);
156 QMenu *stereoMenu = new QMenu();
157 QAction *stereoDisableAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("disable"), this);
158 connect(stereoDisableAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeDisable()));
159 stereoMenu->addAction(stereoDisableAction);
160 QAction *stereoHardwareAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("hardware"), this);
161 connect(stereoHardwareAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeHardware()));
162 stereoMenu->addAction(stereoHardwareAction);
163 QAction *stereoLeftRightAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("left right"), this);
164 connect(stereoLeftRightAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeLeftRight()));
165 stereoMenu->addAction(stereoLeftRightAction);
166 QAction *stereoRightLeftAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("right left"), this);
167 connect(stereoRightLeftAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeRightLeft()));
168 stereoMenu->addAction(stereoRightLeftAction);
169 QAction *stereoTopBottomAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("top bottom"), this);
170 connect(stereoTopBottomAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeTopBottom()));
171 stereoMenu->addAction(stereoTopBottomAction);
172 QAction *stereoBottomTopAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("bottom top"), this);
173 connect(stereoBottomTopAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeBottomTop()));
174 stereoMenu->addAction(stereoBottomTopAction);
175 QAction *stereoAnaglyphAction = new QAction(QIcon::fromTheme("zoom-best-fit"), tr("anaglyph"), this);
176 connect(stereoAnaglyphAction, SIGNAL(triggered()), this, SLOT(setCameraStereoModeAnaglyph()));
177 stereoMenu->addAction(stereoAnaglyphAction);
178 stereoButton->setMenu(stereoMenu);
179 stereoButton->setIcon(QIcon(QPixmap(":/icon_view_stereo.png")));
180 stereoButton->setPopupMode(QToolButton::InstantPopup);
181 toolbar->addWidget(stereoButton);
182
183 // selection mode
184 toolbar->addSeparator();
185 QAction *selAtomAction = new QAction(QIcon(QPixmap(":/icon_select_atom.png")), tr("select atom by clicking"), this);
186 connect(selAtomAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeAtom()));
187 toolbar->addAction(selAtomAction);
188 QAction *selMolAction = new QAction(QIcon(QPixmap(":/icon_select_molecule.png")), tr("select molecule by clicking"), this);
189 connect(selMolAction, SIGNAL(triggered()), worldscene, SLOT(setSelectionModeMolecule()));
190 toolbar->addAction(selMolAction);
191}
192
193void GLWorldView::createDomainBox()
194{
195 QSettings settings;
196 settings.beginGroup("WorldView");
197 QColor colorFrame = settings.value("domainBoxColorFrame", QColor(150,160,200,255)).value<QColor>();
198 QColor colorAmbient = settings.value("domainBoxColorAmbient", QColor(50,60,100,255)).value<QColor>();
199 QColor colorDiffuse = settings.value("domainBoxColorDiffuse", QColor(150,160,200,180)).value<QColor>();
200 settings.setValue("domainBoxColorFrame", colorFrame);
201 settings.setValue("domainBoxColorAmbient", colorAmbient);
202 settings.setValue("domainBoxColorDiffuse", colorDiffuse);
203 settings.endGroup();
204
205 domainBoxMaterial = new QGLMaterial;
206 domainBoxMaterial->setAmbientColor(QColor(0,0,0,255));
207 domainBoxMaterial->setDiffuseColor(QColor(0,0,0,255));
208 domainBoxMaterial->setEmittedLight(colorFrame);
209
210
211 QGLMaterial *material = new QGLMaterial;
212 material->setAmbientColor(colorAmbient);
213 material->setDiffuseColor(colorDiffuse);
214
215 QGLBuilder builder;
216 builder << QGL::Faceted;
217 builder << QGLCube(-1.0); // "inverted" => inside faces are used as front.
218 meshDomainBox = builder.finalizedSceneNode();
219 QMatrix4x4 mat;
220 mat.translate(0.5f, 0.5f, 0.5f);
221 meshDomainBox->setLocalTransform(mat);
222 meshDomainBox->setMaterial(material);
223}
224
225void GLWorldView::createDreiBein()
226{
227 QSettings settings;
228 settings.beginGroup("WorldView");
229 QColor colorX = settings.value("dreiBeinColorX", QColor(255,50,50,255)).value<QColor>();
230 QColor colorY = settings.value("dreiBeinColorY", QColor(50,255,50,255)).value<QColor>();
231 QColor colorZ = settings.value("dreiBeinColorZ", QColor(50,50,255,255)).value<QColor>();
232 settings.setValue("dreiBeinColorX", colorX);
233 settings.setValue("dreiBeinColorY", colorY);
234 settings.setValue("dreiBeinColorZ", colorZ);
235 settings.setValue("dreiBeinEnabled", true);
236 settings.endGroup();
237
238 // Create 3 color for the 3 axes.
239 dreiBeinMaterial[0] = new QGLMaterial;
240 dreiBeinMaterial[0]->setColor(colorX);
241 dreiBeinMaterial[1] = new QGLMaterial;
242 dreiBeinMaterial[1]->setColor(colorY);
243 dreiBeinMaterial[2] = new QGLMaterial;
244 dreiBeinMaterial[2]->setColor(colorZ);
245
246 // Create the basic meshes (cylinder and cone).
247 QGLBuilder builderCyl;
248 builderCyl << QGLCylinder(.15,.15,1.6,16);
249 QGLSceneNode *cyl = builderCyl.finalizedSceneNode();
250
251 QGLBuilder builderCone;
252 builderCone << QGLCylinder(0,.4,0.4,16);
253 QGLSceneNode *cone = builderCone.finalizedSceneNode();
254 {
255 QMatrix4x4 mat;
256 mat.translate(0.0f, 0.0f, 1.0f);
257 cone->setLocalTransform(mat);
258 }
259
260 // Create a scene node from the 3 axes.
261 meshDreiBein = new QGLSceneNode(this);
262
263 // X-direction
264 QGLSceneNode *node = new QGLSceneNode(meshDreiBein);
265 node->setMaterial(dreiBeinMaterial[0]);
266 node->addNode(cyl);
267 node->setPosition(QVector3D(.8f, 0.f, 0.f));
268 node->addNode(cone);
269 {
270 QMatrix4x4 mat;
271 mat.rotate(90, 0.0f, 1.0f, 0.0f);
272 node->setLocalTransform(mat);
273 }
274
275 // Y-direction
276 node = new QGLSceneNode(meshDreiBein);
277 node->setMaterial(dreiBeinMaterial[1]);
278 node->addNode(cyl);
279 node->addNode(cone);
280 {
281 QMatrix4x4 mat;
282 mat.rotate(-90, 1.0f, 0.0f, 0.0f);
283 node->setLocalTransform(mat);
284 }
285 node->setPosition(QVector3D(0.f, .8f, 0.f));
286
287 // Z-direction
288 node = new QGLSceneNode(meshDreiBein);
289 node->setMaterial(dreiBeinMaterial[2]);
290 node->addNode(cyl);
291 node->addNode(cone);
292 node->setPosition(QVector3D(0.f, 0.f, .8f));
293}
294
295/**
296 * Update operation which can be invoked by the observable (which should be the
297 * change tracker here).
298 */
299void GLWorldView::update(Observable *publisher)
300{
301 emit changed();
302}
303
304/**
305 * The observable can tell when it dies.
306 */
307void GLWorldView::subjectKilled(Observable *publisher) {}
308
309/** Listen to specific changes to the world.
310 *
311 * @param publisher ref to observable.
312 * @param notification type of notification
313 */
314void GLWorldView::recieveNotification(Observable *publisher, Notification_ptr notification)
315{
316 if (static_cast<World *>(publisher) == World::getPointer()) {
317 switch (notification->getChannelNo()) {
318 case World::AtomInserted:
319 {
320 const atomicNumber_t _id = World::getInstance().lastChanged<atom>()->getId();
321 #ifdef LOG_OBSERVER
322 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been inserted.";
323 #endif
324 emit atomInserted(_id);
325 break;
326 }
327 case World::AtomRemoved:
328 {
329 const atomicNumber_t _id = World::getInstance().lastChanged<atom>()->getId();
330 #ifdef LOG_OBSERVER
331 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_id)+" has been removed.";
332 #endif
333 emit atomRemoved(_id);
334 break;
335 }
336 case World::SelectionChanged:
337 {
338 #ifdef LOG_OBSERVER
339 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that selection has changed.";
340 #endif
341 emit worldSelectionChanged();
342 break;
343 }
344 case World::MoleculeInserted:
345 {
346 const molecule *_molecule = World::getInstance().lastChanged<molecule>();
347 #ifdef LOG_OBSERVER
348 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that molecule "+toString(_molecule->getId())+" has been removed.";
349 #endif
350 emit moleculeInserted(_molecule);
351 break;
352 }
353 case World::MoleculeRemoved:
354 {
355 const molecule *_molecule = World::getInstance().lastChanged<molecule>();
356 #ifdef LOG_OBSERVER
357 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that molecule "+toString(_molecule->getId())+" has been removed.";
358 #endif
359 emit moleculeRemoved(_molecule);
360 break;
361 }
362 default:
363 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for World.");
364 break;
365 }
366 } else if (static_cast<WorldTime *>(publisher) == WorldTime::getPointer()) {
367 switch (notification->getChannelNo()) {
368 case WorldTime::TimeChanged:
369 {
370#ifdef LOG_OBSERVER
371 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that WorldTime's time has changed.";
372#endif
373 emit changed();
374 break;
375 }
376 default:
377 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for WorldTime.");
378 break;
379 }
380} else if (dynamic_cast<AtomObservable *>(publisher) != NULL) {
381 switch (notification->getChannelNo()) {
382 case AtomObservable::PositionChanged:
383 {
384 #ifdef LOG_OBSERVER
385 const atom *_atom = dynamic_cast<const atom *>(publisher);
386 observerLog().addMessage() << "++ Observer " << observerLog().getName(static_cast<Observer *>(this)) << " received notification that atom "+toString(_atom->getId())+" has changed its position.";
387 #endif
388 emit changed();
389 break;
390 }
391 default:
392 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for AtomObservable.");
393 break;
394 }
395 } else if (static_cast<ShapeRegistry*>(publisher) == ShapeRegistry::getPointer()) {
396 switch (notification->getChannelNo()) {
397 case ShapeRegistry::ShapeInserted:
398 {
399 emit ShapeAdded();
400 break;
401 }
402 case ShapeRegistry::ShapeRemoved:
403 {
404 emit ShapeRemoved();
405 break;
406 }
407 case ShapeRegistry::SelectionChanged:
408 {
409 worldscene->updateSelectedShapes();
410 break;
411 }
412 default:
413 ASSERT(0, "GLWorldView::recieveNotification() - we cannot get here for ShapeRegistry.");
414 break;
415 }
416 } else
417 ASSERT(0, "GLWorldView::recieveNotification() - received notification from unknown source.");
418}
419
420void GLWorldView::checkChanges()
421{
422 updateGL();
423 needsRedraw = false;
424}
425
426void GLWorldView::sceneChangeSignalled()
427{
428 if (!needsRedraw){
429 redrawTimer->singleShot(0, this, SLOT(checkChanges()));
430 needsRedraw = true;
431 redrawTimer->start();
432 }
433}
434
435void GLWorldView::initializeGL(QGLPainter *painter)
436{
437 worldscene->initialize(this, painter);
438 changesPresent = false;
439}
440
441void GLWorldView::paintGL(QGLPainter *painter)
442{
443 if (changesPresent) {
444 initializeGL(painter);
445 changesPresent = false;
446 }
447
448 QVector3D cameraDir = camera()->center() - camera()->eye();
449 cameraDir.normalize();
450 QVector4D cameraPlane(cameraDir, QVector3D::dotProduct(cameraDir, camera()->eye()));
451 worldscene->draw(painter, cameraPlane);
452
453 drawDreiBein(painter);
454
455 // Domain box has to be last because of its transparency.
456 drawDomainBox(painter);
457}
458
459void GLWorldView::keyPressEvent(QKeyEvent *e)
460{
461 if (e->key() == Qt::Key_Tab) {
462 // The Tab key turns the ShowPicking option on and off,
463 // which helps show what the pick buffer looks like.
464 setOption(QGLView::ShowPicking, ((options() & QGLView::ShowPicking) == 0));
465 updateGL();
466 }
467 QGLView::keyPressEvent(e);
468}
469
470void GLWorldView::changeSignalled()
471{
472 changesPresent = true;
473}
474
475
476/**
477 * Set the current camera control mode.
478 */
479void GLWorldView::setCameraControlMode(GLWorldView::CameraControlModeType mode)
480{
481 cameraControlMode = mode;
482}
483
484void GLWorldView::setCameraControlModeRotation()
485{
486 setCameraControlMode(Rotate);
487}
488
489void GLWorldView::setCameraControlModeTranslation()
490{
491 setCameraControlMode(Translate);
492}
493
494/**
495 * Returns the current camera control mode.
496 * This needs to be invertable (rotation - translation), if the shift key is pressed.
497 */
498GLWorldView::CameraControlModeType GLWorldView::getCameraControlMode(bool inverted)
499{
500 if (inverted){
501 if (cameraControlMode == Rotate)
502 return Translate;
503 if (cameraControlMode == Translate)
504 return Rotate;
505 return Rotate;
506 }else
507 return cameraControlMode;
508}
509
510/**
511 * Set the camera so it can oversee the whole domain.
512 */
513void GLWorldView::fitCameraToDomain()
514{
515 // Move the camera focus point to the center of the domain box.
516 Vector v = World::getInstance().getDomain().translateIn(Vector(0.5, 0.5, 0.5));
517 camera()->setCenter(QVector3D(v[0], v[1], v[2]));
518
519 // Guess some eye distance.
520 double dist = v.Norm() * 3;
521 camera()->setEye(QVector3D(v[0], v[1], v[2] + dist));
522 camera()->setUpVector(QVector3D(0, 1, 0));
523}
524
525void GLWorldView::setCameraStereoModeDisable()
526{
527 setStereoType(QGLView::Hardware);
528 camera()->setEyeSeparation(0.0);
529 updateGL();
530}
531
532void GLWorldView::setCameraStereoModeHardware()
533{
534 setStereoType(QGLView::Hardware);
535 camera()->setEyeSeparation(defaultEyeSeparation);
536 updateGL();
537}
538
539void GLWorldView::setCameraStereoModeLeftRight()
540{
541 setStereoType(QGLView::LeftRight);
542 camera()->setEyeSeparation(defaultEyeSeparation);
543 updateGL();
544}
545
546void GLWorldView::setCameraStereoModeRightLeft()
547{
548 setStereoType(QGLView::RightLeft);
549 camera()->setEyeSeparation(defaultEyeSeparation);
550 updateGL();
551}
552
553void GLWorldView::setCameraStereoModeTopBottom()
554{
555 setStereoType(QGLView::TopBottom);
556 camera()->setEyeSeparation(defaultEyeSeparation);
557 updateGL();
558}
559
560void GLWorldView::setCameraStereoModeBottomTop()
561{
562 setStereoType(QGLView::BottomTop);
563 camera()->setEyeSeparation(defaultEyeSeparation);
564 updateGL();
565}
566
567void GLWorldView::setCameraStereoModeAnaglyph()
568{
569 setStereoType(QGLView::RedCyanAnaglyph);
570 camera()->setEyeSeparation(defaultEyeSeparation);
571 updateGL();
572}
573
574void GLWorldView::mousePressEvent(QMouseEvent *event)
575{
576 QGLView::mousePressEvent(event);
577
578 // Reset the saved mouse position.
579 lastMousePos = event->posF();
580}
581
582/**
583 * Handle a mouse move event.
584 * This is used to control the camera (rotation and translation) when the left button is being pressed.
585 */
586void GLWorldView::mouseMoveEvent(QMouseEvent *event)
587{
588 if (event->buttons() & Qt::LeftButton){
589 // Find the mouse distance since the last event.
590 QPointF d = event->posF() - lastMousePos;
591 lastMousePos = event->posF();
592
593 // Rotate or translate? (inverted by shift key)
594 CameraControlModeType mode = getCameraControlMode(event->modifiers() & Qt::ShiftModifier);
595
596 if (mode == Rotate){
597 // Rotate the camera.
598 d *= 0.3;
599 camera()->tiltPanRollCenter(- d.y(), - d.x(), 0);
600 }else if (mode == Translate){
601 // Translate the camera.
602 d *= 0.02;
603 camera()->translateCenter(- d.x(), d.y(), 0);
604 camera()->translateEye(- d.x(), d.y(), 0);
605 }
606 }else{
607 // Without this Qt would not test for hover events (i.e. mouse over an atom).
608 QGLView::mouseMoveEvent(event);
609 }
610}
611
612/**
613 * When the mouse wheel is used, zoom in or out.
614 */
615void GLWorldView::wheelEvent(QWheelEvent *event)
616{
617 // Find the distance between the eye and focus point.
618 QVector3D d = camera()->eye() - camera()->center();
619
620 // Scale the distance.
621 if (event->delta() < 0)
622 d *= 1.2;
623 else if (event->delta() > 0)
624 d /= 1.2;
625
626 // Set new eye position.
627 camera()->setEye(camera()->center() + d);
628}
629
630/**
631 * Draw a transparent cube representing the domain.
632 */
633void GLWorldView::drawDomainBox(QGLPainter *painter) const
634{
635 // Apply the domain matrix.
636 RealSpaceMatrix m = World::getInstance().getDomain().getM();
637 painter->modelViewMatrix().push();
638 painter->modelViewMatrix() *= QMatrix4x4(m.at(0,0), m.at(0,1), m.at(0,2), 0.0,
639 m.at(1,0), m.at(1,1), m.at(1,2), 0.0,
640 m.at(2,0), m.at(2,1), m.at(2,2), 0.0,
641 0.0, 0.0, 0.0, 1.0);
642
643 // Draw the transparent cube.
644 painter->setStandardEffect(QGL::LitMaterial);
645 glCullFace(GL_BACK);
646 glEnable(GL_CULL_FACE);
647 glEnable(GL_BLEND);
648 glDepthMask(0);
649 //glDisable(GL_DEPTH_TEST);
650 meshDomainBox->draw(painter);
651 //glEnable(GL_DEPTH_TEST);
652 glDepthMask(1);
653 glDisable(GL_BLEND);
654 glDisable(GL_CULL_FACE);
655
656 // Draw the outlines.
657 painter->setFaceMaterial(QGL::AllFaces, domainBoxMaterial);
658 //glEnable(GL_LINE_SMOOTH);
659 QVector3DArray array;
660 array.append(0, 0, 0); array.append(1, 0, 0);
661 array.append(1, 0, 0); array.append(1, 1, 0);
662 array.append(1, 1, 0); array.append(0, 1, 0);
663 array.append(0, 1, 0); array.append(0, 0, 0);
664
665 array.append(0, 0, 1); array.append(1, 0, 1);
666 array.append(1, 0, 1); array.append(1, 1, 1);
667 array.append(1, 1, 1); array.append(0, 1, 1);
668 array.append(0, 1, 1); array.append(0, 0, 1);
669
670 array.append(0, 0, 0); array.append(0, 0, 1);
671 array.append(1, 0, 0); array.append(1, 0, 1);
672 array.append(0, 1, 0); array.append(0, 1, 1);
673 array.append(1, 1, 0); array.append(1, 1, 1);
674 painter->clearAttributes();
675 painter->setVertexAttribute(QGL::Position, array);
676 painter->draw(QGL::Lines, 24);
677
678 painter->modelViewMatrix().pop();
679}
680
681void GLWorldView::drawDreiBein(QGLPainter *painter)
682{
683 painter->modelViewMatrix().push();
684 painter->modelViewMatrix().translate(camera()->center());
685 painter->setStandardEffect(QGL::LitMaterial);
686 painter->setFaceMaterial(QGL::FrontFaces, NULL);
687 meshDreiBein->draw(painter);
688 painter->modelViewMatrix().pop();
689}
690
691void GLWorldView::sceneHoverSignalled(const atom *_atom)
692{
693 emit hoverChanged(_atom);
694}
695
696
697//#include <GL/glu.h>
698//#include <QtGui/qslider.h>
699//#include <QtGui/qevent.h>
700//
701//#include "ui_dialoglight.h"
702//
703//#include "CodePatterns/MemDebug.hpp"
704//
705//#include <iostream>
706//#include <boost/shared_ptr.hpp>
707//
708//#include "LinearAlgebra/Line.hpp"
709//#include "Atom/atom.hpp"
710//#include "Bond/bond.hpp"
711//#include "Element/element.hpp"
712//#include "molecule.hpp"
713//#include "Element/periodentafel.hpp"
714//#include "World.hpp"
715//
716//#if defined(Q_CC_MSVC)
717//#pragma warning(disable:4305) // init: truncation from const double to float
718//#endif
719//
720//
721//GLMoleculeView::GLMoleculeView(QWidget *parent) :
722// QGLWidget(parent), Observer("GLMoleculeView"), X(Vector(1,0,0)), Y(Vector(0,1,0)), Z(Vector(0,0,1))
723//{
724// xRot = yRot = zRot = 0.0; // default object rotation
725// scale = 5.; // default object scale
726// object = 0;
727// LightPosition[0] = 0.0f;
728// LightPosition[1] = 2.0f;
729// LightPosition[2] = 2.0f;
730// LightPosition[3] = 0.0f;
731// LightDiffuse[0] = 0.5f;
732// LightDiffuse[1] = 0.5f;
733// LightDiffuse[2] = 0.5f;
734// LightDiffuse[3] = 0.0f;
735// LightAmbient[0] = 0.0f;
736// LightAmbient[1] = 0.0f;
737// LightAmbient[2] = 0.0f;
738// LightAmbient[3] = 0.0f;
739//
740// SelectionColor[0] = 0;
741// SelectionColor[1] = 128;
742// SelectionColor[2] = 128;
743//
744// MultiViewEnabled = true;
745//
746// isSignaller = false;
747//
748// World::getInstance().signOn(this);
749//}
750//
751///** Destructor of GLMoleculeView.
752// * Free's the CallList.
753// */
754//GLMoleculeView::~GLMoleculeView()
755//{
756// makeCurrent();
757// glDeleteLists( object, 1 );
758//
759// World::getInstance().signOff(this);
760//}
761//
762///** Paints the conents of the OpenGL window.
763// * Clears the GL buffers, enables lighting and depth.
764// * Window is either quartered (if GLMoleculeView::MultiViewEnabled) and xy, xz, yz planar views
765// * are added. Uses the CallList, constructed during InitializeGL().
766// */
767//void GLMoleculeView::paintGL()
768//{
769// Vector spot;
770//
771// glClear (GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
772// glShadeModel(GL_SMOOTH); // Enable Smooth Shading
773// glEnable(GL_LIGHTING); // Enable Light One
774// glEnable(GL_DEPTH_TEST); // Enables Depth Testing
775// glDepthFunc(GL_LEQUAL); // The Type Of Depth Testing To Do
776// glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST); // Really Nice Perspective Calculations
777//
778// // 3d viewport
779// if (MultiViewEnabled)
780// glViewport( 0, 0, (GLint)width/2, (GLint)height/2 );
781// else
782// glViewport( 0, 0, (GLint)width, (GLint)height );
783// glMatrixMode( GL_PROJECTION );
784// glLoadIdentity();
785// glFrustum( -1.0, 1.0, -1.0, 1.0, 1.0, 50.0 );
786// glMatrixMode( GL_MODELVIEW );
787// glLoadIdentity();
788//
789// // calculate point of view and direction
790// glTranslated(position[0],position[1],position[2]);
791// glTranslated(0.0, 0.0, -scale);
792// glRotated(xRot, 1.0, 0.0, 0.0);
793// glRotated(yRot, 0.0, 1.0, 0.0);
794// glRotated(zRot, 0.0, 0.0, 1.0);
795//
796// // render scene
797// glCallList(object);
798//
799// // enable light
800// glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
801// glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
802// glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
803// glEnable(GL_LIGHT1); // Enable Light One
804//
805// if (MultiViewEnabled) {
806// // xy view port
807// glViewport( (GLint)width/2, 0, (GLint)width/2, (GLint)height/2 );
808// glMatrixMode( GL_PROJECTION );
809// glLoadIdentity();
810// glScalef(1./scale, 1./scale,1./scale);
811// glOrtho(0, width/2, 0, height/2, 0,0);
812// glMatrixMode( GL_MODELVIEW );
813// glLoadIdentity();
814//
815// // calculate point of view and direction
816// view = position;
817// spot = Vector(0.,0.,scale);
818// top = Vector(0.,1.,0.);
819// gluLookAt(
820// spot[0], spot[1], spot[2],
821// view[0], view[1], view[2],
822// top[0], top[1], top[2]);
823//
824// // enable light
825// glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
826// glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
827// glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
828// glEnable(GL_LIGHT1); // Enable Light One
829//
830// // render scene
831// glCallList(object);
832//
833// // xz viewport
834// glViewport( 0, (GLint)height/2, (GLint)width/2, (GLint)height/2 );
835// glMatrixMode( GL_PROJECTION );
836// glLoadIdentity();
837// glScalef(1./scale, 1./scale,1./scale);
838// glOrtho(0, width/2, 0, height/2, 0,0);
839// glMatrixMode( GL_MODELVIEW );
840// glLoadIdentity();
841//
842// // calculate point of view and direction
843// view = position;
844// spot = Vector(0.,scale,0.);
845// top = Vector(1.,0.,0.);
846// gluLookAt(
847// spot[0], spot[1], spot[2],
848// view[0], view[1], view[2],
849// top[0], top[1], top[2]);
850//
851// // enable light
852// glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
853// glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
854// glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
855// glEnable(GL_LIGHT1); // Enable Light One
856//
857// // render scene
858// glCallList(object);
859//
860// //yz viewport
861// glViewport( (GLint)width/2, (GLint)height/2, (GLint)width/2, (GLint)height/2 );
862// glMatrixMode( GL_PROJECTION );
863// glLoadIdentity();
864// glScalef(1./scale, 1./scale,1./scale);
865// glOrtho(0, width/2, 0, height/2, 0,0);
866// glMatrixMode( GL_MODELVIEW );
867// glLoadIdentity();
868//
869// // calculate point of view and direction
870// view= position;
871// spot = Vector(scale,0.,0.);
872// top = Vector(0.,1.,0.);
873// gluLookAt(
874// spot[0], spot[1], spot[2],
875// view[0], view[1], view[2],
876// top[0], top[1], top[2]);
877//
878// // enable light
879// glLightfv(GL_LIGHT1, GL_AMBIENT, LightAmbient); // Setup The Ambient Light
880// glLightfv(GL_LIGHT1, GL_DIFFUSE, LightDiffuse); // Setup The Diffuse Light
881// glLightfv(GL_LIGHT1, GL_POSITION,LightPosition); // Position The Light
882// glEnable(GL_LIGHT1); // Enable Light One
883//
884// // render scene
885// glCallList(object);
886// }
887// //CoordinatesBar->setText( QString ("X: %1, Y: %2, Z: %3").arg(position[0]).arg(position[1]).arg(position[2]) );
888//}
889//
890////void polarView{GLdouble distance, GLdouble twist,
891//// GLdouble elevation, GLdouble azimuth)
892////{
893//// glTranslated(0.0, 0.0, -distance);
894//// glRotated(-twist, 0.0, 0.0, 1.0);
895//// glRotated(-elevation, 1.0, 0.0, 0.0);
896//// glRotated(azimuth, 0.0, 0.0, 1.0);
897////}
898//
899///** Make a sphere.
900// * \param x position
901// * \param radius radius
902// * \param color[3] color rgb values
903// */
904//void GLMoleculeView::makeSphere(const Vector &x, double radius, const unsigned char color[3])
905//{
906// 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
907// GLUquadricObj* q = gluNewQuadric ();
908// gluQuadricOrientation(q, GLU_OUTSIDE);
909//
910// std::cout << "Setting sphere at " << x << " with color r"
911// << (int)color[0] << ",g" << (int)color[1] << ",b" << (int)color[2] << "." << endl;
912//
913// glPushMatrix();
914// glTranslatef( x[0], x[1], x[2]);
915//// glRotatef( xRot, 1.0, 0.0, 0.0);
916//// glRotatef( yRot, 0.0, 1.0, 0.0);
917//// glRotatef( zRot, 0.0, 0.0, 1.0);
918// glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial);
919// gluSphere (q, (GLdouble)radius, 10, 10);
920// glPopMatrix();
921//}
922//
923///** Make a cylinder.
924// * \param x origin
925// * \param y direction
926// * \param radius thickness
927// * \param height length
928// * \color[3] color rgb values
929// */
930//void GLMoleculeView::makeCylinder(const Vector &x, const Vector &y, double radius, double height, const unsigned char color[3])
931//{
932// float blueMaterial[] = { 255./(float)color[0], 255./(float)color[1], 255./(float)color[2], 1 };
933// GLUquadricObj* q = gluNewQuadric ();
934// gluQuadricOrientation(q, GLU_OUTSIDE);
935// Vector a,b;
936// Vector OtherAxis;
937// double alpha;
938// a = x - y;
939// // construct rotation axis
940// b = a;
941// b.VectorProduct(Z);
942// Line axis(zeroVec, b);
943// // calculate rotation angle
944// alpha = a.Angle(Z);
945// // construct other axis to check right-hand rule
946// OtherAxis = b;
947// OtherAxis.VectorProduct(Z);
948// // assure right-hand rule for the rotation
949// if (a.ScalarProduct(OtherAxis) < MYEPSILON)
950// alpha = M_PI-alpha;
951// // check
952// Vector a_rotated = axis.rotateVector(a, alpha);
953// std::cout << "Setting cylinder from "// << x << " to " << y
954// << a << " to " << a_rotated << " around " << b << " by " << alpha/M_PI*180. << ", respectively, "
955// << " with color r"
956// << (int)color[0] << ",g" << (int)color[1] << ",b" << (int)color[2] << "." << endl;
957//
958// glPushMatrix();
959// glTranslatef( x[0], x[1], x[2]);
960// glRotatef( alpha/M_PI*180., b[0], b[1], b[2]);
961// glMaterialfv(GL_FRONT_AND_BACK, GL_AMBIENT_AND_DIFFUSE, blueMaterial);
962// gluCylinder (q, (GLdouble)radius, (GLdouble)radius, (GLdouble)height, 10, 10);
963// glPopMatrix();
964//}
965//
966///** Defines the display CallList.
967// * Goes through all molecules and their atoms and adds spheres for atoms and cylinders
968// * for bonds. Heeds GLMoleculeView::SelectedAtom and GLMoleculeView::SelectedMolecule.
969// */
970//void GLMoleculeView::initializeGL()
971//{
972// double x[3] = {-1, 0, -10};
973// unsigned char white[3] = {255,255,255};
974// Vector Position, OtherPosition;
975// QSize window = size();
976// width = window.width();
977// height = window.height();
978// std::cout << "Setting width to " << width << " and height to " << height << std::endl;
979// GLfloat shininess[] = { 0.0 };
980// GLfloat specular[] = { 0, 0, 0, 1 };
981// glClearColor(0.0f, 0.0f, 0.0f, 0.0f); // Let OpenGL clear to black
982// object = glGenLists(1);
983// glNewList( object, GL_COMPILE );
984// glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
985// glMaterialfv(GL_FRONT_AND_BACK, GL_SHININESS, shininess);
986//
987// const std::vector<molecule*> &molecules = World::getInstance().getAllMolecules();
988//
989// if (molecules.size() > 0) {
990// for (std::vector<molecule*>::const_iterator Runner = molecules.begin();
991// Runner != molecules.end();
992// Runner++) {
993// for (molecule::const_iterator atomiter = (*Runner)->begin();
994// atomiter != (*Runner)->end();
995// ++atomiter) {
996// // create atom
997// const element *ptr = (*atomiter)->getType();
998// boost::shared_ptr<Vector> MolCenter((*Runner)->DetermineCenterOfGravity());
999// Position = (*atomiter)->getPosition() - *MolCenter;
1000// const unsigned char* color = NULL;
1001// if ((World::getInstance().isSelected(*atomiter)) || (World::getInstance().isSelected((*Runner))))
1002// color = SelectionColor;
1003// else
1004// color = ptr->getColor();
1005// makeSphere(Position, ptr->getVanDerWaalsRadius()*0.25, color);
1006//
1007// // create bonds
1008// const BondList &bonds = (*atomiter)->getListOfBonds();
1009// for (BondList::const_iterator bonditer = bonds.begin();
1010// bonditer != bonds.end();
1011// ++bonditer) {
1012// if ((*bonditer)->leftatom->getId() == (*atomiter)->getId()) {
1013// Position = (*bonditer)->leftatom->getPosition() - *MolCenter;
1014// OtherPosition = (*bonditer)->rightatom->getPosition() - *MolCenter;
1015// const double distance = sqrt(Position.DistanceSquared(OtherPosition))/2.;
1016// const unsigned char *color1 = (*bonditer)->leftatom->getType()->getColor();
1017// const unsigned char *color2 = (*bonditer)->rightatom->getType()->getColor();
1018// makeCylinder(Position, OtherPosition, 0.1, distance, color1);
1019// makeCylinder(OtherPosition, Position, 0.1, distance, color2);
1020// }
1021// }
1022// }
1023// }
1024// } else {
1025// makeSphere( x,1, white);
1026// }
1027// glEndList();
1028//}
1029//
1030//
1031///* ================================== SLOTS ============================== */
1032//
1033///** Initializes some public variables.
1034// * \param *ptr pointer to QLabel statusbar
1035// */
1036//void GLMoleculeView::init(QLabel *ptr)
1037//{
1038// StatusBar = ptr;
1039//}
1040//
1041///** Initializes the viewport statusbar.
1042// * \param *ptr pointer to QLabel for showing view pointcoordinates.
1043// */
1044//void GLMoleculeView::initCoordinates(QLabel *ptr)
1045//{
1046// CoordinatesBar = ptr;
1047//}
1048//
1049///** Slot to be called when to initialize GLMoleculeView::MolData.
1050// */
1051//void GLMoleculeView::createView( )
1052//{
1053// initializeGL();
1054// updateGL();
1055//}
1056//
1057///** Slot of window is resized.
1058// * Copies new width and height to GLMoleculeView::width and GLMoleculeView::height and calls updateGL().
1059// * \param w new width of window
1060// * \param h new height of window
1061// */
1062//void GLMoleculeView::resizeGL( int w, int h )
1063//{
1064// width = w;
1065// height = h;
1066// updateGL();
1067//}
1068//
1069///** Sets x rotation angle.
1070// * sets GLMoleculeView::xRot and calls updateGL().
1071// * \param degrees new rotation angle in degrees
1072// */
1073//void GLMoleculeView::setXRotation( int degrees )
1074//{
1075// xRot = (GLfloat)(degrees % 360);
1076// updateGL();
1077//}
1078//
1079//
1080///** Sets y rotation angle.
1081// * sets GLMoleculeView::yRot and calls updateGL().
1082// * \param degrees new rotation angle in degrees
1083// */
1084//void GLMoleculeView::setYRotation( int degrees )
1085//{
1086// yRot = (GLfloat)(degrees % 360);
1087// updateGL();
1088//}
1089//
1090//
1091///** Sets z rotation angle.
1092// * sets GLMoleculeView::zRot and calls updateGL().
1093// * \param degrees new rotation angle in degrees
1094// */
1095//void GLMoleculeView::setZRotation( int degrees )
1096//{
1097// zRot = (GLfloat)(degrees % 360);
1098// updateGL();
1099//}
1100//
1101///** Sets the scale of the scene.
1102// * sets GLMoleculeView::scale and calls updateGL().
1103// * \param distance distance divided by 100 is the new scale
1104// */
1105//void GLMoleculeView::setScale( int distance )
1106//{
1107// scale = (GLfloat)(distance / 100.);
1108// updateGL();
1109//}
1110//
1111///** Update the ambient light.
1112// * \param light[4] light strength per axis and position (w)
1113// */
1114//void GLMoleculeView::setLightAmbient( int *light )
1115//{
1116// for(int i=0;i<4;i++)
1117// LightAmbient[i] = light[i];
1118// updateGL();
1119//}
1120//
1121///** Update the diffuse light.
1122// * \param light[4] light strength per axis and position (w)
1123// */
1124//void GLMoleculeView::setLightDiffuse( int *light )
1125//{
1126// for(int i=0;i<4;i++)
1127// LightDiffuse[i] = light[i];
1128// updateGL();
1129//}
1130//
1131///** Update the position of light.
1132// * \param light[4] light strength per axis and position (w)
1133// */
1134//void GLMoleculeView::setLightPosition( int *light )
1135//{
1136// for(int i=0;i<4;i++)
1137// LightPosition[i] = light[i];
1138// updateGL();
1139//}
1140//
1141///** Toggles the boolean GLMoleculeView::MultiViewEnabled.
1142// * Flips the boolean and calls updateGL().
1143// */
1144//void GLMoleculeView::toggleMultiViewEnabled ( )
1145//{
1146// MultiViewEnabled = !MultiViewEnabled;
1147// cout << "Setting MultiView to " << MultiViewEnabled << "." << endl;
1148// updateGL();
1149//}
1150//
1151///** Launch a dialog to configure the lights.
1152// */
1153//void GLMoleculeView::createDialogLight()
1154//{
1155//// Ui_DialogLight *Lights = new Ui_DialogLight();
1156//// if (Lights == NULL)
1157//// return;
1158//// // Set up the dynamic dialog here
1159//// QLineEdit *Field = NULL;
1160//// Field = Lights->findChild<QLineEdit *>("LightPositionX");
1161//// if (Field) Field->setText( QString("%1").arg(LightPosition[0]) );
1162//// Field = Lights->findChild<QLineEdit *>("LightPositionY");
1163//// if (Field) Field->setText( QString("%1").arg(LightPosition[1]) );
1164//// Field = Lights->findChild<QLineEdit *>("LightPositionZ");
1165//// if (Field) Field->setText( QString("%1").arg(LightPosition[2]) );
1166//// Field = Lights->findChild<QLineEdit *>("LightPositionW");
1167//// if (Field) Field->setText( QString("%1").arg(LightPosition[3]) );
1168////
1169//// Field = Lights->findChild<QLineEdit *>("LightDiffuseX");
1170//// if (Field) Field->setText( QString("%1").arg(LightDiffuse[0]) );
1171//// Field = Lights->findChild<QLineEdit *>("LightDiffuseY");
1172//// if (Field) Field->setText( QString("%1").arg(LightDiffuse[1]) );
1173//// Field = Lights->findChild<QLineEdit *>("LightDiffuseZ");
1174//// if (Field) Field->setText( QString("%1").arg(LightDiffuse[2]) );
1175//// Field = Lights->findChild<QLineEdit *>("LightDiffuseW");
1176//// if (Field) Field->setText( QString("%1").arg(LightDiffuse[3]) );
1177////
1178//// Field = Lights->findChild<QLineEdit *>("LightAmbientX");
1179//// if (Field) Field->setText( QString("%1").arg(LightAmbient[0]) );
1180//// Field = Lights->findChild<QLineEdit *>("LightAmbientY");
1181//// if (Field) Field->setText( QString("%1").arg(LightAmbient[1]) );
1182//// Field = Lights->findChild<QLineEdit *>("LightAmbientZ");
1183//// if (Field) Field->setText( QString("%1").arg(LightAmbient[2]) );
1184//// Field = Lights->findChild<QLineEdit *>("LightAmbientW");
1185//// if (Field) Field->setText( QString("%1").arg(LightAmbient[3]) );
1186////
1187//// if ( Lights->exec() ) {
1188//// //cout << "User accepted.\n";
1189//// // The user accepted, act accordingly
1190//// Field = Lights->findChild<QLineEdit *>("LightPositionX");
1191//// if (Field) LightPosition[0] = Field->text().toDouble();
1192//// Field = Lights->findChild<QLineEdit *>("LightPositionY");
1193//// if (Field) LightPosition[1] = Field->text().toDouble();
1194//// Field = Lights->findChild<QLineEdit *>("LightPositionZ");
1195//// if (Field) LightPosition[2] = Field->text().toDouble();
1196//// Field = Lights->findChild<QLineEdit *>("LightPositionW");
1197//// if (Field) LightPosition[3] = Field->text().toDouble();
1198////
1199//// Field = Lights->findChild<QLineEdit *>("LightDiffuseX");
1200//// if (Field) LightDiffuse[0] = Field->text().toDouble();
1201//// Field = Lights->findChild<QLineEdit *>("LightDiffuseY");
1202//// if (Field) LightDiffuse[1] = Field->text().toDouble();
1203//// Field = Lights->findChild<QLineEdit *>("LightDiffuseZ");
1204//// if (Field) LightDiffuse[2] = Field->text().toDouble();
1205//// Field = Lights->findChild<QLineEdit *>("LightDiffuseW");
1206//// if (Field) LightDiffuse[3] = Field->text().toDouble();
1207////
1208//// Field = Lights->findChild<QLineEdit *>("LightAmbientX");
1209//// if (Field) LightAmbient[0] = Field->text().toDouble();
1210//// Field = Lights->findChild<QLineEdit *>("LightAmbientY");
1211//// if (Field) LightAmbient[1] = Field->text().toDouble();
1212//// Field = Lights->findChild<QLineEdit *>("LightAmbientZ");
1213//// if (Field) LightAmbient[2] = Field->text().toDouble();
1214//// Field = Lights->findChild<QLineEdit *>("LightAmbientW");
1215//// if (Field) LightAmbient[3] = Field->text().toDouble();
1216//// updateGL();
1217//// } else {
1218//// //cout << "User reclined.\n";
1219//// }
1220//// delete(Lights);
1221//}
1222//
1223///** Slot for event of pressed mouse button.
1224// * Switch discerns between buttons and stores position of event in GLMoleculeView::LeftButtonPos,
1225// * GLMoleculeView::MiddleButtonPos or GLMoleculeView::RightButtonPos.
1226// * \param *event structure containing information of the event
1227// */
1228//void GLMoleculeView::mousePressEvent(QMouseEvent *event)
1229//{
1230// std::cout << "MousePressEvent." << endl;
1231// QPoint *pos = NULL;
1232// switch (event->button()) { // get the right array
1233// case Qt::LeftButton:
1234// pos = &LeftButtonPos;
1235// std::cout << "Left Button" << endl;
1236// break;
1237// case Qt::MidButton:
1238// pos = &MiddleButtonPos;
1239// std::cout << "Middle Button" << endl;
1240// break;
1241// case Qt::RightButton:
1242// pos = &RightButtonPos;
1243// std::cout << "Right Button" << endl;
1244// break;
1245// default:
1246// break;
1247// }
1248// if (pos) { // store the position
1249// pos->setX(event->pos().x());
1250// pos->setY(event->pos().y());
1251// std::cout << "Stored src position is (" << pos->x() << "," << pos->y() << ")." << endl;
1252// } else {
1253// std::cout << "pos is NULL." << endl;
1254// }
1255//}
1256//
1257///** Slot for event of pressed mouse button.
1258// * Switch discerns between buttons:
1259// * -# Left Button: Rotates the view of the GLMoleculeView, relative to GLMoleculeView::LeftButtonPos.
1260// * -# Middle Button: nothing
1261// * -# Right Button: Shifts the selected molecule or atom, relative to GLMoleculeView::RightButtonPos.
1262// * \param *event structure containing information of the event
1263// */
1264//void GLMoleculeView::mouseReleaseEvent(QMouseEvent *event)
1265//{
1266// std::cout << "MouseReleaseEvent." << endl;
1267// QPoint *srcpos = NULL;
1268// QPoint destpos = event->pos();
1269// int Width = (MultiViewEnabled) ? width/2 : width;
1270// int Height = (MultiViewEnabled) ? height/2 : height;
1271// std::cout << "Received dest position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
1272// switch (event->button()) { // get the right array
1273// case Qt::LeftButton: // LeftButton rotates the view
1274// srcpos = &LeftButtonPos;
1275// std::cout << "Left Button" << endl;
1276// if (srcpos) { // subtract the position and act
1277// std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
1278// destpos -= *srcpos;
1279// std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
1280// std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
1281//
1282// int pos = (int)floor((double)srcpos->x()/(double)Width) + ((int)floor((double)srcpos->y()/(double)Height))*2;
1283// if ((MultiViewEnabled) && (pos != 2)) { // means four regions, and we are in a shifting one
1284// // switch between three regions
1285// // decide into which of the four screens the initial click has been made
1286// std::cout << "Position is " << pos << "." << endl;
1287// switch(pos) {
1288// case 0: // lower left = xz
1289// position[0] += -destpos.y()/100.;
1290// position[2] += destpos.x()/100.;
1291// break;
1292// case 1: // lower right = yz
1293// position[1] += -destpos.y()/100.;
1294// position[2] += -destpos.x()/100.;
1295// break;
1296// case 2: // upper left = projected
1297// std::cout << "This is impossible: Shifting in the projected region, we should rotate!." << endl;
1298// break;
1299// case 3: // upper right = xy
1300// position[0] += destpos.x()/100.;
1301// position[1] += -destpos.y()/100.;
1302// break;
1303// default:
1304// std::cout << "click was not in any of the four regions." << endl;
1305// break;
1306// }
1307// updateGL();
1308// } else { // we are in rotation region
1309// QWidget *Parent = parentWidget();
1310// QSlider *sliderX = Parent->findChild<QSlider *>("sliderX");
1311// QSlider *sliderY = Parent->findChild<QSlider *>("sliderY");
1312// std::cout << sliderX << " and " << sliderY << endl;
1313// if (sliderX) {
1314// int xrange = sliderX->maximum() - sliderX->minimum();
1315// double xValue = ((destpos.x() + Width) % Width);
1316// xValue *= (double)xrange/(double)Width;
1317// xValue += sliderX->value();
1318// int xvalue = (int) xValue % xrange;
1319// std::cout << "Setting x to " << xvalue << " within range " << xrange << "." << endl;
1320// setXRotation(xvalue);
1321// sliderX->setValue(xvalue);
1322// } else {
1323// std::cout << "sliderX is NULL." << endl;
1324// }
1325// if (sliderY) {
1326// int yrange = sliderY->maximum() - sliderY->minimum();
1327// double yValue = ((destpos.y() + Height) % Height);
1328// yValue *= (double)yrange/(double)Height;
1329// yValue += sliderY->value();
1330// int yvalue = (int) yValue % yrange;
1331// std::cout << "Setting y to " << yvalue << " within range " << yrange << "." << endl;
1332// setYRotation(yvalue);
1333// sliderY->setValue(yvalue);
1334// } else {
1335// std::cout << "sliderY is NULL." << endl;
1336// }
1337// }
1338// } else {
1339// std::cout << "srcpos is NULL." << endl;
1340// }
1341// break;
1342//
1343// case Qt::MidButton: // MiddleButton has no function so far
1344// srcpos = &MiddleButtonPos;
1345// std::cout << "Middle Button" << endl;
1346// if (srcpos) { // subtract the position and act
1347// QWidget *Parent = parentWidget();
1348// QSlider *sliderZ = Parent->findChild<QSlider *>("sliderZ");
1349// QSlider *sliderScale = Parent->findChild<QSlider *>("sliderScale");
1350// std::cout << sliderZ << " and " << sliderScale << endl;
1351// std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
1352// destpos -= *srcpos;
1353// std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
1354// std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
1355// if (sliderZ) {
1356// int xrange = sliderZ->maximum() - sliderZ->minimum();
1357// double xValue = ((destpos.x() + Width) % Width);
1358// xValue *= (double)xrange/(double)Width;
1359// xValue += sliderZ->value();
1360// int xvalue = (int) xValue % xrange;
1361// std::cout << "Setting x to " << xvalue << " within range " << xrange << "." << endl;
1362// setZRotation(xvalue);
1363// sliderZ->setValue(xvalue);
1364// } else {
1365// std::cout << "sliderZ is NULL." << endl;
1366// }
1367// if (sliderScale) {
1368// int yrange = sliderScale->maximum() - sliderScale->minimum();
1369// double yValue = ((destpos.y() + Height) % Height);
1370// yValue *= (double)yrange/(double)Height;
1371// yValue += sliderScale->value();
1372// int yvalue = (int) yValue % yrange;
1373// std::cout << "Setting y to " << yvalue << " within range " << yrange << "." << endl;
1374// setScale(yvalue);
1375// sliderScale->setValue(yvalue);
1376// } else {
1377// std::cout << "sliderScale is NULL." << endl;
1378// }
1379// } else {
1380// std::cout << "srcpos is NULL." << endl;
1381// }
1382// break;
1383// break;
1384//
1385// case Qt::RightButton: // RightButton moves eitstdher the selected molecule or atom
1386// srcpos = &RightButtonPos;
1387// std::cout << "Right Button" << endl;
1388// if (srcpos) { // subtract the position and act
1389// std::cout << "Stored src position is (" << srcpos->x() << "," << srcpos->y() << ")." << endl;
1390// destpos -= *srcpos;
1391// std::cout << "Resulting diff position is (" << destpos.x() << "," << destpos.y() << ")." << endl;
1392// std::cout << "Width and Height are " << Width << "," << Height << "." << endl;
1393// if (MultiViewEnabled) {
1394// // which vector to change
1395// Vector SelectedPosition;
1396// const std::vector<atom*> &SelectedAtoms = World::getInstance().getSelectedAtoms();
1397// const std::vector<molecule*> &SelectedMolecules = World::getInstance().getSelectedMolecules();
1398// if (SelectedMolecules.size()) {
1399// if (SelectedAtoms.size())
1400// SelectedPosition = (*SelectedAtoms.begin())->getPosition();
1401// else
1402// SelectedPosition = (*(*SelectedMolecules.begin())->begin())->getPosition();
1403// }
1404// // decide into which of the four screens the initial click has been made
1405// int pos = (int)floor((double)srcpos->x()/(double)Width) + ((int)floor((double)srcpos->y()/(double)Height))*2;
1406// if (!SelectedPosition.IsZero()) {
1407// std::cout << "Position is " << pos << "." << endl;
1408// switch(pos) {
1409// case 0: // lower left = xz
1410// SelectedPosition[0] += -destpos.y()/100.;
1411// SelectedPosition[2] += destpos.x()/100.;
1412// break;
1413// case 1: // lower right = yz
1414// SelectedPosition[1] += -destpos.y()/100.;
1415// SelectedPosition[2] += -destpos.x()/100.;
1416// break;
1417// case 2: // upper left = projected
1418// SelectedPosition[0] += destpos.x()/100.;
1419// SelectedPosition[1] += destpos.y()/100.;
1420// SelectedPosition[2] += destpos.y()/100.;
1421// break;
1422// case 3: // upper right = xy
1423// SelectedPosition[0] += destpos.x()/100.;
1424// SelectedPosition[1] += -destpos.y()/100.;
1425// break;
1426// default:
1427// std::cout << "click was not in any of the four regions." << endl;
1428// break;
1429// }
1430// } else {
1431// std::cout << "Nothing selected." << endl;
1432// }
1433// // update Tables
1434// if (SelectedMolecules.size()) {
1435// isSignaller = true;
1436// if (SelectedAtoms.size())
1437// emit notifyAtomChanged( (*SelectedMolecules.begin()), (*SelectedAtoms.begin()), AtomPosition);
1438// else
1439// emit notifyMoleculeChanged( (*SelectedMolecules.begin()), MoleculePosition );
1440// }
1441// // update graphic
1442// initializeGL();
1443// updateGL();
1444// } else {
1445// cout << "MultiView is not enabled." << endl;
1446// }
1447// } else {
1448// cout << "srcpos is NULL." << endl;
1449// }
1450// break;
1451//
1452// default:
1453// break;
1454// }
1455//}
1456//
1457///* ======================================== SLOTS ================================ */
1458//
1459///** Hear announcement of selected molecule.
1460// * \param *mol pointer to selected molecule
1461// */
1462//void GLMoleculeView::hearMoleculeSelected(molecule *mol)
1463//{
1464// if (isSignaller) { // if we emitted the signal, return
1465// isSignaller = false;
1466// return;
1467// }
1468// initializeGL();
1469// updateGL();
1470//};
1471//
1472///** Hear announcement of selected atom.
1473// * \param *mol pointer to molecule containing atom
1474// * \param *Walker pointer to selected atom
1475// */
1476//void GLMoleculeView::hearAtomSelected(molecule *mol, atom *Walker)
1477//{
1478// if (isSignaller) { // if we emitted the signal, return
1479// isSignaller = false;
1480// return;
1481// }
1482// initializeGL();
1483// updateGL();
1484//};
1485//
1486///** Hear announcement of changed molecule.
1487// * \param *mol pointer to changed molecule
1488// * \param type of change
1489// */
1490//void GLMoleculeView::hearMoleculeChanged(molecule *mol, enum ChangesinMolecule type)
1491//{
1492// if (isSignaller) { // if we emitted the signal, return
1493// isSignaller = false;
1494// return;
1495// }
1496// initializeGL();
1497// updateGL();
1498//};
1499//
1500///** Hear announcement of changed atom.
1501// * \param *mol pointer to molecule containing atom
1502// * \param *Walker pointer to changed atom
1503// * \param type type of change
1504// */
1505//void GLMoleculeView::hearAtomChanged(molecule *mol, atom *Walker, enum ChangesinAtom type)
1506//{
1507// if (isSignaller) { // if we emitted the signal, return
1508// isSignaller = false;
1509// return;
1510// }
1511// initializeGL();
1512// updateGL();
1513//};
1514//
1515///** Hear announcement of changed element.
1516// * \param *Runner pointer to changed element
1517// * \param type of change
1518// */
1519//void GLMoleculeView::hearElementChanged(element *Runner, enum ChangesinElement type)
1520//{
1521// if (isSignaller) { // if we emitted the signal, return
1522// isSignaller = false;
1523// return;
1524// }
1525// switch(type) {
1526// default:
1527// case ElementName:
1528// case ElementSymbol:
1529// case ElementMass:
1530// case ElementValence:
1531// case ElementZ:
1532// break;
1533// case ElementCovalent:
1534// case ElementVanderWaals:
1535// initializeGL();
1536// updateGL();
1537// break;
1538// }
1539//};
1540//
1541///** Hear announcement of added molecule.
1542// * \param *mol pointer to added molecule
1543// */
1544//void GLMoleculeView::hearMoleculeAdded(molecule *mol)
1545//{
1546// if (isSignaller) { // if we emitted the signal, return
1547// isSignaller = false;
1548// return;
1549// }
1550// initializeGL();
1551// updateGL();
1552//};
1553//
1554///** Hear announcement of added atom.
1555// * \param *mol pointer to molecule containing atom
1556// * \param *Walker pointer to added atom
1557// */
1558//void GLMoleculeView::hearAtomAdded(molecule *mol, atom *Walker)
1559//{
1560// if (isSignaller) { // if we emitted the signal, return
1561// isSignaller = false;
1562// return;
1563// }
1564// initializeGL();
1565// updateGL();
1566//};
1567//
1568///** Hear announcement of removed molecule.
1569// * \param *mol pointer to removed molecule
1570// */
1571//void GLMoleculeView::hearMoleculeRemoved(molecule *mol)
1572//{
1573// if (isSignaller) { // if we emitted the signal, return
1574// isSignaller = false;
1575// return;
1576// }
1577// initializeGL();
1578// updateGL();
1579//};
1580//
1581///** Hear announcement of removed atom.
1582// * \param *mol pointer to molecule containing atom
1583// * \param *Walker pointer to removed atom
1584// */
1585//void GLMoleculeView::hearAtomRemoved(molecule *mol, atom *Walker)
1586//{
1587// if (isSignaller) { // if we emitted the signal, return
1588// isSignaller = false;
1589// return;
1590// }
1591// initializeGL();
1592// updateGL();
1593//};
1594//
1595//void GLMoleculeView::update(Observable *publisher)
1596//{
1597// initializeGL();
1598// updateGL();
1599//}
1600//
1601///**
1602// * This method is called when a special named change
1603// * of the Observable occured
1604// */
1605//void GLMoleculeView::recieveNotification(Observable *publisher, Notification_ptr notification)
1606//{
1607// initializeGL();
1608// updateGL();
1609//}
1610//
1611///**
1612// * This method is called when the observed object is destroyed.
1613// */
1614//void GLMoleculeView::subjectKilled(Observable *publisher)
1615//{
1616//
1617//}
1618//
1619//
1620//// new stuff
1621//
1622///** Returns the ref to the Material for element No \a from the map.
1623// *
1624// * \note We create a new one if the element is missing.
1625// *
1626// * @param no element no
1627// * @return ref to QGLMaterial
1628// */
1629//QGLMaterial* GLMoleculeView::getMaterial(size_t no)
1630//{
1631// if (ElementNoMaterialMap.find(no) != ElementNoMaterialMap.end()){
1632// // get present one
1633//
1634// } else {
1635// ASSERT( (no >= 0) && (no < MAX_ELEMENTS),
1636// "GLMoleculeView::getMaterial() - Element no "+toString(no)+" is invalid.");
1637// // create new one
1638// LOG(1, "Creating new material for element "+toString(no)+".");
1639// QGLMaterial *newmaterial = new QGLMaterial(this);
1640// periodentafel *periode = World::getInstance().getPeriode();
1641// element *desiredelement = periode->FindElement(no);
1642// ASSERT(desiredelement != NULL,
1643// "GLMoleculeView::getMaterial() - desired element "+toString(no)+" not present in periodentafel.");
1644// const unsigned char* color = desiredelement->getColor();
1645// newmaterial->setAmbientColor( QColor(color[0], color[1], color[2]) );
1646// newmaterial->setSpecularColor( QColor(60, 60, 60) );
1647// newmaterial->setShininess( QColor(128) );
1648// ElementNoMaterialMap.insert( no, newmaterial);
1649// }
1650//}
1651//
1652//QGLSceneNode* GLMoleculeView::getAtom(size_t no)
1653//{
1654// // first some sensibility checks
1655// ASSERT(World::getInstance().getAtom(AtomById(no)) != NULL,
1656// "GLMoleculeView::getAtom() - desired atom "
1657// +toString(no)+" not present in the World.");
1658// ASSERT(AtomsinSceneMap.find(no) != AtomsinSceneMap.end(),
1659// "GLMoleculeView::getAtom() - desired atom "
1660// +toString(no)+" not present in the AtomsinSceneMap.");
1661//
1662// return AtomsinSceneMap[no];
1663//}
1664//
1665//QGLSceneNode* GLMoleculeView::getBond(size_t leftno, size_t rightno)
1666//{
1667// // first some sensibility checks
1668// ASSERT(World::getInstance().getAtom(AtomById(leftno)) != NULL,
1669// "GLMoleculeView::getAtom() - desired atom "
1670// +toString(leftno)+" of bond not present in the World.");
1671// ASSERT(World::getInstance().getAtom(AtomById(rightno)) != NULL,
1672// "GLMoleculeView::getAtom() - desired atom "
1673// +toString(rightno)+" of bond not present in the World.");
1674// ASSERT(AtomsinSceneMap.find(leftno) != AtomsinSceneMap.end(),
1675// "GLMoleculeView::getAtom() - desired atom "
1676// +toString(leftno)+" of bond not present in the AtomsinSceneMap.");
1677// ASSERT(AtomsinSceneMap.find(rightno) != AtomsinSceneMap.end(),
1678// "GLMoleculeView::getAtom() - desired atom "
1679// +toString(rightno)+" of bond not present in the AtomsinSceneMap.");
1680// ASSERT(leftno == rightno,
1681// "GLMoleculeView::getAtom() - bond must not be between the same atom: "
1682// +toString(leftno)+" == "+toString(rightno)+".");
1683//
1684// // then return with smaller index first
1685// if (leftno > rightno)
1686// return AtomsinSceneMap[ make_pair(rightno, leftno) ];
1687// else
1688// return AtomsinSceneMap[ make_pair(leftno, rightno) ];
1689//}
1690//
Note: See TracBrowser for help on using the repository browser.