source: src/UIElements/Views/Qt4/Qt3D/GLWorldScene.cpp@ 1eba7c

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 Candidate_v1.7.0 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 1eba7c was 1eba7c, checked in by Frederik Heber <heber@…>, 10 years ago

Protecting access to atom and bond functions in GLWorldScene with mutexes.

  • mutex are now for general access to internal maps, not just NodesInSceneMap.
  • Property mode set to 100644
File size: 32.6 KB
RevLine 
[907636]1/*
2 * Project: MoleCuilder
3 * Description: creates and alters molecular systems
[0aa122]4 * Copyright (C) 2010-2012 University of Bonn. All rights reserved.
[5aaa43]5 * Copyright (C) 2013 Frederik Heber. All rights reserved.
[94d5ac6]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/>.
[907636]22 */
23
24/*
25 * GLWorldScene.cpp
26 *
27 * This is based on the Qt3D example "teaservice", specifically parts of teaservice.cpp.
28 *
29 * Created on: Aug 17, 2011
30 * Author: heber
31 */
32
33// include config.h
34#ifdef HAVE_CONFIG_H
35#include <config.h>
36#endif
37
38#include "GLWorldScene.hpp"
[d1196d]39#include <Qt3D/qglview.h>
[bca99d]40#include <Qt3D/qglbuilder.h>
41#include <Qt3D/qglscenenode.h>
42#include <Qt3D/qglsphere.h>
43#include <Qt3D/qglcylinder.h>
[907636]44
[015f8c]45#include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject.hpp"
46#include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_atom.hpp"
47#include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_bond.hpp"
48#include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_molecule.hpp"
49#include "UIElements/Views/Qt4/Qt3D/GLMoleculeObject_shape.hpp"
50
[2f7988]51#include "UIElements/Qt4/InstanceBoard/QtObservedInstanceBoard.hpp"
[907636]52
53#include "CodePatterns/MemDebug.hpp"
54
[7188b1]55#include "CodePatterns/Log.hpp"
56
[f1b5ca]57#include <boost/assign.hpp>
58
[0e9ffe]59#include "Actions/SelectionAction/Atoms/AtomByIdAction.hpp"
[89643d]60#include "Actions/SelectionAction/Atoms/NotAtomByIdAction.hpp"
[6966b7]61#include "Actions/SelectionAction/Molecules/MoleculeByIdAction.hpp"
62#include "Actions/SelectionAction/Molecules/NotMoleculeByIdAction.hpp"
[6f0841]63#include "Atom/atom.hpp"
[7188b1]64#include "Bond/bond.hpp"
[89643d]65#include "Descriptors/AtomIdDescriptor.hpp"
[8c001a]66#include "Descriptors/MoleculeIdDescriptor.hpp"
[37b2575]67#include "Helpers/helpers.hpp"
[85c36d]68#include "Shapes/ShapeRegistry.hpp"
[907636]69#include "molecule.hpp"
70#include "World.hpp"
71
[2ad1ec]72#include <iostream>
73
[ce7fdc]74using namespace MoleCuilder;
[907636]75
[efeeb7]76// static functions
77
78static void eraseBondNodeParents(
79 std::vector<GLWorldScene::BondNodeParentMap_t> &_BondNodeParentMaps,
80 const ObservedValue_Index_t &_bondid)
81{
82 const size_t left_erased = _BondNodeParentMaps[0].left.erase(_bondid);
83 const size_t right_erased = _BondNodeParentMaps[1].left.erase(_bondid);
84 ASSERT( (left_erased == 1) && (right_erased == 1),
85 "eraseBondNodeParents() - could not erase both parents of "+toString(_bondid)+"?");
86}
87
88/** Checks whether both parents of the bond are set to GLWorldScene and the
89 * bondRemoved() signals was received for this bond.
90 *
91 * \param _BondNodeParent_Maps - map containing parents
92 * \param _ToBeRemovedNodes - set with all bonds that are to be removed
93 * \param _bondid id of bond
94 * \return true - both parents are assigned to GLWorldScene, false - else
95 */
96static bool checkBondRemoval(
97 const std::vector<GLWorldScene::BondNodeParentMap_t> &_BondNodeParentMaps,
98 const GLWorldScene::ToBeRemovedNodes_t &_ToBeRemovedNodes,
99 const ObservedValue_Index_t &_bondid)
100{
101 GLWorldScene::BondNodeParentMap_t::left_const_iterator leftiter =
102 _BondNodeParentMaps[0].left.find(_bondid);
103 GLWorldScene::BondNodeParentMap_t::left_const_iterator rightiter =
104 _BondNodeParentMaps[1].left.find(_bondid);
105 ASSERT( leftiter != _BondNodeParentMaps[0].left.end(),
106 "checkBondRemoval() - left parent to index "+toString(_bondid)+" missing?");
107 ASSERT( rightiter != _BondNodeParentMaps[1].left.end(),
108 "checkBondRemoval() - right parent to index "+toString(_bondid)+" missing?");
109 return ((leftiter->second == (ObservedValue_Index_t)NULL)
110 && (rightiter->second == (ObservedValue_Index_t)NULL)
111 && (_ToBeRemovedNodes.count(_bondid)));
112}
113
114void removeBondFromScene(
115 GLWorldScene::BondNodeMap &_BondsinSceneMap,
116 const ObservedValue_Index_t &_bondid)
117{
118 std::pair<GLWorldScene::BondNodeMap::iterator, GLWorldScene::BondNodeMap::iterator> iters =
119 _BondsinSceneMap.equal_range(_bondid);
120 ASSERT( iters.first != iters.second,
121 "removeBondFromScene() - could not find bond to id "+toString(_bondid));
122 for (GLWorldScene::BondNodeMap::iterator iter = iters.first; iter != iters.second; ++iter) {
123 GLMoleculeObject_bond *bondObject = iter->second;
124 delete bondObject; // is done by signal from bond itself
125 //LOG(4, "INFO: Still present bonds " << BondsinSceneMap << ".");
126 }
127 _BondsinSceneMap.erase(_bondid);
128}
129
130static bool checkAtomRemoval(
131 const GLWorldScene::AtomNodeParentMap_t &_AtomNodeParentMap,
132 const GLWorldScene::ToBeRemovedNodes_t &_ToBeRemovedNodes,
133 const ObservedValue_Index_t &_atomid)
134{
135 GLWorldScene::AtomNodeParentMap_t::left_const_iterator iter = _AtomNodeParentMap.left.find(_atomid);
136 ASSERT( iter != _AtomNodeParentMap.left.end(),
137 "checkAtomRemoval() - missing parent entry for "+toString(_atomid));
138 return ((iter->second == (ObservedValue_Index_t)NULL) && (_ToBeRemovedNodes.count(_atomid)));
139}
140
141// class definitions
142
[15c8a9]143GLWorldScene::GLWorldScene(
[2f7988]144 QtObservedInstanceBoard * _board,
[15c8a9]145 QObject *parent) :
146 QObject(parent),
[a13f2b]147 BondNodeParentMaps(std::vector<BondNodeParentMap_t>(2)),
[15c8a9]148 selectionMode(SelectAtom),
149 board(_board)
[907636]150{
[f1b5ca]151 qRegisterMetaType<atomId_t>("atomId_t");
152 qRegisterMetaType<GLMoleculeObject_bond::SideOfBond>("GLMoleculeObject_bond::SideOfBond");
153
[72a4c1]154 int sphereDetails[] = {5, 3, 2, 0};
155 int cylinderDetails[] = {16, 8, 6, 3};
156 for (int i=0;i<GLMoleculeObject::DETAILTYPES_MAX;i++){
157 QGLBuilder emptyBuilder;
[8c001a]158 GLMoleculeObject::meshEmpty[i] = emptyBuilder.finalizedSceneNode();
[72a4c1]159 QGLBuilder sphereBuilder;
160 sphereBuilder << QGLSphere(2.0, sphereDetails[i]);
[8c001a]161 GLMoleculeObject::meshSphere[i] = sphereBuilder.finalizedSceneNode();
162 GLMoleculeObject::meshSphere[i]->setOption(QGLSceneNode::CullBoundingBox, true);
[72a4c1]163 QGLBuilder cylinderBuilder;
164 cylinderBuilder << QGLCylinder(.25,.25,1.0,cylinderDetails[i]);
[8c001a]165 GLMoleculeObject::meshCylinder[i] = cylinderBuilder.finalizedSceneNode();
166 GLMoleculeObject::meshCylinder[i]->setOption(QGLSceneNode::CullBoundingBox, true);
[72a4c1]167 }
[1b07b1]168 connect(board, SIGNAL(moleculeInserted(QtObservedMolecule::ptr)),
[bd6768]169 this, SLOT(insertMolecule(QtObservedMolecule::ptr)));
[f91ef6]170 connect(board, SIGNAL(moleculeRemoved(ObservedValue_Index_t)),
[bd6768]171 this, SLOT(removeMolecule(ObservedValue_Index_t)));
172
[59f1bc]173 connect(board, SIGNAL(atomInserted(QtObservedAtom::ptr)),
[bd6768]174 this, SLOT(connectAtom(QtObservedAtom::ptr)), Qt::DirectConnection);
175 connect(this, SIGNAL(atomConnected(QtObservedAtom::ptr)),
176 this, SLOT(insertAtom(QtObservedAtom::ptr)));
[f91ef6]177 connect(board, SIGNAL(atomRemoved(ObservedValue_Index_t)),
[bd6768]178 this, SLOT(removeAtom(ObservedValue_Index_t)));
179
[96f14a]180 connect(board, SIGNAL(bondInserted(QtObservedBond::ptr)),
[bd6768]181 this, SLOT(connectBond(QtObservedBond::ptr)), Qt::DirectConnection);
182 connect(this, SIGNAL(bondConnected(QtObservedBond::ptr)),
183 this, SLOT(insertBond(QtObservedBond::ptr)));
[96f14a]184 connect(board, SIGNAL(bondRemoved(ObservedValue_Index_t)),
[bd6768]185 this, SLOT(removeBond(ObservedValue_Index_t)));
[0a6ff9]186
[f714763]187// connect(this, SIGNAL(updated()), this, SLOT(update()));
[907636]188}
189
190GLWorldScene::~GLWorldScene()
[7188b1]191{
192 // remove all elements
193 GLMoleculeObject::cleanMaterialMap();
194}
[907636]195
[bd6768]196void GLWorldScene::clickAtom(atomId_t no)
[8c001a]197{
[bd6768]198 LOG(3, "INFO: GLWorldScene - atom " << no << " has been clicked.");
[f01769]199 const atom * const Walker = const_cast<const World &>(World::getInstance()).
200 getAtom(AtomById(no));
[369cb1]201 ASSERT( Walker != NULL,
[bd6768]202 "GLWorldScene::clickAtom() - clicked atom has disappeared.");
[8c001a]203 if (selectionMode == SelectAtom){
204 if (!World::getInstance().isSelected(Walker))
205 SelectionAtomById(std::vector<atomId_t>(1,no));
206 else
207 SelectionNotAtomById(std::vector<atomId_t>(1,no));
208 }else if (selectionMode == SelectMolecule){
209 const molecule *mol = Walker->getMolecule();
210 ASSERT(mol, "Atom without molecule has been clicked.");
[d7cad1]211 molids_t ids(1, mol->getId());
[8c001a]212 if (!World::getInstance().isSelected(mol))
[d7cad1]213 SelectionMoleculeById(ids);
[8c001a]214 else
[d7cad1]215 SelectionNotMoleculeById(ids);
[8c001a]216 }
217 emit clicked(no);
218}
219
[bd6768]220/** Prepares adding an atom to the scene
221 *
222 * We need to listen to moleculeChanged() in order to properly re-parent()
223 * this QObject
224 *
225 * @param _atom atom to connect
226 */
227void GLWorldScene::connectAtom(QtObservedAtom::ptr _atom)
228{
229 connect(_atom.get(), SIGNAL(moleculeChanged()), this, SLOT(reparentAtom()));
230
[1eba7c]231 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
232
[136842]233 // store the object, as we need it on reparenting
[1eba7c]234 const ObservedValue_Index_t atomid = _atom->getIndex();
[136842]235#ifndef NDEBUG
[1eba7c]236 std::pair< ObservedAtoms_t::iterator, bool > inserter =
[136842]237#endif
[1eba7c]238 ObservedAtoms.insert( std::make_pair(_atom.get(), _atom) );
239 ASSERT( inserter.second,
240 "GLWorldScene::connectAtom() - observed atom "+toString(_atom)+" already stored?");
[649f59]241#ifndef NDEBUG
[1eba7c]242 std::pair< ObservedValueIndexLookup_t::iterator, bool > indexinserter =
[649f59]243#endif
[1eba7c]244 ObservedValueIndexLookup.insert( std::make_pair(atomid, _atom.get()) );
245 ASSERT( indexinserter.second,
246 "GLWorldScene::connectAtom() - observed atom's index "
247 +toString(atomid)+" already stored?");
248
249 // and create entry in the parent map
250 AtomNodeParentMap.left.insert( std::make_pair(atomid, (ObservedValue_Index_t)NULL) );
[bd6768]251
252 emit atomConnected(_atom);
253}
254
[f1b5ca]255/** Adds an atom to the scene.
[59f1bc]256 *
[f1b5ca]257 * @param _atom atom to add
[9c259e]258 */
[bd6768]259void GLWorldScene::insertAtom(QtObservedAtom::ptr _atom)
[9c259e]260{
[f1b5ca]261 LOG(3, "INFO: GLWorldScene: Received signal atomInserted for atom "
262 << _atom->getAtomIndex());
[1eba7c]263 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
[f1b5ca]264
[f91ef6]265 const ObservedValue_Index_t atomid = _atom->getIndex();
[bd6768]266 QObject *parent = static_cast<QObject *>(this);
267 GLMoleculeObject_atom *atomObject = NULL;
268 {
[a13f2b]269 AtomNodeParentMap_t::left_iterator parentiter = AtomNodeParentMap.left.find(atomid);
270 ASSERT (parentiter != AtomNodeParentMap.left.end(),
[502614]271 "GLWorldScene::insertAtom() - parent to atom id "+toString(atomid)+" unknown?");
272 const ObservedValue_Index_t parentindex = parentiter->second;
273 if (parentindex != (ObservedValue_Index_t)NULL) {
274 const MoleculeNodeMap::iterator moliter = MoleculesinSceneMap.find(parentindex);
275 if (moliter != MoleculesinSceneMap.end())
276 parent = moliter->second;
277 }
[bd6768]278
279 atomObject = new GLMoleculeObject_atom(
280 GLMoleculeObject::meshSphere,
281 parent,
282 _atom);
283 ASSERT( atomObject != NULL,
284 "GLWorldScene::atomInserted - could not create atom object for "
285 +toString(_atom->getAtomIndex()));
286 }
[f1b5ca]287 AtomNodeMap::iterator iter = AtomsinSceneMap.find(atomid);
288 ASSERT(iter == AtomsinSceneMap.end(),
[bd6768]289 "GLWorldScene::insertAtom - same atom with id "
[f1b5ca]290 +toString(_atom->getAtomIndex())+" added again.");
291 AtomsinSceneMap.insert( make_pair(atomid, atomObject) );
292
[bd6768]293 connect (atomObject, SIGNAL(clicked(atomId_t)), this, SLOT(clickAtom(atomId_t)));
[f1b5ca]294 connect (atomObject, SIGNAL(changed()), this, SIGNAL(changed()));
295 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SIGNAL(changed()));
296 connect (atomObject, SIGNAL(hoverChanged(GLMoleculeObject *)), this, SLOT(hoverChangedSignalled(GLMoleculeObject *)));
297
298 emit changed();
299 emit changeOccured();
[59f1bc]300}
301
[649f59]302template <class T>
303void removeStoredObservedValue(
304 GLWorldScene::ObservedValueIndexLookup_t &_ObservedValueIndexLookup,
305 T &_ObservedValues,
[efeeb7]306 const ObservedValue_Index_t &_id)
[649f59]307{
308 // get QObject* from lookup
309 const GLWorldScene::ObservedValueIndexLookup_t::iterator iter =
310 _ObservedValueIndexLookup.find(_id);
311 ASSERT( iter != _ObservedValueIndexLookup.end(),
[efeeb7]312 "removeStoredObservedValue() - could not find index "+toString(_id)
[649f59]313 +" to stored observed value.");
314 QObject * sender = iter->second;
315 const size_t erased = _ObservedValues.erase(sender);
316 ASSERT( erased == 1,
[efeeb7]317 "removeStoredObservedValue() - could not erase stored observed value "
[649f59]318 +toString(_id));
319 _ObservedValueIndexLookup.erase(iter);
320}
321
[efeeb7]322void removeAtomFromScene(
323 GLWorldScene::AtomNodeMap &_AtomsinSceneMap,
324 const ObservedValue_Index_t &_atomid)
325{
326 GLWorldScene::AtomNodeMap::iterator iter = _AtomsinSceneMap.find(_atomid);
327 ASSERT(iter != _AtomsinSceneMap.end(),
328 "removeAtomFromScene() - atom "+toString(_atomid)+" not on display.");
329 GLMoleculeObject_atom *atomObject = iter->second;
330 _AtomsinSceneMap.erase(iter);
331 delete atomObject;
332}
333
334void GLWorldScene::checkAndRemoveAtom(const ObservedValue_Index_t &_atomid)
335{
[1eba7c]336 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
[efeeb7]337
338 if (checkAtomRemoval(AtomNodeParentMap, ToBeRemovedNodes, _atomid)) {
339 LOG(4, "DEBUG: Found parent of to be removed atom as GLWorldScene, removing.");
340 removeAtomFromScene(AtomsinSceneMap, _atomid);
341 AtomNodeParentMap.left.erase(_atomid);
342 ToBeRemovedNodes.erase(_atomid);
343 removeStoredObservedValue(ObservedValueIndexLookup, ObservedAtoms, _atomid);
344 }
345}
346
[f1b5ca]347/** Removes an atom.
[59f1bc]348 *
[f1b5ca]349 * @param _atomid index of the atom that is removed
[59f1bc]350 */
[bd6768]351void GLWorldScene::removeAtom(ObservedValue_Index_t _atomid)
[59f1bc]352{
[f1b5ca]353 LOG(3, "INFO: GLWorldScene: Received signal atomRemoved for atom "+toString(_atomid)+".");
354 // bonds are removed by signal coming from ~bond
[1eba7c]355 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
[f1b5ca]356
[efeeb7]357 ASSERT( ToBeRemovedNodes.count(_atomid) == 0,
358 "GLWorldScene::removeAtom() - removedAtom signal for id "+toString(_atomid)
359 +" came in twice?");
360 ToBeRemovedNodes.insert( _atomid );
361
[f1b5ca]362 // remove atoms
[efeeb7]363 checkAndRemoveAtom( _atomid );
[649f59]364
[f1b5ca]365 emit changed();
366 emit changeOccured();
[59f1bc]367}
368
[bd6768]369/** Prepares adding a bond to the scene
370 *
371 * We need to listen to moleculeChanged() in order to properly re-parent()
372 * this QObject
373 *
374 * @param _bond bond to connect
375 */
376void GLWorldScene::connectBond(QtObservedBond::ptr _bond)
377{
[efeeb7]378 LOG(3, "INFO: GLWorldScene::connectBond() - connecting to bonds " << _bond->getBondIndex());
379
380 connect(_bond.get(), SIGNAL(leftmoleculeChanged()), this, SLOT(reparentBondLeft()), Qt::QueuedConnection);
381 connect(_bond.get(), SIGNAL(rightmoleculeChanged()), this, SLOT(reparentBondRight()), Qt::QueuedConnection);
[bd6768]382
[1eba7c]383 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
384
[136842]385 // store the object, as we need it on reparenting
[1eba7c]386 const ObservedValue_Index_t bondid = _bond->getIndex();
[649f59]387 {
[136842]388#ifndef NDEBUG
[649f59]389 std::pair< ObservedBonds_t::iterator, bool > inserter =
[136842]390#endif
[649f59]391 ObservedBonds.insert( std::make_pair(_bond.get(), _bond) );
392 ASSERT( inserter.second,
393 "GLWorldScene::connectBond() - observed bond "+toString(_bond)+" already stored?");
394#ifndef NDEBUG
395 std::pair< ObservedValueIndexLookup_t::iterator, bool > indexinserter =
396#endif
[1eba7c]397 ObservedValueIndexLookup.insert( std::make_pair(bondid, _bond.get()) );
[649f59]398 ASSERT( indexinserter.second,
399 "GLWorldScene::connectBond() - observed bond's index "
[1eba7c]400 +toString(bondid)+" already stored?");
[649f59]401 }
[bd6768]402 {
[502614]403 if ((_bond->getLeftAtom() != NULL) && (_bond->getLeftAtom()->getMoleculeRef() != NULL))
[a13f2b]404 BondNodeParentMaps[0].left.insert(
405 std::make_pair(bondid, _bond->getLeftAtom()->getMoleculeRef()->getIndex()) );
406 else
407 BondNodeParentMaps[0].left.insert(
408 std::make_pair(bondid, (ObservedValue_Index_t)NULL) );
[502614]409 if ((_bond->getRightAtom() != NULL) && (_bond->getRightAtom()->getMoleculeRef() != NULL))
[a13f2b]410 BondNodeParentMaps[1].left.insert(
411 std::make_pair(bondid, _bond->getRightAtom()->getMoleculeRef()->getIndex()) );
412 else
413 BondNodeParentMaps[1].left.insert(
414 std::make_pair(bondid, (ObservedValue_Index_t)NULL) );
[bd6768]415 }
416
417 emit bondConnected(_bond);
418}
419
[f1b5ca]420/** Adds a bond to the scene.
[96f14a]421 *
[f1b5ca]422 * @param _bond bond to add
[96f14a]423 */
[bd6768]424void GLWorldScene::insertBond(QtObservedBond::ptr _bond)
[96f14a]425{
[1eba7c]426 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
427
428 const std::vector< GLMoleculeObject_bond::SideOfBond > bondsides =
[f1b5ca]429 boost::assign::list_of<GLMoleculeObject_bond::SideOfBond>
430 (GLMoleculeObject_bond::left)
431 (GLMoleculeObject_bond::right);
[bd6768]432 LOG(3, "INFO: GLWorldScene::insertBond() - Adding bonds " << _bond->getBondIndex());
[f1b5ca]433
[96f14a]434 const ObservedValue_Index_t bondid = _bond->getIndex();
[a13f2b]435#ifdef NDEBUG
436 BondNodeMap::iterator iter = BondsinSceneMap.find(bondid);
437 ASSERT( iter == BondsinSceneMap.end(),
438 "GLWorldScene::insertBond() - bond "+toString(bondid)+" is already known.");
439#endif
[bd6768]440 {
[a13f2b]441 for (size_t i=0;i<2;++i) {
442 BondNodeParentMap_t::left_iterator parentiter = BondNodeParentMaps[i].left.find(bondid);
443 ASSERT (parentiter != BondNodeParentMaps[i].left.end(),
444 "GLWorldScene::insertBond() - parent to bond id "+toString(bondid)+" unknown?");
445 QObject *parent = this;
446 if (parentiter->second != (ObservedValue_Index_t)NULL) {
447 const MoleculeNodeMap::iterator moliter = MoleculesinSceneMap.find(parentiter->second);
[502614]448 if (moliter != MoleculesinSceneMap.end())
[a13f2b]449 parent = moliter->second;
[502614]450 }
[bd6768]451
452 GLMoleculeObject_bond *bondObject = new GLMoleculeObject_bond(
453 GLMoleculeObject::meshCylinder,
[a13f2b]454 parent,
[bd6768]455 _bond,
456 bondsides[i]);
457 connect (bondObject, SIGNAL(changed()), this, SIGNAL(changed()));
458 BondsinSceneMap.insert( std::make_pair(bondid, bondObject) );
459 }
[96f14a]460 }
461
[f1b5ca]462 emit changed();
463 emit changeOccured();
[96f14a]464}
465
[efeeb7]466void GLWorldScene::checkAndRemoveBond(const ObservedValue_Index_t &_bondid)
467{
[1eba7c]468 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
469
[efeeb7]470 if (checkBondRemoval(BondNodeParentMaps, ToBeRemovedNodes, _bondid)) {
471 LOG(3, "DEBUG: Found both parents of to be removed bond " << _bondid << " as GLWorldScene, removing.");
472 removeBondFromScene(BondsinSceneMap, _bondid);
473 removeStoredObservedValue(ObservedValueIndexLookup, ObservedBonds, _bondid);
474 eraseBondNodeParents(BondNodeParentMaps, _bondid);
475 ToBeRemovedNodes.erase(_bondid);
476 }
477}
478
[f1b5ca]479/** Removes a bond.
[96f14a]480 *
[f1b5ca]481 * @param _bondid id of bond to remove
[96f14a]482 */
[bd6768]483void GLWorldScene::removeBond(ObservedValue_Index_t _bondid)
[96f14a]484{
[1eba7c]485 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
[efeeb7]486 LOG(3, "INFO: GLWorldScene::removedBond() - got bondRemoved signal from board for id " << _bondid);
[9c259e]487
[efeeb7]488 ASSERT( ToBeRemovedNodes.find(_bondid) == ToBeRemovedNodes.end(),
489 "GLWorldScene::removeBond() - bondRemoved for "+toString(_bondid)+" obtained twice?");
490 ToBeRemovedNodes.insert( _bondid );
491
492 // check whether node has still non-NULL parents, otherwise remove completely
493 checkAndRemoveBond( _bondid );
[8281cc]494
[f1b5ca]495 emit changed();
496 emit changeOccured();
[9c259e]497}
498
[f1b5ca]499void GLWorldScene::hoverChangedSignalled(GLMoleculeObject *ob)
[96f14a]500{
[1eba7c]501 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
[f1b5ca]502 // Find the atom, ob corresponds to.
503 hoverAtomId = -1;
504 GLMoleculeObject_atom *atomObject = dynamic_cast<GLMoleculeObject_atom *>(ob);
505 if (atomObject){
506 for (AtomNodeMap::iterator iter = AtomsinSceneMap.begin();iter != AtomsinSceneMap.end(); ++ iter){
507 if (iter->second == atomObject)
508 hoverAtomId = iter->second->objectId();
[96f14a]509 }
510
[f1b5ca]511 // Propagate signal.
512 emit hoverChanged(hoverAtomId);
[96f14a]513 } else {
[f1b5ca]514 // Find the atom, ob corresponds to.
515 GLMoleculeObject_molecule *moleculeObject = dynamic_cast<GLMoleculeObject_molecule *>(ob);
516 if (moleculeObject){
517 // Propagate signal.
518 emit hoverChanged(moleculeObject->objectId(), 0);
[96f14a]519 }
520 }
521}
522
[bd6768]523void GLWorldScene::clickMolecule(moleculeId_t no)
[8281cc]524{
[f1b5ca]525 LOG(3, "INFO: GLMoleculeObject_molecule - mol " << no << " has been clicked.");
526 const molecule * const mol= const_cast<const World &>(World::getInstance()).
527 getMolecule(MoleculeById(no));
528 ASSERT(mol, "Atom without molecule has been clicked.");
529 molids_t ids(1, mol->getId());
530 if (!World::getInstance().isSelected(mol))
531 SelectionMoleculeById(ids);
532 else
533 SelectionNotMoleculeById(ids);
534 emit clicked(no);
[8281cc]535}
536
[026bef]537/** Inserts a molecule into the scene.
[c67518]538 *
[8c001a]539 * @param _mol molecule to insert
[c67518]540 */
[bd6768]541void GLWorldScene::insertMolecule(QtObservedMolecule::ptr _mol)
[c67518]542{
[f91ef6]543 const ObservedValue_Index_t molid = _mol->getIndex();
544 LOG(3, "INFO: GLWorldScene: Received signal moleculeInserted for molecule "
545 << _mol->getMolIndex());
[7cf0eb]546
[1b07b1]547 MoleculeNodeMap::const_iterator iter = MoleculesinSceneMap.find(molid);
[8c001a]548 ASSERT( iter == MoleculesinSceneMap.end(),
[a13f2b]549 "GLWorldScene::insertMolecule() - molecule's id "+toString(molid)
[f91ef6]550 +" already present.");
[8c001a]551
552 // add new object
[a13f2b]553 LOG(1, "DEBUG: Adding GLMoleculeObject_molecule to id " << molid);
[1b07b1]554 GLMoleculeObject_molecule *molObject =
555 new GLMoleculeObject_molecule(
556 GLMoleculeObject::meshEmpty,
557 this,
558 _mol);
559 ASSERT( molObject != NULL,
[bd6768]560 "GLWorldScene::insertMolecule - could not create molecule object for "
[a13f2b]561 +toString(molid));
[6c4b69]562#ifndef NDEBUG
563 foreach (QObject *obj, molObject->children()) {
564 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
565 ASSERT( meshobj == NULL,
566 "GLWorldScene::insertMolecule() - there are already atoms or bonds attached to a to molecule.");
567 }
568#endif
[a13f2b]569
570 // check all atoms for not yet assigned parents
571 {
[1eba7c]572 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
[a13f2b]573 std::pair<AtomNodeParentMap_t::right_const_iterator, AtomNodeParentMap_t::right_const_iterator> iters =
574 AtomNodeParentMap.right.equal_range(molid);
575 for (AtomNodeParentMap_t::right_const_iterator iter = iters.first;
576 iter != iters.second; ++iter) {
577 AtomNodeMap::const_iterator atomiter = AtomsinSceneMap.find(iter->second);
578 if (atomiter != AtomsinSceneMap.end())
579 resetParent(atomiter->second, molObject);
580 }
581 }
582 // check all bonds for not yet assigned parents
583 {
[1eba7c]584 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
[a13f2b]585 for (size_t i=0;i<2;++i) {
586 std::pair<BondNodeParentMap_t::right_const_iterator, BondNodeParentMap_t::right_const_iterator> iters =
587 BondNodeParentMaps[i].right.equal_range(molid);
588 for (BondNodeParentMap_t::right_const_iterator iter = iters.first;
589 iter != iters.second; ++iter) {
590 BondNodeMap::const_iterator bonditer = BondsinSceneMap.find(iter->second);
591 if (bonditer != BondsinSceneMap.end())
592 resetParent(bonditer->second, molObject);
593 }
594 }
595 }
596
[1b07b1]597#ifndef NDEBUG
598 std::pair<MoleculeNodeMap::iterator, bool> inserter =
599#endif
600 MoleculesinSceneMap.insert( make_pair(molid, molObject) );
601 ASSERT(inserter.second,
[bd6768]602 "GLWorldScene::insertMolecule() - molecule "+toString(_mol->getMolIndex())
[f91ef6]603 +" already present in scene.");
[1b07b1]604
605 connect (molObject, SIGNAL(changed()), this, SIGNAL(changed()));
606 connect (molObject, SIGNAL(changeOccured()), this, SIGNAL(changeOccured()));
607
608 emit changed();
609 emit changeOccured();
[c67518]610}
611
[7cf0eb]612/** Removes a molecule from the scene.
613 *
[f1b5ca]614 * @param _molid index of the molecule to remove
[7cf0eb]615 */
[bd6768]616void GLWorldScene::removeMolecule(ObservedValue_Index_t _molid)
[7cf0eb]617{
[f1b5ca]618 LOG(3, "INFO: GLWorldScene: Received signal moleculeRemoved for molecule "+toString(_molid)+".");
[7c7c4a]619
[f1b5ca]620 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_molid);
[4a187d]621 ASSERT ( iter != MoleculesinSceneMap.end(),
[bd6768]622 "GLWorldScene::removeMolecule() - to be removed molecule "+toString(_molid)
[4a187d]623 +" is already gone.");
[f1b5ca]624 GLMoleculeObject_molecule *molObject = iter->second;
[6c4b69]625 // check for any atoms and bonds still attached to it
626#ifndef NDEBUG
627 foreach (QObject *obj, molObject->children()) {
628 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
629 ASSERT( meshobj == NULL,
630 "GLWorldScene::removeMolecule() - there are still atoms or bonds attached to a to molecule.");
631 }
632#endif
633 // finally, remove molecule
[f1b5ca]634 delete molObject;
[4a187d]635 MoleculesinSceneMap.erase(iter);
[bcf9cd]636
[f1b5ca]637 emit changed();
638 emit changeOccured();
[ce4126]639}
640
[f91ef6]641void GLWorldScene::moleculesVisibilityChanged(ObservedValue_Index_t _id, bool _visible)
[739ee9]642{
643 MoleculeNodeMap::iterator iter = MoleculesinSceneMap.find(_id);
644 ASSERT( iter != MoleculesinSceneMap.end(),
[f91ef6]645 "GLWorldScene::moleculeInserted() - molecule's id "
646 +toString(board->getMoleculeIdToIndex(_id))+" is unknown.");
[739ee9]647
648 GLMoleculeObject_molecule *molObject = iter->second;
649 molObject->setVisible(_visible);
650
651 emit changed();
652 emit changeOccured();
653}
654
[a13f2b]655/** This converts safely index into a GLMoleculeObject_molecule.
656 *
657 * \param _MoleculesinSceneMap all present molecules
658 * \param _molid index to look for
659 * \return MolObject or NULL when not found
660 */
661GLMoleculeObject_molecule *GLWorldScene::getMoleculeObject(
662 const ObservedValue_Index_t _molid) const
663{
664 const MoleculeNodeMap::const_iterator moliter = MoleculesinSceneMap.find(_molid);
665 if (moliter != MoleculesinSceneMap.end())
666 return moliter->second;
667 else
668 return NULL;
669}
670
[bd6768]671/** Changes the parent of an object in the scene.
672 *
673 * \param _id index of the object whose parent to change
674 * \param _ob new parent
675 */
676void GLWorldScene::reparentAtom()
677{
[1eba7c]678 boost::recursive_mutex::scoped_lock lock(Atom_mutex);
[649f59]679 QObject * origin = sender();
[efeeb7]680 if (origin == NULL) {
681 ELOG(1, "Got reparentAtom() with sender being NULL.");
682 return;
683 }
[649f59]684 ObservedAtoms_t::const_iterator iter = ObservedAtoms.find(origin);
685 ASSERT( iter != ObservedAtoms.end(),
686 "GLWorldScene::reparentAtom() - atom's "+toString(origin)+" is no longer stored?");
687 QtObservedAtom::ptr walker = iter->second;
[bd6768]688 const ObservedValue_Index_t walkerid = walker->getIndex();
[6c4b69]689 LOG(4, "DEBUG: GLWorldScene: Received signal moleculeChanged for atom "+toString(walkerid)+".");
[a13f2b]690 AtomNodeParentMap_t::left_iterator parentiter = AtomNodeParentMap.left.find(walkerid);
691 ASSERT( parentiter != AtomNodeParentMap.left.end(),
[bd6768]692 "GLWorldScene::reparentAtom() - could not find object to id "+toString(walkerid));
[502614]693
694 // change parent entry
[a13f2b]695 AtomNodeParentMap.left.erase(parentiter);
[502614]696 if (walker->getMoleculeRef() != NULL)
[a13f2b]697 AtomNodeParentMap.left.insert( std::make_pair(walkerid, walker->getMoleculeRef()->getIndex()) );
[502614]698 else
[a13f2b]699 AtomNodeParentMap.left.insert( std::make_pair(walkerid, (ObservedValue_Index_t)NULL) );
700 parentiter = AtomNodeParentMap.left.find(walkerid);
[502614]701
[a13f2b]702 const AtomNodeMap::iterator atomiter = AtomsinSceneMap.find(walkerid);
703 if (atomiter != AtomsinSceneMap.end())
704 resetParent(atomiter->second, getMoleculeObject(parentiter->second));
705 // else atom does not yet exist
[649f59]706
[efeeb7]707 // check whether node is still shown, otherwise remove completely
708 checkAndRemoveAtom( walkerid );
[bd6768]709}
710
[502614]711/** Changes the parent of an left-side bond in the scene.
[bd6768]712 *
713 */
714void GLWorldScene::reparentBondLeft()
715{
[1eba7c]716 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
[649f59]717 QObject * origin = sender();
[efeeb7]718 if (origin == NULL) {
719 ELOG(1, "Got reparentBondLeft() with sender being NULL.");
720 return;
721 }
[649f59]722 ObservedBonds_t::const_iterator iter = ObservedBonds.find(origin);
723 ASSERT( iter != ObservedBonds.end(),
724 "GLWorldScene::reparentBondLeft() - bond "+toString(origin)+" is no longer stored?");
725 QtObservedBond::ptr bond = iter->second;
[efeeb7]726 LOG(3, "INFO: GLWorldScene::reparentBondLeft() - Reparenting left side of bond "
727 << bond->getBondIndex() << ".");
[502614]728 reparentBond(bond, bond->getLeftAtom(), GLMoleculeObject_bond::left);
[649f59]729
[efeeb7]730 // check whether node is still shown, otherwise remove completely
731 checkAndRemoveBond( bond->getIndex() );
[502614]732}
733
734/** Changes the parent of an right-side bond in the scene.
735 *
736 */
737void GLWorldScene::reparentBondRight()
738{
[1eba7c]739 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
[649f59]740 QObject * origin = sender();
[efeeb7]741 if (origin == NULL) {
742 ELOG(1, "Got reparentBondRight() with sender being NULL.");
743 return;
744 }
[649f59]745 ObservedBonds_t::const_iterator iter = ObservedBonds.find(origin);
746 ASSERT( iter != ObservedBonds.end(),
747 "GLWorldScene::reparentBondRight() - bond "+toString(origin)+" is no longer stored?");
748 QtObservedBond::ptr bond = iter->second;
[efeeb7]749 LOG(3, "INFO: GLWorldScene::reparentBondRight() - Reparenting right side of bond "
750 << bond->getBondIndex() << ".");
[502614]751 reparentBond(bond, bond->getRightAtom(), GLMoleculeObject_bond::right);
[649f59]752
[efeeb7]753 // check whether node is still shown, otherwise remove completely
754 checkAndRemoveBond( bond->getIndex() );
[502614]755}
756
757GLMoleculeObject_bond *GLWorldScene::getBondInScene(
758 const ObservedValue_Index_t _bondid,
759 GLMoleculeObject_bond::SideOfBond _side) const
760{
761 std::pair<GLWorldScene::BondNodeMap::const_iterator, GLWorldScene::BondNodeMap::const_iterator> iters =
762 BondsinSceneMap.equal_range(_bondid);
[efeeb7]763 ASSERT( std::distance(iters.first, iters.second) >= 1,
764 "GLWorldScene::getBondInScene() - not at least one bond of id "
[502614]765 +toString(_bondid)+" present in scene.");
766 for (GLWorldScene::BondNodeMap::const_iterator bonditer = iters.first;
767 bonditer != iters.second; ++bonditer) {
768 if (bonditer->second->BondSide == _side)
769 return bonditer->second;
[bd6768]770 }
[502614]771 return NULL;
[bd6768]772}
773
774/** Changes the parent of an object in the scene.
775 *
[502614]776 * \param _atom atom of bond whose molecule we are associated to
777 * \param _side side of bond
[bd6768]778 */
[502614]779void GLWorldScene::reparentBond(
[649f59]780 const QtObservedBond::ptr _bond,
[507f3c]781 const QtObservedAtom::ptr _atom,
[502614]782 const GLMoleculeObject_bond::SideOfBond _side)
[bd6768]783{
[1eba7c]784 boost::recursive_mutex::scoped_lock lock(Bond_mutex);
[a13f2b]785 const size_t dim = (_side == GLMoleculeObject_bond::left) ? 0 : 1;
[502614]786 const ObservedValue_Index_t bondid = _bond->getIndex();
[a13f2b]787 BondNodeParentMap_t::left_iterator parentiter = BondNodeParentMaps[dim].left.find(bondid);
788 ASSERT( parentiter != BondNodeParentMaps[dim].left.end(),
[502614]789 "GLWorldScene::reparentBond() - could not find object to id "+toString(bondid));
790
791 // change parent entry
[a13f2b]792 BondNodeParentMaps[dim].left.erase(bondid);
[502614]793 if ((_atom != NULL) && (_atom->getMoleculeRef() != NULL))
[a13f2b]794 BondNodeParentMaps[dim].left.insert( std::make_pair( bondid, _atom->getMoleculeRef()->getIndex()));
[502614]795 else
[a13f2b]796 BondNodeParentMaps[dim].left.insert( std::make_pair( bondid, (ObservedValue_Index_t)NULL) );
797 parentiter = BondNodeParentMaps[dim].left.find(bondid);
[efeeb7]798 LOG(3, "INFO: GLWorldScene::reparentBond() - Reparented bond "
799 << _bond->getBondIndex() << " to " << parentiter->second);
[502614]800
801 // reset parent
[a13f2b]802 resetParent(getBondInScene(bondid, _side), getMoleculeObject(parentiter->second));
803}
804
805/** Resets the parent of an GLMoleculeObject.
806 *
807 * \param _obj object to reparent
808 * \param _molid index of parent molecule
809 */
810void GLWorldScene::resetParent(
811 GLMoleculeObject *_obj,
812 GLMoleculeObject_molecule *_molobj)
813{
814 if (_obj != NULL) {
[502614]815 QObject *parent = this;
[a13f2b]816 if (_molobj != NULL)
817 parent = _molobj;
818 // else: molecule does not yet exist: is done when molecule is instantiated
[6c4b69]819 LOG(5, "DEBUG: Resetting parent of " << _obj << " to " << parent);
[a13f2b]820 _obj->setParent(parent);
[6c4b69]821 ASSERT( _obj->parent() == parent,
822 "GLWorldScene::resetParent() - new parent "+toString(parent)+" was not set.");
823 } else
824 ELOG(1, "Object to reparent was NULL.");
[a13f2b]825 // else object does not yet exist
[bd6768]826}
827
[f75491]828/** Adds a shape to the scene.
[4d6662]829 *
[f75491]830 */
[07136a]831void GLWorldScene::addShape(const std::string &_name)
[f75491]832{
[07136a]833 Shape * const shape = ShapeRegistry::getInstance().getByName(_name);
834 if (shape != NULL) {
835 GLMoleculeObject_shape *shapeObject = new GLMoleculeObject_shape(*shape, this);
836 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(_name);
837 ASSERT(iter == ShapesinSceneMap.end(),
838 "GLWorldScene::addShape() - same shape "+_name+" added again.");
839 ShapesinSceneMap.insert( make_pair(_name, shapeObject) );
840 } else
841 ELOG(2, "GLWorldScene::addShape() - shape disappeared before we could draw it.");
842
843 emit changed();
[284551]844}
845
[07136a]846void GLWorldScene::removeShape(const std::string &_name)
[85c36d]847{
[07136a]848 ShapeNodeMap::iterator iter = ShapesinSceneMap.find(_name);
[ba6b5c]849 ASSERT(iter != ShapesinSceneMap.end(),
[07136a]850 "GLWorldScene::removeShape() - shape "+_name+" not in scene.");
[148dde0]851 ShapesinSceneMap.erase(iter);
[85c36d]852 delete(iter->second);
[07136a]853
854 emit changed();
[85c36d]855}
856
857void GLWorldScene::updateSelectedShapes()
[284551]858{
859 foreach (QObject *obj, children()) {
860 GLMoleculeObject_shape *shapeobj = qobject_cast<GLMoleculeObject_shape *>(obj);
[85c36d]861 if (shapeobj){
862 shapeobj->enable(ShapeRegistry::getInstance().isSelected(shapeobj->getShape()));
863 }
[284551]864 }
[07136a]865
866 emit changed();
[f75491]867}
868
[7188b1]869void GLWorldScene::initialize(QGLView *view, QGLPainter *painter) const
870{
871 // Initialize all of the mesh objects that we have as children.
872 foreach (QObject *obj, children()) {
873 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
874 if (meshobj)
875 meshobj->initialize(view, painter);
876 }
877}
878
[72a4c1]879void GLWorldScene::draw(QGLPainter *painter, const QVector4D &cameraPlane) const
[7188b1]880{
881 // Draw all of the mesh objects that we have as children.
882 foreach (QObject *obj, children()) {
883 GLMoleculeObject *meshobj = qobject_cast<GLMoleculeObject *>(obj);
884 if (meshobj)
[72a4c1]885 meshobj->draw(painter, cameraPlane);
[7188b1]886 }
[907636]887}
[06ebf5]888
[6966b7]889void GLWorldScene::setSelectionMode(SelectionModeType mode)
890{
891 selectionMode = mode;
892 // TODO send update to toolbar
893}
894
895void GLWorldScene::setSelectionModeAtom()
896{
897 setSelectionMode(SelectAtom);
898}
899
900void GLWorldScene::setSelectionModeMolecule()
901{
902 setSelectionMode(SelectMolecule);
903}
[20f9b5]904
Note: See TracBrowser for help on using the repository browser.