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

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

FIX: GLWorldScene and GLWorldView have atomRemoved with id not atom ptr.

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